syntax.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  1. /* editor syntax highlighting.
  2. Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
  3. 2007 Free Software Foundation, Inc.
  4. Authors: 1998 Paul Sheer
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. 02110-1301, USA.
  17. */
  18. #include <config.h>
  19. #include <stdio.h>
  20. #include <stdarg.h>
  21. #include <sys/types.h>
  22. #include <unistd.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25. #include <errno.h>
  26. #include <sys/stat.h>
  27. #include <stdlib.h>
  28. #include "../src/global.h"
  29. #include "edit.h"
  30. #include "edit-widget.h"
  31. #include "../src/color.h" /* use_colors */
  32. #include "../src/main.h" /* mc_home */
  33. #include "../src/wtools.h" /* message() */
  34. #include "../src/strutil.h" /* utf string functions */
  35. /* bytes */
  36. #define SYNTAX_MARKER_DENSITY 512
  37. /*
  38. Mispelled words are flushed from the syntax highlighting rules
  39. when they have been around longer than
  40. TRANSIENT_WORD_TIME_OUT seconds. At a cursor rate of 30
  41. chars per second and say 3 chars + a space per word, we can
  42. accumulate 450 words absolute max with a value of 60. This is
  43. below this limit of 1024 words in a context.
  44. */
  45. #define TRANSIENT_WORD_TIME_OUT 60
  46. #define UNKNOWN_FORMAT "unknown"
  47. #define MAX_WORDS_PER_CONTEXT 1024
  48. #define MAX_CONTEXTS 128
  49. #define RULE_ON_LEFT_BORDER 1
  50. #define RULE_ON_RIGHT_BORDER 2
  51. #define SYNTAX_TOKEN_STAR '\001'
  52. #define SYNTAX_TOKEN_PLUS '\002'
  53. #define SYNTAX_TOKEN_BRACKET '\003'
  54. #define SYNTAX_TOKEN_BRACE '\004'
  55. struct key_word {
  56. char *keyword;
  57. unsigned char first;
  58. char *whole_word_chars_left;
  59. char *whole_word_chars_right;
  60. int line_start;
  61. int color;
  62. };
  63. struct context_rule {
  64. char *left;
  65. unsigned char first_left;
  66. char *right;
  67. unsigned char first_right;
  68. char line_start_left;
  69. char line_start_right;
  70. int between_delimiters;
  71. char *whole_word_chars_left;
  72. char *whole_word_chars_right;
  73. char *keyword_first_chars;
  74. int spelling;
  75. /* first word is word[1] */
  76. struct key_word **keyword;
  77. };
  78. struct _syntax_marker {
  79. long offset;
  80. struct syntax_rule rule;
  81. struct _syntax_marker *next;
  82. };
  83. int option_syntax_highlighting = 1;
  84. int option_auto_syntax = 1;
  85. char *option_syntax_type = NULL;
  86. static gint
  87. mc_defines_destroy (gpointer key, gpointer value, gpointer data)
  88. {
  89. char **values = value;
  90. (void) data;
  91. g_free (key);
  92. while (*values)
  93. g_free (*values++);
  94. g_free (value);
  95. return FALSE;
  96. }
  97. /* Completely destroys the defines tree */
  98. static inline void
  99. destroy_defines (GTree **defines)
  100. {
  101. g_tree_traverse (*defines, mc_defines_destroy, G_POST_ORDER, NULL);
  102. g_tree_destroy (*defines);
  103. *defines = 0;
  104. }
  105. static void
  106. subst_defines (GTree *defines, char **argv, char **argv_end)
  107. {
  108. char **t, **p;
  109. int argc;
  110. while (*argv && argv < argv_end) {
  111. if ((t = g_tree_lookup (defines, *argv))) {
  112. int count = 0;
  113. /* Count argv array members */
  114. argc = 0;
  115. for (p = &argv[1]; *p; p++)
  116. argc++;
  117. /* Count members of definition array */
  118. for (p = t; *p; p++)
  119. count++;
  120. p = &argv[count + argc];
  121. /* Buffer overflow or infinitive loop in define */
  122. if (p >= argv_end)
  123. break;
  124. /* Move rest of argv after definition members */
  125. while (argc >= 0)
  126. *p-- = argv[argc-- + 1];
  127. /* Copy definition members to argv */
  128. for (p = argv; *t; *p++ = *t++);
  129. }
  130. argv++;
  131. }
  132. }
  133. static long
  134. compare_word_to_right (WEdit *edit, long i, const char *text,
  135. const char *whole_left, const char *whole_right,
  136. int line_start)
  137. {
  138. const unsigned char *p, *q;
  139. int c, d, j;
  140. if (!*text)
  141. return -1;
  142. c = edit_get_byte (edit, i - 1);
  143. if (line_start)
  144. if (c != '\n')
  145. return -1;
  146. if (whole_left)
  147. if (strchr (whole_left, c))
  148. return -1;
  149. for (p = (unsigned char *) text, q = p + str_term_width1 ((char *) p); p < q; p++, i++) {
  150. switch (*p) {
  151. case SYNTAX_TOKEN_STAR:
  152. if (++p > q)
  153. return -1;
  154. for (;;) {
  155. c = edit_get_byte (edit, i);
  156. if (!*p)
  157. if (whole_right)
  158. if (!strchr (whole_right, c))
  159. break;
  160. if (c == *p)
  161. break;
  162. if (c == '\n')
  163. return -1;
  164. i++;
  165. }
  166. break;
  167. case SYNTAX_TOKEN_PLUS:
  168. if (++p > q)
  169. return -1;
  170. j = 0;
  171. for (;;) {
  172. c = edit_get_byte (edit, i);
  173. if (c == *p) {
  174. j = i;
  175. if (*p == *text && !p[1]) /* handle eg '+' and @+@ keywords properly */
  176. break;
  177. }
  178. if (j && strchr ((char *) p + 1, c)) /* c exists further down, so it will get matched later */
  179. break;
  180. if (c == '\n' || c == '\t' || c == ' ') {
  181. if (!*p) {
  182. i--;
  183. break;
  184. }
  185. if (!j)
  186. return -1;
  187. i = j;
  188. break;
  189. }
  190. if (whole_right)
  191. if (!strchr (whole_right, c)) {
  192. if (!*p) {
  193. i--;
  194. break;
  195. }
  196. if (!j)
  197. return -1;
  198. i = j;
  199. break;
  200. }
  201. i++;
  202. }
  203. break;
  204. case SYNTAX_TOKEN_BRACKET:
  205. if (++p > q)
  206. return -1;
  207. c = -1;
  208. for (;; i++) {
  209. d = c;
  210. c = edit_get_byte (edit, i);
  211. for (j = 0; p[j] != SYNTAX_TOKEN_BRACKET && p[j]; j++)
  212. if (c == p[j])
  213. goto found_char2;
  214. break;
  215. found_char2:
  216. ; /* dummy command */
  217. }
  218. i--;
  219. while (*p != SYNTAX_TOKEN_BRACKET && p <= q)
  220. p++;
  221. if (p > q)
  222. return -1;
  223. if (p[1] == d)
  224. i--;
  225. break;
  226. case SYNTAX_TOKEN_BRACE:
  227. if (++p > q)
  228. return -1;
  229. c = edit_get_byte (edit, i);
  230. for (; *p != SYNTAX_TOKEN_BRACE && *p; p++)
  231. if (c == *p)
  232. goto found_char3;
  233. return -1;
  234. found_char3:
  235. while (*p != SYNTAX_TOKEN_BRACE && p < q)
  236. p++;
  237. break;
  238. default:
  239. if (*p != edit_get_byte (edit, i))
  240. return -1;
  241. }
  242. }
  243. if (whole_right)
  244. if (strchr (whole_right, edit_get_byte (edit, i)))
  245. return -1;
  246. return i;
  247. }
  248. static inline const char *xx_strchr (const unsigned char *s, int c)
  249. {
  250. while (*s >= '\005' && *s != (unsigned char) c) {
  251. s++;
  252. }
  253. return (const char *) s;
  254. }
  255. static inline struct syntax_rule apply_rules_going_right (WEdit * edit, long i, struct syntax_rule rule)
  256. {
  257. struct context_rule *r;
  258. int contextchanged = 0, c;
  259. int found_right = 0, found_left = 0, keyword_foundleft = 0, keyword_foundright = 0;
  260. int is_end;
  261. long end = 0;
  262. struct syntax_rule _rule = rule;
  263. if (!(c = edit_get_byte (edit, i)))
  264. return rule;
  265. is_end = (rule.end == (unsigned char) i);
  266. /* check to turn off a keyword */
  267. if (_rule.keyword) {
  268. if (edit_get_byte (edit, i - 1) == '\n')
  269. _rule.keyword = 0;
  270. if (is_end) {
  271. _rule.keyword = 0;
  272. keyword_foundleft = 1;
  273. }
  274. }
  275. /* check to turn off a context */
  276. if (_rule.context && !_rule.keyword) {
  277. long e;
  278. r = edit->rules[_rule.context];
  279. if (r->first_right == c && !(rule.border & RULE_ON_RIGHT_BORDER) && (e = compare_word_to_right (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) > 0) {
  280. _rule.end = e;
  281. found_right = 1;
  282. _rule.border = RULE_ON_RIGHT_BORDER;
  283. if (r->between_delimiters)
  284. _rule.context = 0;
  285. } else if (is_end && rule.border & RULE_ON_RIGHT_BORDER) {
  286. /* always turn off a context at 4 */
  287. found_left = 1;
  288. _rule.border = 0;
  289. if (!keyword_foundleft)
  290. _rule.context = 0;
  291. } else if (is_end && rule.border & RULE_ON_LEFT_BORDER) {
  292. /* never turn off a context at 2 */
  293. found_left = 1;
  294. _rule.border = 0;
  295. }
  296. }
  297. /* check to turn on a keyword */
  298. if (!_rule.keyword) {
  299. const char *p;
  300. p = (r = edit->rules[_rule.context])->keyword_first_chars;
  301. if (p)
  302. while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
  303. struct key_word *k;
  304. int count;
  305. long e;
  306. count = p - r->keyword_first_chars;
  307. k = r->keyword[count];
  308. e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
  309. if (e > 0) {
  310. end = e;
  311. _rule.end = e;
  312. _rule.keyword = count;
  313. keyword_foundright = 1;
  314. break;
  315. }
  316. }
  317. }
  318. /* check to turn on a context */
  319. if (!_rule.context) {
  320. if (!found_left && is_end) {
  321. if (rule.border & RULE_ON_RIGHT_BORDER) {
  322. _rule.border = 0;
  323. _rule.context = 0;
  324. contextchanged = 1;
  325. _rule.keyword = 0;
  326. } else if (rule.border & RULE_ON_LEFT_BORDER) {
  327. r = edit->rules[_rule._context];
  328. _rule.border = 0;
  329. if (r->between_delimiters) {
  330. long e;
  331. _rule.context = _rule._context;
  332. contextchanged = 1;
  333. _rule.keyword = 0;
  334. if (r->first_right == c && (e = compare_word_to_right (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) >= end) {
  335. _rule.end = e;
  336. found_right = 1;
  337. _rule.border = RULE_ON_RIGHT_BORDER;
  338. _rule.context = 0;
  339. }
  340. }
  341. }
  342. }
  343. if (!found_right) {
  344. int count;
  345. struct context_rule **rules = edit->rules;
  346. for (count = 1; rules[count]; count++) {
  347. r = rules[count];
  348. if (r->first_left == c) {
  349. long e;
  350. e = compare_word_to_right (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left);
  351. if (e >= end && (!_rule.keyword || keyword_foundright)) {
  352. _rule.end = e;
  353. found_right = 1;
  354. _rule.border = RULE_ON_LEFT_BORDER;
  355. _rule._context = count;
  356. if (!r->between_delimiters)
  357. if (!_rule.keyword) {
  358. _rule.context = count;
  359. contextchanged = 1;
  360. }
  361. break;
  362. }
  363. }
  364. }
  365. }
  366. }
  367. /* check again to turn on a keyword if the context switched */
  368. if (contextchanged && !_rule.keyword) {
  369. const char *p;
  370. p = (r = edit->rules[_rule.context])->keyword_first_chars;
  371. while (*(p = xx_strchr ((unsigned char *) p + 1, c))) {
  372. struct key_word *k;
  373. int count;
  374. long e;
  375. count = p - r->keyword_first_chars;
  376. k = r->keyword[count];
  377. e = compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start);
  378. if (e > 0) {
  379. _rule.end = e;
  380. _rule.keyword = count;
  381. break;
  382. }
  383. }
  384. }
  385. return _rule;
  386. }
  387. static struct syntax_rule edit_get_rule (WEdit * edit, long byte_index)
  388. {
  389. long i;
  390. if (byte_index > edit->last_get_rule) {
  391. for (i = edit->last_get_rule + 1; i <= byte_index; i++) {
  392. edit->rule = apply_rules_going_right (edit, i, edit->rule);
  393. if (i > (edit->syntax_marker ? edit->syntax_marker->offset + SYNTAX_MARKER_DENSITY : SYNTAX_MARKER_DENSITY)) {
  394. struct _syntax_marker *s;
  395. s = edit->syntax_marker;
  396. edit->syntax_marker = g_malloc0 (sizeof (struct _syntax_marker));
  397. edit->syntax_marker->next = s;
  398. edit->syntax_marker->offset = i;
  399. edit->syntax_marker->rule = edit->rule;
  400. }
  401. }
  402. } else if (byte_index < edit->last_get_rule) {
  403. struct _syntax_marker *s;
  404. for (;;) {
  405. if (!edit->syntax_marker) {
  406. memset (&edit->rule, 0, sizeof (edit->rule));
  407. for (i = -1; i <= byte_index; i++)
  408. edit->rule = apply_rules_going_right (edit, i, edit->rule);
  409. break;
  410. }
  411. if (byte_index >= edit->syntax_marker->offset) {
  412. edit->rule = edit->syntax_marker->rule;
  413. for (i = edit->syntax_marker->offset + 1; i <= byte_index; i++)
  414. edit->rule = apply_rules_going_right (edit, i, edit->rule);
  415. break;
  416. }
  417. s = edit->syntax_marker->next;
  418. MC_PTR_FREE (edit->syntax_marker);
  419. edit->syntax_marker = s;
  420. }
  421. }
  422. edit->last_get_rule = byte_index;
  423. return edit->rule;
  424. }
  425. static void translate_rule_to_color (WEdit * edit, struct syntax_rule rule, int *color)
  426. {
  427. struct key_word *k;
  428. k = edit->rules[rule.context]->keyword[rule.keyword];
  429. *color = k->color;
  430. }
  431. void edit_get_syntax_color (WEdit * edit, long byte_index, int *color)
  432. {
  433. if (edit->rules && byte_index < edit->last_byte &&
  434. option_syntax_highlighting && use_colors) {
  435. translate_rule_to_color (edit, edit_get_rule (edit, byte_index), color);
  436. } else {
  437. *color = use_colors ? EDITOR_NORMAL_COLOR_INDEX : 0;
  438. }
  439. }
  440. /*
  441. Returns 0 on error/eof or a count of the number of bytes read
  442. including the newline. Result must be free'd.
  443. In case of an error, *line will not be modified.
  444. */
  445. static int read_one_line (char **line, FILE * f)
  446. {
  447. GString *p = g_string_new ("");
  448. int c, r = 0;
  449. for (;;) {
  450. c = fgetc (f);
  451. if (c == EOF) {
  452. if (ferror (f)) {
  453. if (errno == EINTR)
  454. continue;
  455. r = 0;
  456. }
  457. break;
  458. }
  459. r++;
  460. /* handle all of \r\n, \r, \n correctly. */
  461. if (c == '\r') {
  462. if ( (c = fgetc (f)) == '\n')
  463. r++;
  464. else
  465. ungetc (c, f);
  466. break;
  467. }
  468. if (c == '\n')
  469. break;
  470. g_string_append_c (p, c);
  471. }
  472. if (r != 0) {
  473. *line = p->str;
  474. g_string_free (p, FALSE);
  475. } else {
  476. g_string_free (p, TRUE);
  477. }
  478. return r;
  479. }
  480. static char *convert (char *s)
  481. {
  482. char *r, *p;
  483. p = r = s;
  484. while (*s) {
  485. switch (*s) {
  486. case '\\':
  487. s++;
  488. switch (*s) {
  489. case ' ':
  490. *p = ' ';
  491. s--;
  492. break;
  493. case 'n':
  494. *p = '\n';
  495. break;
  496. case 'r':
  497. *p = '\r';
  498. break;
  499. case 't':
  500. *p = '\t';
  501. break;
  502. case 's':
  503. *p = ' ';
  504. break;
  505. case '*':
  506. *p = '*';
  507. break;
  508. case '\\':
  509. *p = '\\';
  510. break;
  511. case '[':
  512. case ']':
  513. *p = SYNTAX_TOKEN_BRACKET;
  514. break;
  515. case '{':
  516. case '}':
  517. *p = SYNTAX_TOKEN_BRACE;
  518. break;
  519. case 0:
  520. *p = *s;
  521. return r;
  522. default:
  523. *p = *s;
  524. break;
  525. }
  526. break;
  527. case '*':
  528. *p = SYNTAX_TOKEN_STAR;
  529. break;
  530. case '+':
  531. *p = SYNTAX_TOKEN_PLUS;
  532. break;
  533. default:
  534. *p = *s;
  535. break;
  536. }
  537. s++;
  538. p++;
  539. }
  540. *p = '\0';
  541. return r;
  542. }
  543. #define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
  544. static int get_args (char *l, char **args, int args_size)
  545. {
  546. int argc = 0;
  547. while (argc < args_size) {
  548. char *p = l;
  549. while (*p && whiteness (*p))
  550. p++;
  551. if (!*p)
  552. break;
  553. for (l = p + 1; *l && !whiteness (*l); l++);
  554. if (*l)
  555. *l++ = '\0';
  556. args[argc++] = convert (p);
  557. }
  558. args[argc] = (char *) NULL;
  559. return argc;
  560. }
  561. #define free_args(x)
  562. #define break_a {result=line;break;}
  563. #define check_a {if(!*a){result=line;break;}}
  564. #define check_not_a {if(*a){result=line;break;}}
  565. static int
  566. this_try_alloc_color_pair (const char *fg, const char *bg)
  567. {
  568. char f[80], b[80], *p;
  569. if (bg)
  570. if (!*bg)
  571. bg = 0;
  572. if (fg)
  573. if (!*fg)
  574. fg = 0;
  575. if (fg) {
  576. g_strlcpy (f, fg, sizeof (f));
  577. p = strchr (f, '/');
  578. if (p)
  579. *p = '\0';
  580. fg = f;
  581. }
  582. if (bg) {
  583. g_strlcpy (b, bg, sizeof (b));
  584. p = strchr (b, '/');
  585. if (p)
  586. *p = '\0';
  587. bg = b;
  588. }
  589. return try_alloc_color_pair (fg, bg);
  590. }
  591. static char *error_file_name = 0;
  592. static FILE *open_include_file (const char *filename)
  593. {
  594. FILE *f;
  595. MC_PTR_FREE (error_file_name);
  596. error_file_name = g_strdup (filename);
  597. if (*filename == PATH_SEP)
  598. return fopen (filename, "r");
  599. g_free (error_file_name);
  600. error_file_name = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR PATH_SEP_STR,
  601. filename, (char *) NULL);
  602. f = fopen (error_file_name, "r");
  603. if (f)
  604. return f;
  605. g_free (error_file_name);
  606. error_file_name = g_strconcat (mc_home, PATH_SEP_STR "syntax" PATH_SEP_STR,
  607. filename, (char *) NULL);
  608. return fopen (error_file_name, "r");
  609. }
  610. /* returns line number on error */
  611. static int
  612. edit_read_syntax_rules (WEdit *edit, FILE *f, char **args, int args_size)
  613. {
  614. FILE *g = 0;
  615. char *fg, *bg;
  616. char last_fg[32] = "", last_bg[32] = "";
  617. char whole_right[512];
  618. char whole_left[512];
  619. char *l = 0;
  620. int save_line = 0, line = 0;
  621. struct context_rule **r, *c = 0;
  622. int num_words = -1, num_contexts = -1;
  623. int result = 0;
  624. int argc;
  625. int i, j;
  626. int alloc_contexts = MAX_CONTEXTS,
  627. alloc_words_per_context = MAX_WORDS_PER_CONTEXT,
  628. max_alloc_words_per_context = MAX_WORDS_PER_CONTEXT;
  629. args[0] = 0;
  630. strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
  631. strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
  632. r = edit->rules = g_malloc0 (alloc_contexts * sizeof (struct context_rule *));
  633. if (!edit->defines)
  634. edit->defines = g_tree_new ((GCompareFunc) strcmp);
  635. for (;;) {
  636. char **a;
  637. line++;
  638. l = 0;
  639. if (!read_one_line (&l, f)) {
  640. if (g) {
  641. fclose (f);
  642. f = g;
  643. g = 0;
  644. line = save_line + 1;
  645. MC_PTR_FREE (error_file_name);
  646. MC_PTR_FREE (l);
  647. if (!read_one_line (&l, f))
  648. break;
  649. } else {
  650. break;
  651. }
  652. }
  653. argc = get_args (l, args, args_size);
  654. a = args + 1;
  655. if (!args[0]) {
  656. /* do nothing */
  657. } else if (!strcmp (args[0], "include")) {
  658. if (g || argc != 2) {
  659. result = line;
  660. break;
  661. }
  662. g = f;
  663. f = open_include_file (args[1]);
  664. if (!f) {
  665. MC_PTR_FREE (error_file_name);
  666. result = line;
  667. break;
  668. }
  669. save_line = line;
  670. line = 0;
  671. } else if (!strcmp (args[0], "wholechars")) {
  672. check_a;
  673. if (!strcmp (*a, "left")) {
  674. a++;
  675. g_strlcpy (whole_left, *a, sizeof (whole_left));
  676. } else if (!strcmp (*a, "right")) {
  677. a++;
  678. g_strlcpy (whole_right, *a, sizeof (whole_right));
  679. } else {
  680. g_strlcpy (whole_left, *a, sizeof (whole_left));
  681. g_strlcpy (whole_right, *a, sizeof (whole_right));
  682. }
  683. a++;
  684. check_not_a;
  685. } else if (!strcmp (args[0], "context")) {
  686. check_a;
  687. if (num_contexts == -1) {
  688. if (strcmp (*a, "default")) { /* first context is the default */
  689. break_a;
  690. }
  691. a++;
  692. c = r[0] = g_malloc0 (sizeof (struct context_rule));
  693. c->left = g_strdup (" ");
  694. c->right = g_strdup (" ");
  695. num_contexts = 0;
  696. } else {
  697. /* Terminate previous context. */
  698. r[num_contexts - 1]->keyword[num_words] = NULL;
  699. c = r[num_contexts] = g_malloc0 (sizeof (struct context_rule));
  700. if (!strcmp (*a, "exclusive")) {
  701. a++;
  702. c->between_delimiters = 1;
  703. }
  704. check_a;
  705. if (!strcmp (*a, "whole")) {
  706. a++;
  707. c->whole_word_chars_left = g_strdup (whole_left);
  708. c->whole_word_chars_right = g_strdup (whole_right);
  709. } else if (!strcmp (*a, "wholeleft")) {
  710. a++;
  711. c->whole_word_chars_left = g_strdup (whole_left);
  712. } else if (!strcmp (*a, "wholeright")) {
  713. a++;
  714. c->whole_word_chars_right = g_strdup (whole_right);
  715. }
  716. check_a;
  717. if (!strcmp (*a, "linestart")) {
  718. a++;
  719. c->line_start_left = 1;
  720. }
  721. check_a;
  722. c->left = g_strdup (*a++);
  723. check_a;
  724. if (!strcmp (*a, "linestart")) {
  725. a++;
  726. c->line_start_right = 1;
  727. }
  728. check_a;
  729. c->right = g_strdup (*a++);
  730. c->first_left = *c->left;
  731. c->first_right = *c->right;
  732. }
  733. c->keyword = g_malloc (alloc_words_per_context * sizeof (struct key_word *));
  734. num_words = 1;
  735. c->keyword[0] = g_malloc0 (sizeof (struct key_word));
  736. subst_defines (edit->defines, a, &args[1024]);
  737. fg = *a;
  738. if (*a)
  739. a++;
  740. bg = *a;
  741. if (*a)
  742. a++;
  743. g_strlcpy (last_fg, fg ? fg : "", sizeof (last_fg));
  744. g_strlcpy (last_bg, bg ? bg : "", sizeof (last_bg));
  745. c->keyword[0]->color = this_try_alloc_color_pair (fg, bg);
  746. c->keyword[0]->keyword = g_strdup (" ");
  747. check_not_a;
  748. alloc_words_per_context = MAX_WORDS_PER_CONTEXT;
  749. if (++num_contexts >= alloc_contexts) {
  750. struct context_rule **tmp;
  751. alloc_contexts += 128;
  752. tmp = g_realloc (r, alloc_contexts * sizeof (struct context_rule *));
  753. r = tmp;
  754. }
  755. } else if (!strcmp (args[0], "spellcheck")) {
  756. if (!c) {
  757. result = line;
  758. break;
  759. }
  760. c->spelling = 1;
  761. } else if (!strcmp (args[0], "keyword")) {
  762. struct key_word *k;
  763. if (num_words == -1)
  764. break_a;
  765. check_a;
  766. k = r[num_contexts - 1]->keyword[num_words] = g_malloc0 (sizeof (struct key_word));
  767. if (!strcmp (*a, "whole")) {
  768. a++;
  769. k->whole_word_chars_left = g_strdup (whole_left);
  770. k->whole_word_chars_right = g_strdup (whole_right);
  771. } else if (!strcmp (*a, "wholeleft")) {
  772. a++;
  773. k->whole_word_chars_left = g_strdup (whole_left);
  774. } else if (!strcmp (*a, "wholeright")) {
  775. a++;
  776. k->whole_word_chars_right = g_strdup (whole_right);
  777. }
  778. check_a;
  779. if (!strcmp (*a, "linestart")) {
  780. a++;
  781. k->line_start = 1;
  782. }
  783. check_a;
  784. if (!strcmp (*a, "whole")) {
  785. break_a;
  786. }
  787. k->keyword = g_strdup (*a++);
  788. k->first = *k->keyword;
  789. subst_defines (edit->defines, a, &args[1024]);
  790. fg = *a;
  791. if (*a)
  792. a++;
  793. bg = *a;
  794. if (*a)
  795. a++;
  796. if (!fg)
  797. fg = last_fg;
  798. if (!bg)
  799. bg = last_bg;
  800. k->color = this_try_alloc_color_pair (fg, bg);
  801. check_not_a;
  802. if (++num_words >= alloc_words_per_context) {
  803. struct key_word **tmp;
  804. alloc_words_per_context += 1024;
  805. if (alloc_words_per_context > max_alloc_words_per_context)
  806. max_alloc_words_per_context = alloc_words_per_context;
  807. tmp = g_realloc (c->keyword, alloc_words_per_context * sizeof (struct key_word *));
  808. c->keyword = tmp;
  809. }
  810. } else if (*(args[0]) == '#') {
  811. /* do nothing for comment */
  812. } else if (!strcmp (args[0], "file")) {
  813. break;
  814. } else if (!strcmp (args[0], "define")) {
  815. char *key = *a++;
  816. char **argv;
  817. if (argc < 3)
  818. break_a;
  819. if ((argv = g_tree_lookup (edit->defines, key))) {
  820. mc_defines_destroy (NULL, argv, NULL);
  821. } else {
  822. key = g_strdup (key);
  823. }
  824. argv = g_new (char *, argc - 1);
  825. g_tree_insert (edit->defines, key, argv);
  826. while (*a) {
  827. *argv++ = g_strdup (*a++);
  828. };
  829. *argv = NULL;
  830. } else { /* anything else is an error */
  831. break_a;
  832. }
  833. free_args (args);
  834. MC_PTR_FREE (l);
  835. }
  836. free_args (args);
  837. MC_PTR_FREE (l);
  838. /* Terminate context array. */
  839. if (num_contexts > 0) {
  840. r[num_contexts - 1]->keyword[num_words] = NULL;
  841. r[num_contexts] = NULL;
  842. }
  843. if (!edit->rules[0])
  844. MC_PTR_FREE (edit->rules);
  845. if (result)
  846. return result;
  847. if (num_contexts == -1) {
  848. return line;
  849. }
  850. {
  851. char *first_chars, *p;
  852. first_chars = g_malloc (max_alloc_words_per_context + 2);
  853. for (i = 0; edit->rules[i]; i++) {
  854. c = edit->rules[i];
  855. p = first_chars;
  856. *p++ = (char) 1;
  857. for (j = 1; c->keyword[j]; j++)
  858. *p++ = c->keyword[j]->first;
  859. *p = '\0';
  860. c->keyword_first_chars = g_strdup (first_chars);
  861. }
  862. g_free (first_chars);
  863. }
  864. return result;
  865. }
  866. void edit_free_syntax_rules (WEdit * edit)
  867. {
  868. int i, j;
  869. if (!edit)
  870. return;
  871. if (edit->defines)
  872. destroy_defines (&edit->defines);
  873. if (!edit->rules)
  874. return;
  875. edit_get_rule (edit, -1);
  876. MC_PTR_FREE (edit->syntax_type);
  877. edit->syntax_type = 0;
  878. for (i = 0; edit->rules[i]; i++) {
  879. if (edit->rules[i]->keyword) {
  880. for (j = 0; edit->rules[i]->keyword[j]; j++) {
  881. MC_PTR_FREE (edit->rules[i]->keyword[j]->keyword);
  882. MC_PTR_FREE (edit->rules[i]->keyword[j]->whole_word_chars_left);
  883. MC_PTR_FREE (edit->rules[i]->keyword[j]->whole_word_chars_right);
  884. MC_PTR_FREE (edit->rules[i]->keyword[j]);
  885. }
  886. }
  887. MC_PTR_FREE (edit->rules[i]->left);
  888. MC_PTR_FREE (edit->rules[i]->right);
  889. MC_PTR_FREE (edit->rules[i]->whole_word_chars_left);
  890. MC_PTR_FREE (edit->rules[i]->whole_word_chars_right);
  891. MC_PTR_FREE (edit->rules[i]->keyword);
  892. MC_PTR_FREE (edit->rules[i]->keyword_first_chars);
  893. MC_PTR_FREE (edit->rules[i]);
  894. }
  895. while (edit->syntax_marker) {
  896. struct _syntax_marker *s = edit->syntax_marker->next;
  897. MC_PTR_FREE (edit->syntax_marker);
  898. edit->syntax_marker = s;
  899. }
  900. MC_PTR_FREE (edit->rules);
  901. }
  902. /* returns -1 on file error, line number on error in file syntax */
  903. static int
  904. edit_read_syntax_file (WEdit * edit, char ***pnames, const char *syntax_file,
  905. const char *editor_file, const char *first_line,
  906. const char *type)
  907. {
  908. #define NENTRIES 30
  909. FILE *f, *g = NULL;
  910. regex_t r;
  911. regmatch_t pmatch[1];
  912. char *args[1024], *l = 0;
  913. int line = 0;
  914. int result = 0;
  915. int count = 0;
  916. char *lib_file;
  917. int found = 0;
  918. char **tmpnames = NULL;
  919. f = fopen (syntax_file, "r");
  920. if (!f){
  921. lib_file = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
  922. f = fopen (lib_file, "r");
  923. g_free (lib_file);
  924. if (!f)
  925. return -1;
  926. }
  927. args[0] = 0;
  928. for (;;) {
  929. line++;
  930. MC_PTR_FREE (l);
  931. if (!read_one_line (&l, f))
  932. break;
  933. (void)get_args (l, args, 1023); /* Final NULL */
  934. if (!args[0])
  935. continue;
  936. /* Looking for `include ...` lines before first `file ...` ones */
  937. if (!found && !strcmp (args[0], "include")) {
  938. if (g)
  939. continue;
  940. if (!args[1] || !(g = open_include_file (args[1]))) {
  941. result = line;
  942. break;
  943. }
  944. goto found_type;
  945. }
  946. /* looking for `file ...' lines only */
  947. if (strcmp (args[0], "file")) {
  948. continue;
  949. }
  950. found = 1;
  951. /* must have two args or report error */
  952. if (!args[1] || !args[2]) {
  953. result = line;
  954. break;
  955. }
  956. if (pnames && *pnames) {
  957. /* 1: just collecting a list of names of rule sets */
  958. /* Reallocate the list if required */
  959. if (count % NENTRIES == 0) {
  960. if ((tmpnames = (char**) g_realloc (*pnames, (count + NENTRIES
  961. + 1) * sizeof (char*))) != NULL)
  962. *pnames = tmpnames;
  963. else
  964. abort ();
  965. }
  966. (*pnames)[count++] = g_strdup (args[2]);
  967. (*pnames)[count] = NULL;
  968. } else if (type) {
  969. /* 2: rule set was explicitly specified by the caller */
  970. if (!strcmp (type, args[2]))
  971. goto found_type;
  972. } else if (editor_file && edit) {
  973. /* 3: auto-detect rule set from regular expressions */
  974. int q;
  975. if (regcomp (&r, args[1], REG_EXTENDED)) {
  976. result = line;
  977. break;
  978. }
  979. /* does filename match arg 1 ? */
  980. q = !regexec (&r, editor_file, 1, pmatch, 0);
  981. regfree (&r);
  982. if (!q && args[3]) {
  983. if (regcomp (&r, args[3], REG_EXTENDED)) {
  984. result = line;
  985. break;
  986. }
  987. /* does first line match arg 3 ? */
  988. q = !regexec (&r, first_line, 1, pmatch, 0);
  989. regfree (&r);
  990. }
  991. if (q) {
  992. int line_error;
  993. char *syntax_type;
  994. found_type:
  995. syntax_type = args[2];
  996. line_error = edit_read_syntax_rules (edit, g ? g : f, args, 1023);
  997. if (line_error) {
  998. if (!error_file_name) /* an included file */
  999. result = line + line_error;
  1000. else
  1001. result = line_error;
  1002. } else {
  1003. MC_PTR_FREE (edit->syntax_type);
  1004. edit->syntax_type = g_strdup (syntax_type);
  1005. /* if there are no rules then turn off syntax highlighting for speed */
  1006. if (!g && !edit->rules[1])
  1007. if (!edit->rules[0]->keyword[1] && !edit->rules[0]->spelling) {
  1008. edit_free_syntax_rules (edit);
  1009. break;
  1010. }
  1011. }
  1012. if (g) {
  1013. fclose (g);
  1014. g = NULL;
  1015. } else {
  1016. break;
  1017. }
  1018. }
  1019. }
  1020. }
  1021. MC_PTR_FREE (l);
  1022. fclose (f);
  1023. return result;
  1024. }
  1025. static char *get_first_editor_line (WEdit * edit)
  1026. {
  1027. int i;
  1028. static char s[256];
  1029. s[0] = '\0';
  1030. if (!edit)
  1031. return s;
  1032. for (i = 0; i < 255; i++) {
  1033. s[i] = edit_get_byte (edit, i);
  1034. if (s[i] == '\n') {
  1035. s[i] = '\0';
  1036. break;
  1037. }
  1038. }
  1039. s[255] = '\0';
  1040. return s;
  1041. }
  1042. /*
  1043. * Load rules into edit struct. Either edit or *pnames must be NULL. If
  1044. * edit is NULL, a list of types will be stored into names. If type is
  1045. * NULL, then the type will be selected according to the filename.
  1046. */
  1047. void
  1048. edit_load_syntax (WEdit *edit, char ***pnames, const char *type)
  1049. {
  1050. int r;
  1051. char *f = NULL;
  1052. if (option_auto_syntax)
  1053. type = NULL;
  1054. edit_free_syntax_rules (edit);
  1055. if (!use_colors)
  1056. return;
  1057. if (!option_syntax_highlighting && (!pnames || !*pnames))
  1058. return;
  1059. if (edit) {
  1060. if (!edit->filename)
  1061. return;
  1062. if (!*edit->filename && !type)
  1063. return;
  1064. }
  1065. f = concat_dir_and_file (home_dir, SYNTAX_FILE);
  1066. r = edit_read_syntax_file (edit, pnames, f, edit ? edit->filename : 0,
  1067. get_first_editor_line (edit), type);
  1068. if (r == -1) {
  1069. edit_free_syntax_rules (edit);
  1070. message (D_ERROR, _(" Load syntax file "),
  1071. _(" Cannot open file %s \n %s "), f,
  1072. unix_error_string (errno));
  1073. } else if (r) {
  1074. edit_free_syntax_rules (edit);
  1075. message (D_ERROR, _(" Load syntax file "),
  1076. _(" Error in file %s on line %d "),
  1077. error_file_name ? error_file_name : f, r);
  1078. MC_PTR_FREE (error_file_name);
  1079. } else {
  1080. /* succeeded */
  1081. }
  1082. g_free (f);
  1083. }