syntax.c 28 KB

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