syntax.c 27 KB

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