syntax.c 28 KB

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