syntax.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136
  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. strncpy (f, fg, sizeof (f) - 1);
  561. f[sizeof (f) - 1] = 0;
  562. p = strchr (f, '/');
  563. if (p)
  564. *p = '\0';
  565. fg = f;
  566. }
  567. if (bg) {
  568. strncpy (b, bg, sizeof (b) - 1);
  569. b[sizeof (b) - 1] = 0;
  570. p = strchr (b, '/');
  571. if (p)
  572. *p = '\0';
  573. bg = b;
  574. }
  575. return try_alloc_color_pair (fg, bg);
  576. }
  577. static char *error_file_name = 0;
  578. static FILE *open_include_file (const char *filename)
  579. {
  580. FILE *f;
  581. syntax_g_free (error_file_name);
  582. error_file_name = g_strdup (filename);
  583. if (*filename == PATH_SEP)
  584. return fopen (filename, "r");
  585. g_free (error_file_name);
  586. error_file_name = g_strconcat (home_dir, EDIT_DIR PATH_SEP_STR,
  587. filename, NULL);
  588. f = fopen (error_file_name, "r");
  589. if (f)
  590. return f;
  591. g_free (error_file_name);
  592. error_file_name = g_strconcat (mc_home, PATH_SEP_STR "syntax" PATH_SEP_STR,
  593. filename, NULL);
  594. return fopen (error_file_name, "r");
  595. }
  596. /* returns line number on error */
  597. static int
  598. edit_read_syntax_rules (WEdit *edit, FILE *f, char **args)
  599. {
  600. FILE *g = 0;
  601. char *fg, *bg;
  602. char last_fg[32] = "", last_bg[32] = "";
  603. char whole_right[512];
  604. char whole_left[512];
  605. char *l = 0;
  606. int save_line = 0, line = 0;
  607. struct context_rule **r, *c = 0;
  608. int num_words = -1, num_contexts = -1;
  609. int argc, result = 0;
  610. int i, j;
  611. int alloc_contexts = MAX_CONTEXTS,
  612. alloc_words_per_context = MAX_WORDS_PER_CONTEXT,
  613. max_alloc_words_per_context = MAX_WORDS_PER_CONTEXT;
  614. args[0] = 0;
  615. strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
  616. strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
  617. r = edit->rules = g_malloc (alloc_contexts * sizeof (struct context_rule *));
  618. if (!edit->defines)
  619. edit->defines = g_tree_new ((GCompareFunc) strcmp);
  620. for (;;) {
  621. char **a;
  622. line++;
  623. l = 0;
  624. if (!read_one_line (&l, f)) {
  625. if (g) {
  626. fclose (f);
  627. f = g;
  628. g = 0;
  629. line = save_line + 1;
  630. syntax_g_free (error_file_name);
  631. if (l)
  632. syntax_g_free (l);
  633. if (!read_one_line (&l, f))
  634. break;
  635. } else {
  636. break;
  637. }
  638. }
  639. get_args (l, args, &argc);
  640. a = args + 1;
  641. if (!args[0]) {
  642. /* do nothing */
  643. } else if (!strcmp (args[0], "include")) {
  644. if (g || argc != 2) {
  645. result = line;
  646. break;
  647. }
  648. g = f;
  649. f = open_include_file (args[1]);
  650. if (!f) {
  651. syntax_g_free (error_file_name);
  652. result = line;
  653. break;
  654. }
  655. save_line = line;
  656. line = 0;
  657. } else if (!strcmp (args[0], "wholechars")) {
  658. check_a;
  659. if (!strcmp (*a, "left")) {
  660. a++;
  661. strncpy (whole_left, *a, sizeof (whole_left) - 1);
  662. whole_left[sizeof (whole_left) - 1] = 0;
  663. } else if (!strcmp (*a, "right")) {
  664. a++;
  665. strncpy (whole_right, *a, sizeof (whole_right) - 1);
  666. whole_right[sizeof (whole_right) - 1] = 0;
  667. } else {
  668. strncpy (whole_left, *a, sizeof (whole_left) - 1);
  669. whole_left[sizeof (whole_left) - 1] = 0;
  670. strncpy (whole_right, *a, sizeof (whole_right) - 1);
  671. whole_right[sizeof (whole_right) - 1] = 0;
  672. }
  673. a++;
  674. check_not_a;
  675. } else if (!strcmp (args[0], "context")) {
  676. check_a;
  677. if (num_contexts == -1) {
  678. if (strcmp (*a, "default")) { /* first context is the default */
  679. break_a;
  680. }
  681. a++;
  682. c = r[0] = g_malloc0 (sizeof (struct context_rule));
  683. c->left = g_strdup (" ");
  684. c->right = g_strdup (" ");
  685. num_contexts = 0;
  686. } else {
  687. /* Terminate previous context. */
  688. r[num_contexts - 1]->keyword[num_words] = NULL;
  689. c = r[num_contexts] = g_malloc0 (sizeof (struct context_rule));
  690. if (!strcmp (*a, "exclusive")) {
  691. a++;
  692. c->between_delimiters = 1;
  693. }
  694. check_a;
  695. if (!strcmp (*a, "whole")) {
  696. a++;
  697. c->whole_word_chars_left = g_strdup (whole_left);
  698. c->whole_word_chars_right = g_strdup (whole_right);
  699. } else if (!strcmp (*a, "wholeleft")) {
  700. a++;
  701. c->whole_word_chars_left = g_strdup (whole_left);
  702. } else if (!strcmp (*a, "wholeright")) {
  703. a++;
  704. c->whole_word_chars_right = g_strdup (whole_right);
  705. }
  706. check_a;
  707. if (!strcmp (*a, "linestart")) {
  708. a++;
  709. c->line_start_left = 1;
  710. }
  711. check_a;
  712. c->left = g_strdup (*a++);
  713. check_a;
  714. if (!strcmp (*a, "linestart")) {
  715. a++;
  716. c->line_start_right = 1;
  717. }
  718. check_a;
  719. c->right = g_strdup (*a++);
  720. c->first_left = *c->left;
  721. c->first_right = *c->right;
  722. }
  723. c->keyword = g_malloc (alloc_words_per_context * sizeof (struct key_word *));
  724. num_words = 1;
  725. c->keyword[0] = g_malloc0 (sizeof (struct key_word));
  726. subst_defines (edit->defines, a, &args[1024]);
  727. fg = *a;
  728. if (*a)
  729. a++;
  730. bg = *a;
  731. if (*a)
  732. a++;
  733. strncpy (last_fg, fg ? fg : "", sizeof (last_fg) - 1);
  734. last_fg[sizeof (last_fg) - 1] = 0;
  735. strncpy (last_bg, bg ? bg : "", sizeof (last_bg) - 1);
  736. last_bg[sizeof (last_bg) - 1] = 0;
  737. c->keyword[0]->color = this_try_alloc_color_pair (fg, bg);
  738. c->keyword[0]->keyword = g_strdup (" ");
  739. check_not_a;
  740. alloc_words_per_context = MAX_WORDS_PER_CONTEXT;
  741. if (++num_contexts >= alloc_contexts) {
  742. struct context_rule **tmp;
  743. alloc_contexts += 128;
  744. tmp = g_realloc (r, alloc_contexts * sizeof (struct context_rule *));
  745. r = tmp;
  746. }
  747. } else if (!strcmp (args[0], "spellcheck")) {
  748. if (!c) {
  749. result = line;
  750. break;
  751. }
  752. c->spelling = 1;
  753. } else if (!strcmp (args[0], "keyword")) {
  754. struct key_word *k;
  755. if (num_words == -1)
  756. break_a;
  757. check_a;
  758. k = r[num_contexts - 1]->keyword[num_words] = g_malloc0 (sizeof (struct key_word));
  759. if (!strcmp (*a, "whole")) {
  760. a++;
  761. k->whole_word_chars_left = g_strdup (whole_left);
  762. k->whole_word_chars_right = g_strdup (whole_right);
  763. } else if (!strcmp (*a, "wholeleft")) {
  764. a++;
  765. k->whole_word_chars_left = g_strdup (whole_left);
  766. } else if (!strcmp (*a, "wholeright")) {
  767. a++;
  768. k->whole_word_chars_right = g_strdup (whole_right);
  769. }
  770. check_a;
  771. if (!strcmp (*a, "linestart")) {
  772. a++;
  773. k->line_start = 1;
  774. }
  775. check_a;
  776. if (!strcmp (*a, "whole")) {
  777. break_a;
  778. }
  779. k->keyword = g_strdup (*a++);
  780. k->first = *k->keyword;
  781. subst_defines (edit->defines, a, &args[1024]);
  782. fg = *a;
  783. if (*a)
  784. a++;
  785. bg = *a;
  786. if (*a)
  787. a++;
  788. if (!fg)
  789. fg = last_fg;
  790. if (!bg)
  791. bg = last_bg;
  792. k->color = this_try_alloc_color_pair (fg, bg);
  793. check_not_a;
  794. if (++num_words >= alloc_words_per_context) {
  795. struct key_word **tmp;
  796. alloc_words_per_context += 1024;
  797. if (alloc_words_per_context > max_alloc_words_per_context)
  798. max_alloc_words_per_context = alloc_words_per_context;
  799. tmp = g_realloc (c->keyword, alloc_words_per_context * sizeof (struct key_word *));
  800. c->keyword = tmp;
  801. }
  802. } else if (*(args[0]) == '#') {
  803. /* do nothing for comment */
  804. } else if (!strcmp (args[0], "file")) {
  805. break;
  806. } else if (!strcmp (args[0], "define")) {
  807. char *key = *a++;
  808. char **argv;
  809. if (argc < 3)
  810. break_a;
  811. if ((argv = g_tree_lookup (edit->defines, key))) {
  812. mc_defines_destroy (NULL, argv, NULL);
  813. } else {
  814. key = g_strdup (key);
  815. }
  816. argv = g_new (char *, argc - 1);
  817. g_tree_insert (edit->defines, key, argv);
  818. while (*a) {
  819. *argv++ = g_strdup (*a++);
  820. };
  821. *argv = NULL;
  822. } else { /* anything else is an error */
  823. break_a;
  824. }
  825. free_args (args);
  826. syntax_g_free (l);
  827. }
  828. free_args (args);
  829. syntax_g_free (l);
  830. /* Terminate context array. */
  831. if (num_contexts > 0) {
  832. r[num_contexts - 1]->keyword[num_words] = NULL;
  833. r[num_contexts] = NULL;
  834. }
  835. if (!edit->rules[0])
  836. syntax_g_free (edit->rules);
  837. if (result)
  838. return result;
  839. if (num_contexts == -1) {
  840. return line;
  841. }
  842. {
  843. char *first_chars, *p;
  844. first_chars = g_malloc (max_alloc_words_per_context + 2);
  845. for (i = 0; edit->rules[i]; i++) {
  846. c = edit->rules[i];
  847. p = first_chars;
  848. *p++ = (char) 1;
  849. for (j = 1; c->keyword[j]; j++)
  850. *p++ = c->keyword[j]->first;
  851. *p = '\0';
  852. c->keyword_first_chars = g_strdup (first_chars);
  853. }
  854. g_free (first_chars);
  855. }
  856. return result;
  857. }
  858. void edit_free_syntax_rules (WEdit * edit)
  859. {
  860. int i, j;
  861. if (!edit)
  862. return;
  863. if (edit->defines)
  864. destroy_defines (&edit->defines);
  865. if (!edit->rules)
  866. return;
  867. edit_get_rule (edit, -1);
  868. syntax_g_free (edit->syntax_type);
  869. edit->syntax_type = 0;
  870. for (i = 0; edit->rules[i]; i++) {
  871. if (edit->rules[i]->keyword) {
  872. for (j = 0; edit->rules[i]->keyword[j]; j++) {
  873. syntax_g_free (edit->rules[i]->keyword[j]->keyword);
  874. syntax_g_free (edit->rules[i]->keyword[j]->whole_word_chars_left);
  875. syntax_g_free (edit->rules[i]->keyword[j]->whole_word_chars_right);
  876. syntax_g_free (edit->rules[i]->keyword[j]);
  877. }
  878. }
  879. syntax_g_free (edit->rules[i]->left);
  880. syntax_g_free (edit->rules[i]->right);
  881. syntax_g_free (edit->rules[i]->whole_word_chars_left);
  882. syntax_g_free (edit->rules[i]->whole_word_chars_right);
  883. syntax_g_free (edit->rules[i]->keyword);
  884. syntax_g_free (edit->rules[i]->keyword_first_chars);
  885. syntax_g_free (edit->rules[i]);
  886. }
  887. while (edit->syntax_marker) {
  888. struct _syntax_marker *s = edit->syntax_marker->next;
  889. syntax_g_free (edit->syntax_marker);
  890. edit->syntax_marker = s;
  891. }
  892. syntax_g_free (edit->rules);
  893. }
  894. /* returns -1 on file error, line number on error in file syntax */
  895. static int
  896. edit_read_syntax_file (WEdit * edit, char **names, const char *syntax_file,
  897. const char *editor_file, const char *first_line,
  898. const char *type)
  899. {
  900. FILE *f, *g = NULL;
  901. regex_t r;
  902. regmatch_t pmatch[1];
  903. char *args[1024], *l = 0;
  904. int line = 0;
  905. int argc;
  906. int result = 0;
  907. int count = 0;
  908. char *lib_file;
  909. int found = 0;
  910. f = fopen (syntax_file, "r");
  911. if (!f){
  912. lib_file = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
  913. f = fopen (lib_file, "r");
  914. g_free (lib_file);
  915. if (!f)
  916. return -1;
  917. }
  918. args[0] = 0;
  919. for (;;) {
  920. line++;
  921. syntax_g_free (l);
  922. if (!read_one_line (&l, f))
  923. break;
  924. get_args (l, args, &argc);
  925. if (!args[0])
  926. continue;
  927. /* Looking for `include ...` lines before first `file ...` ones */
  928. if (!found && !strcmp (args[0], "include")) {
  929. if (g)
  930. continue;
  931. if (!args[1] || !(g = open_include_file (args[1]))) {
  932. result = line;
  933. break;
  934. }
  935. goto found_type;
  936. }
  937. /* looking for `file ...' lines only */
  938. if (strcmp (args[0], "file")) {
  939. continue;
  940. }
  941. found = 1;
  942. /* must have two args or report error */
  943. if (!args[1] || !args[2]) {
  944. result = line;
  945. break;
  946. }
  947. if (names) {
  948. /* 1: just collecting a list of names of rule sets */
  949. names[count++] = g_strdup (args[2]);
  950. names[count] = 0;
  951. } else if (type) {
  952. /* 2: rule set was explicitly specified by the caller */
  953. if (!strcmp (type, args[2]))
  954. goto found_type;
  955. } else if (editor_file && edit) {
  956. /* 3: auto-detect rule set from regular expressions */
  957. int q;
  958. if (regcomp (&r, args[1], REG_EXTENDED)) {
  959. result = line;
  960. break;
  961. }
  962. /* does filename match arg 1 ? */
  963. q = !regexec (&r, editor_file, 1, pmatch, 0);
  964. regfree (&r);
  965. if (!q && args[3]) {
  966. if (regcomp (&r, args[3], REG_EXTENDED)) {
  967. result = line;
  968. break;
  969. }
  970. /* does first line match arg 3 ? */
  971. q = !regexec (&r, first_line, 1, pmatch, 0);
  972. regfree (&r);
  973. }
  974. if (q) {
  975. int line_error;
  976. char *syntax_type;
  977. found_type:
  978. syntax_type = args[2];
  979. line_error = edit_read_syntax_rules (edit, g ? g : f, args);
  980. if (line_error) {
  981. if (!error_file_name) /* an included file */
  982. result = line + line_error;
  983. else
  984. result = line_error;
  985. } else {
  986. syntax_g_free (edit->syntax_type);
  987. edit->syntax_type = g_strdup (syntax_type);
  988. /* if there are no rules then turn off syntax highlighting for speed */
  989. if (!g && !edit->rules[1])
  990. if (!edit->rules[0]->keyword[1] && !edit->rules[0]->spelling) {
  991. edit_free_syntax_rules (edit);
  992. break;
  993. }
  994. }
  995. if (g) {
  996. fclose (g);
  997. g = NULL;
  998. } else {
  999. break;
  1000. }
  1001. }
  1002. }
  1003. }
  1004. syntax_g_free (l);
  1005. fclose (f);
  1006. return result;
  1007. }
  1008. static char *get_first_editor_line (WEdit * edit)
  1009. {
  1010. int i;
  1011. static char s[256];
  1012. s[0] = '\0';
  1013. if (!edit)
  1014. return s;
  1015. for (i = 0; i < 255; i++) {
  1016. s[i] = edit_get_byte (edit, i);
  1017. if (s[i] == '\n') {
  1018. s[i] = '\0';
  1019. break;
  1020. }
  1021. }
  1022. s[255] = '\0';
  1023. return s;
  1024. }
  1025. /*
  1026. * Load rules into edit struct. Either edit or names must be NULL. If
  1027. * edit is NULL, a list of types will be stored into names. If type is
  1028. * NULL, then the type will be selected according to the filename.
  1029. */
  1030. void
  1031. edit_load_syntax (WEdit *edit, char **names, const char *type)
  1032. {
  1033. int r;
  1034. char *f;
  1035. edit_free_syntax_rules (edit);
  1036. if (!use_colors)
  1037. return;
  1038. if (!option_syntax_highlighting)
  1039. return;
  1040. if (edit) {
  1041. if (!edit->filename)
  1042. return;
  1043. if (!*edit->filename && !type)
  1044. return;
  1045. }
  1046. f = catstrs (home_dir, SYNTAX_FILE, 0);
  1047. r = edit_read_syntax_file (edit, names, f, edit ? edit->filename : 0,
  1048. get_first_editor_line (edit), type);
  1049. if (r == -1) {
  1050. edit_free_syntax_rules (edit);
  1051. message (D_ERROR, _(" Load syntax file "),
  1052. _(" Cannot open file %s \n %s "), f,
  1053. unix_error_string (errno));
  1054. return;
  1055. }
  1056. if (r) {
  1057. edit_free_syntax_rules (edit);
  1058. message (D_ERROR, _(" Load syntax file "),
  1059. _(" Error in file %s on line %d "),
  1060. error_file_name ? error_file_name : f, r);
  1061. syntax_g_free (error_file_name);
  1062. return;
  1063. }
  1064. }