syntax.c 26 KB

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