]> git.lyx.org Git - features.git/blob - src/lyxlex.C
last updates from 1.0.4, no more updates expected from that branch now
[features.git] / src / lyxlex.C
1 //  Generalized simple lexical analizer.
2 //  It can be used for simple syntax parsers, like lyxrc,
3 //  texclass and others to come.   [asierra30/03/96]
4 //
5 //   (C) 1996 Lyx Team.
6
7 #include <config.h>
8 //#include "definitions.h"
9
10 #include <stdlib.h>
11 #include <string.h>
12
13 #ifdef __GNUG__
14 #pragma implementation "lyxlex.h"
15 #endif
16
17 #include "lyxlex.h"
18 #include "error.h"
19 #include "filetools.h"
20
21 //      $Id: lyxlex.C,v 1.1 1999/09/27 18:44:37 larsbj Exp $    
22
23 #if !defined(lint) && !defined(WITH_WARNINGS)
24 static char vcid[] = "$Id: lyxlex.C,v 1.1 1999/09/27 18:44:37 larsbj Exp $";
25 #endif /* lint */
26
27
28 LyXLex::LyXLex(keyword_item* tab, int num)
29         : table(tab), no_items(num)
30 {
31         file = NULL;
32         owns_file = false;
33         status = 0;
34         pushed = NULL;
35 }
36
37
38 void LyXLex::pushTable(keyword_item* tab, int num)
39 {
40         pushed_table *tmppu = new pushed_table;
41         tmppu->next = pushed;
42         tmppu->table_elem = table;
43         tmppu->table_siz = no_items;
44         pushed = tmppu;
45         table = tab;
46         no_items = num;
47 }
48
49
50 void LyXLex::popTable()
51 {
52         if (pushed == NULL)
53                 lyxerr.print("LyXLex error: nothing to pop!");
54
55         pushed_table *tmp;
56         tmp = pushed;
57         table = tmp->table_elem;
58         no_items = tmp->table_siz;
59         tmp->table_elem = NULL;
60         pushed = tmp->next;
61         delete tmp;
62 }
63
64
65 void LyXLex::printTable()
66 {
67         lyxerr.print(LString("\nNumber of tags: ")+no_items);
68         for(int i=0; i<no_items; i++)
69                 lyxerr.print(LString("table[")+i+
70                               "]:  tag: `"+table[i].tag+
71                               "'  code:"+(long)table[i].code);
72         lyxerr.print(LString());
73 }
74
75
76 void LyXLex::printError(LString const & message)
77 {
78         LString tmpmsg = message;
79         tmpmsg.subst("$$Token",GetString());
80         lyxerr.print("LyX: "+tmpmsg+" [around line "+lineno+" of file "
81                       +MakeDisplayPath(name)+']');
82 }
83
84
85 bool LyXLex::setFile(LString const & filename)
86 {
87         if (file) 
88                 lyxerr.print("Error in LyXLex::setFile: file already set.");
89         file = fopen(filename.c_str(), "r");
90         name = filename;
91         owns_file = true;
92         lineno = 0;
93         return (file ? true : false);
94 }
95
96
97 void LyXLex::setFile(FILE *f)
98 {
99         if (file) 
100                 lyxerr.print("Error in LyXLex::setFile: file already set.");
101         file = f;
102         owns_file = false;
103         lineno = 0; // this is bogus if the file already has been read from
104 }
105
106
107 int LyXLex::lex()
108 {
109         //NOTE: possible bug.
110    if (next() && status==LEX_TOKEN)
111        return search_kw(buff);
112    else
113        return status;
114 }
115
116
117 int LyXLex::GetInteger()
118 {
119    if (buff[0]>' ')   
120        return atoi(buff);
121    else {
122         printError("Bad integer `$$Token'");
123         return -1;
124    }
125 }
126
127
128 float LyXLex::GetFloat()
129 {
130    if (buff[0]>' ')   
131        return (float)strtod(buff, (char**)NULL);
132    else {
133         printError("Bad float `$$Token'");
134         return -1;
135    }
136 }
137
138
139 LString LyXLex::GetString() const
140 {
141         return LString(buff);
142 }
143
144
145 // I would prefer to give a tag number instead of an explicit token
146 // here, but it is not possible because Buffer::readLyXformat2 uses
147 // explicit tokens (JMarc) 
148 LString LyXLex::getLongString(LString const &endtoken)
149 {
150         LString str, prefix;
151         bool firstline = true;
152
153         while (IsOK()) {
154                 if (!EatLine())
155                         // blank line in the file being read
156                         continue;
157                 
158                 LString const token = GetString().strip().frontStrip();
159                 
160                 lyxerr.debug("LongString: `"+GetString()+'\'', Error::LEX_PARSER);
161
162                 // We do a case independent comparison, like search_kw
163                 // does.
164                 if (strcasecmp(token.c_str(), endtoken.c_str()) != 0) {
165                         LString tmpstr = GetString();
166                         if (firstline) {
167                                 int i = 0;
168                                 while(i < tmpstr.length()
169                                       && tmpstr[i] == ' ') {
170                                         i++;
171                                         prefix += ' ';
172                                 }
173                                 firstline = false;
174                                 lyxerr.debug("Prefix = `"+prefix+'\'',
175                                               Error::LEX_PARSER); 
176                         } 
177
178                         if (!prefix.empty() 
179                             && tmpstr.prefixIs(prefix.c_str())) {
180                                 tmpstr.substring(prefix.length(), 
181                                                  tmpstr.length()-1);
182                         }
183                         str += tmpstr + '\n';
184                 }
185                 else // token == endtoken
186                         break;
187         }
188         if (!IsOK())
189                 printError("Long string not ended by `" + endtoken + '\'');
190
191         return str;
192 }
193
194
195 bool LyXLex::GetBool()
196 {
197    if (strcmp(buff, "true") == 0)
198         return true;
199    else if (strcmp(buff, "false") != 0)
200         printError("Bad boolean `$$Token'. Use \"false\" or \"true\"");
201    return false;
202 }
203
204
205 bool LyXLex::EatLine()
206 {
207         int i=0;
208         int c = '\0'; // getc() returns an int
209
210         while (!feof(file) && c!='\n' && i!=(LEX_MAX_BUFF-1)) {
211                 c = getc(file);
212                 if (c != '\r')
213                         buff[i++] = c;
214         }
215         if (i==(LEX_MAX_BUFF-1) && c !='\n') {
216                 printError("Line too long");
217                 c = '\n'; // Pretend we had an end of line
218                 lineno--; // but don't increase line counter (netto effect)
219                 i++; // and preserve last character read.
220         }
221         if (c=='\n') {
222                 lineno++;
223                 buff[--i] = '\0'; // i can never be 0 here, so no danger
224                 status = LEX_DATA;
225                 return true;
226         } else {
227                 buff[i] = '\0';
228                 return false;
229         }
230 }
231
232
233 int LyXLex::search_kw(char const * const tag) const
234 {
235         int m, k=0 , l= 0, r=no_items;
236
237         while (l < r) {
238                 m = (l+r)/2;
239
240                 if (lyxerr.debugging(Error::LEX_PARSER)) {
241                         LString my_l;
242                         my_l+="LyXLex::search_kw: elem " ;
243                         my_l+= m; 
244                         my_l+=" tag "; 
245                         my_l+=table[m].tag;
246                         my_l+=" search tag ";
247                         my_l+= tag;
248                         lyxerr.print(my_l);
249                 }
250
251                 if (table[m].tag)
252                         k = strcasecmp(table[m].tag, tag);
253                 if (k==0)
254                         return table[m].code;
255                 else
256                         if (k<0) l = m+1; else r = m;
257         }
258         return -1;
259 }
260
261
262 bool LyXLex::next(bool esc)
263 {
264
265         if (!esc) {
266                 int c; // getc() returns an int
267                 int i;
268                 
269                 
270                 status = 0;
271                 while (!feof(file) && !status) { 
272                         c = getc(file);
273                         if (c=='#') {
274                                 // Read rest of line (fast :-)
275                                 fgets(buff, sizeof(buff), file);
276                                 lineno++;
277                                 continue;
278                         }
279                         
280                         if (c=='\"') {
281                                 i = -1;
282                                 do {
283                                         c = getc(file);
284                                         if (c != '\r')
285                                                 buff[++i] = c;
286                                 } while (c!='\"' && c!='\n' && !feof(file) &&
287                                          i!=(LEX_MAX_BUFF-2));
288                                 
289                                 if (i==(LEX_MAX_BUFF-2)) {
290                                         printError("Line too long");
291                                         c = '\"'; // Pretend we got a "
292                                         i++;
293                                 }
294                                 
295                                 if (c!='\"') {
296                                         printError("Missing quote");
297                                         if (c=='\n')
298                                                 lineno++;
299                                 }
300                                 
301                                 buff[i] = '\0';
302                                 status = LEX_DATA;
303                                 break; 
304                         }
305                         
306                         if (c==',')
307                                 continue;              /* Skip ','s */
308                         
309                         if (c > ' ' && !feof(file))  {
310                                 i = 0;
311                                 do {
312                                         buff[i++] = c;
313                                         c = getc(file);
314                                 } while (c > ' ' && c != ',' && !feof(file) &&
315                                          (i != LEX_MAX_BUFF-1) );
316                                 if (i == LEX_MAX_BUFF-1) {
317                                         printError("Line too long");
318                                 }
319                                 buff[i] = '\0';
320                                 status = LEX_TOKEN;
321                         }
322                         
323                         if (c=='\r' && !feof(file)) {
324                                 // The Windows support has lead to the
325                                 // possibility of "\r\n" at the end of
326                                 // a line.  This will stop LyX choking
327                                 // when it expected to find a '\n'
328                                 c = getc(file);
329                         }
330
331                         if (c=='\n')
332                                 lineno++;
333                         
334                 }
335                 if (status) return true;
336                 
337                 status = (feof(file)) ? LEX_FEOF: LEX_UNDEF;
338                 buff[0] = '\0';
339                 return false;
340         } else {
341                 int c; // getc() returns an int
342                 int i;
343                 
344                 
345                 status = 0;
346                 while (!feof(file) && !status) { 
347                         c = getc(file);
348
349                         // skip ','s
350                         if (c==',') continue;
351                         
352                         if (c=='\\') {
353                                 // escape
354                                 i = 0;
355                                 do {
356                                         if (c == '\\') {
357                                                 // escape the next char
358                                                 c = getc(file);
359                                         }
360                                         buff[i++] = c;
361                                         c = getc(file);
362                                 } while (c > ' ' && c != ',' && !feof(file) &&
363                                          (i != LEX_MAX_BUFF-1) );
364                                 if (i == LEX_MAX_BUFF-1) {
365                                         printError("Line too long");
366                                 }
367                                 buff[i] = '\0';
368                                 status = LEX_TOKEN;
369                                 continue;
370                         }
371                         
372                         if (c=='#') {
373                                 // Read rest of line (fast :-)
374                                 fgets(buff, sizeof(buff), file);
375                                 lineno++;
376                                 continue;
377                         }
378
379                         // string
380                         if (c=='\"') {
381                                 i = -1;
382                                 bool escaped = false;
383                                 do {
384                                         escaped = false;
385                                         c = getc(file);
386                                         if (c == '\r') continue;
387                                         if (c == '\\') {
388                                                 // escape the next char
389                                                 c = getc(file);
390                                                 escaped = true;
391                                         }
392                                         buff[++i] = c;
393                                 
394                                         if (!escaped && c == '\"') break;
395                                 } while (c!='\n' && !feof(file) &&
396                                          i!=(LEX_MAX_BUFF-2));
397                                 
398                                 if (i==(LEX_MAX_BUFF-2)) {
399                                         printError("Line too long");
400                                         c = '\"'; // Pretend we got a "
401                                         i++;
402                                 }
403                                 
404                                 if (c!='\"') {
405                                         printError("Missing quote");
406                                         if (c=='\n')
407                                                 lineno++;
408                                 }
409                                 
410                                 buff[i] = '\0';
411                                 status = LEX_DATA;
412                                 break; 
413                         }
414                         
415                         if (c > ' ' && !feof(file))  {
416                                 i = 0;
417                                 do {
418                                         if (c == '\\') {
419                                                 // escape the next char
420                                                 c = getc(file);
421                                                 //escaped = true;
422                                         }
423                                         buff[i++] = c;
424                                         c = getc(file);
425                                 } while (c > ' ' && c != ',' && !feof(file) &&
426                                          (i != LEX_MAX_BUFF-1) );
427                                 if (i == LEX_MAX_BUFF-1) {
428                                         printError("Line too long");
429                                 }
430                                 buff[i] = '\0';
431                                 status = LEX_TOKEN;
432                         }
433
434                         // new line
435                         if (c=='\n')
436                                 lineno++;
437                 }
438                 
439                 if (status) return true;
440                 
441                 status = (feof(file)) ? LEX_FEOF: LEX_UNDEF;
442                 buff[0] = '\0';
443                 return false;   
444         }
445 }
446
447
448 bool LyXLex::nextToken()
449 {
450         int c; // getc() returns an int
451         int i;
452         
453         status = 0;
454         while (!feof(file) && !status) { 
455                 c = getc(file);
456            
457                 if (c >= ' ' && !feof(file))  {
458                         i = 0;
459                         if (c == '\\') { // first char == '\\'
460                                 do {
461                                         buff[i++] = c;
462                                         c = getc(file);
463                                 } while (c > ' ' && c != '\\' && !feof(file) &&
464                                          i != (LEX_MAX_BUFF-1));
465                         } else {
466                                 do {
467                                         buff[i++] = c;
468                                         c = getc(file);
469                                 } while (c >= ' ' && c != '\\' && !feof(file)
470                                          && i != (LEX_MAX_BUFF-1));
471                         }
472
473                         if (i == (LEX_MAX_BUFF-1)) {
474                                 printError("Line too long");
475                         }
476
477                         if (c == '\\') ungetc(c,file); // put it back
478                         buff[i] = '\0';
479                         status = LEX_TOKEN;
480                 }
481                   
482                 if (c=='\n')
483                         lineno++;
484         
485         }
486         if (status)  return true;
487         
488         status = (feof(file)) ? LEX_FEOF: LEX_UNDEF;
489         buff[0] = '\0';
490         return false;
491 }
492
493
494 int LyXLex::FindToken(char const* string[])
495 {  
496    int i = -1;
497    
498    if (next()) {
499       if (strcmp(buff, "default")) {
500          for (i=0; string[i][0] && strcmp(string[i], buff); i++);
501          if (!string[i][0]) {
502             printError("Unknown argument `$$Token'");
503             i = -1;
504          }
505       }  
506    } else
507      printError("file ended while scanning string token");
508    return i;
509 }
510
511
512 int LyXLex::CheckToken(char const* string[], int print_error)
513 {  
514    int i = -1;
515    
516    if (strcmp(buff, "default")) {
517        for (i=0; string[i][0] && strcmp(string[i], buff); i++);
518        if (!string[i][0]) {
519            if (print_error)
520                printError("Unknown argument `$$Token'");
521            i = -1;
522        }
523    }
524    return i;
525 }