This commit was manufactured by cvs2svn to create tag
[lyx.git] / src / lyxlex.C
blob517bad5e00c492d9e7ca3ab632372edd2a7dc50c
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.
7 #include <config.h>
9 #include <cstdlib>
11 #ifdef __GNUG__
12 #pragma implementation "lyxlex.h"
13 #endif
15 #include "lyxlex.h"
16 #include "debug.h"
17 #include "support/filetools.h"
19 LyXLex::LyXLex(keyword_item * tab, int num)
20         : table(tab), no_items(num)
22         file = 0;
23         owns_file = false;
24         status = 0;
25         pushed = 0;
29 void LyXLex::pushTable(keyword_item * tab, int num)
31         pushed_table * tmppu = new pushed_table;
32         tmppu->next = pushed;
33         tmppu->table_elem = table;
34         tmppu->table_siz = no_items;
35         pushed = tmppu;
36         table = tab;
37         no_items = num;
41 void LyXLex::popTable()
43         if (pushed == 0)
44                 lyxerr << "LyXLex error: nothing to pop!" << endl;
46         pushed_table * tmp;
47         tmp = pushed;
48         table = tmp->table_elem;
49         no_items = tmp->table_siz;
50         tmp->table_elem = 0;
51         pushed = tmp->next;
52         delete tmp;
56 void LyXLex::printTable()
58         lyxerr << "\nNumber of tags: " << no_items << endl;
59         for(int i=0; i<no_items; i++)
60                 lyxerr << "table[" << i
61                        << "]:  tag: `" << table[i].tag
62                        << "'  code:" << table[i].code << endl;
63         lyxerr << endl;
67 void LyXLex::printError(string const & message)
69         string tmpmsg = subst(message, "$$Token", GetString());
70         lyxerr << "LyX: " << tmpmsg << " [around line " << lineno
71                << " of file " << MakeDisplayPath(name) << ']' << endl;
75 bool LyXLex::setFile(string const & filename)
77         if (file) 
78                 lyxerr << "Error in LyXLex::setFile: file already set." <<endl;
79         file = fopen(filename.c_str(), "r");
80         name = filename;
81         owns_file = true;
82         lineno = 0;
83         return (file ? true : false);
87 void LyXLex::setFile(FILE * f)
89         if (file) 
90                 lyxerr << "Error in LyXLex::setFile: file already set." << endl;
91         file = f;
92         owns_file = false;
93         lineno = 0; // this is bogus if the file already has been read from
97 int LyXLex::lex()
99         //NOTE: possible bug.
100    if (next() && status==LEX_TOKEN)
101        return search_kw(buff);
102    else
103        return status;
107 int LyXLex::GetInteger()
109    if (buff[0]>' ')   
110        return atoi(buff);
111    else {
112         printError("Bad integer `$$Token'");
113         return -1;
114    }
118 float LyXLex::GetFloat()
120    if (buff[0]>' ')   
121        return (float)strtod(buff, (char**)0);
122    else {
123         printError("Bad float `$$Token'");
124         return -1;
125    }
129 string LyXLex::GetString() const
131         return string(buff);
135 // I would prefer to give a tag number instead of an explicit token
136 // here, but it is not possible because Buffer::readLyXformat2 uses
137 // explicit tokens (JMarc) 
138 string LyXLex::getLongString(string const & endtoken)
140         string str, prefix;
141         bool firstline = true;
143         while (IsOK()) {
144                 if (!EatLine())
145                         // blank line in the file being read
146                         continue;
147                 
148                 string const token = frontStrip(strip(GetString()), " \t");
149                 
150                 lyxerr[Debug::PARSER] << "LongString: `"
151                                       << GetString() << '\'' << endl;
153                 // We do a case independent comparison, like search_kw
154                 // does.
155                 if (compare_no_case(token, endtoken) != 0) {
156                         string tmpstr = GetString();
157                         if (firstline) {
158                                 unsigned int i = 0;
159                                 while(i < tmpstr.length()
160                                       && tmpstr[i] == ' ') {
161                                         ++i;
162                                         prefix += ' ';
163                                 }
164                                 firstline = false;
165                                 lyxerr[Debug::PARSER] << "Prefix = `" << prefix
166                                                       << '\'' << endl;
167                         } 
169                         if (!prefix.empty() 
170                             && prefixIs(tmpstr, prefix.c_str())) {
171                                 tmpstr.erase(0, prefix.length() - 1);
172                         }
173                         str += tmpstr + '\n';
174                 }
175                 else // token == endtoken
176                         break;
177         }
178         if (!IsOK())
179                 printError("Long string not ended by `" + endtoken + '\'');
181         return str;
185 bool LyXLex::GetBool()
187    if (compare(buff, "true") == 0)
188         return true;
189    else if (compare(buff, "false") != 0)
190         printError("Bad boolean `$$Token'. Use \"false\" or \"true\"");
191    return false;
195 bool LyXLex::EatLine()
197         int i=0;
198         int c = '\0'; // getc() returns an int
200         while (!feof(file) && c!='\n' && i!=(LEX_MAX_BUFF-1)) {
201                 c = getc(file);
202                 if (c != '\r')
203                         buff[i++] = c;
204         }
205         if (i==(LEX_MAX_BUFF-1) && c !='\n') {
206                 printError("Line too long");
207                 c = '\n'; // Pretend we had an end of line
208                 --lineno; // but don't increase line counter (netto effect)
209                 ++i; // and preserve last character read.
210         }
211         if (c=='\n') {
212                 ++lineno;
213                 buff[--i] = '\0'; // i can never be 0 here, so no danger
214                 status = LEX_DATA;
215                 return true;
216         } else {
217                 buff[i] = '\0';
218                 return false;
219         }
223 int LyXLex::search_kw(char const * const tag) const
225         int m, k=0 , l= 0, r=no_items;
227         while (l < r) {
228                 m = (l+r)/2;
230                 if (lyxerr.debugging(Debug::PARSER)) {
231                         lyxerr << "LyXLex::search_kw: elem " << m
232                                << " tag " << table[m].tag
233                                << " search tag " << tag
234                                << endl;
235                 }
237                 if (table[m].tag)
238                         k = compare_no_case(table[m].tag, tag);
239                 if (k==0)
240                         return table[m].code;
241                 else
242                         if (k<0) l = m+1; else r = m;
243         }
244         return -1;
248 bool LyXLex::next(bool esc)
251         if (!esc) {
252                 int c; // getc() returns an int
253                 //int i;
254                 
255                 
256                 status = 0;
257                 while (!feof(file) && !status) { 
258                         c = getc(file);
259                         if (c=='#') {
260                                 // Read rest of line (fast :-)
261                                 fgets(buff, sizeof(buff), file);
262                                 ++lineno;
263                                 continue;
264                         }
265                         
266                         if (c=='\"') {
267                                 int i = -1;
268                                 do {
269                                         c = getc(file);
270                                         if (c != '\r')
271                                                 buff[++i] = c;
272                                 } while (c!='\"' && c!='\n' && !feof(file) &&
273                                          i!=(LEX_MAX_BUFF-2));
274                                 
275                                 if (i==(LEX_MAX_BUFF-2)) {
276                                         printError("Line too long");
277                                         c = '\"'; // Pretend we got a "
278                                         ++i;
279                                 }
280                                 
281                                 if (c!='\"') {
282                                         printError("Missing quote");
283                                         if (c=='\n')
284                                                 ++lineno;
285                                 }
286                                 
287                                 buff[i] = '\0';
288                                 status = LEX_DATA;
289                                 break; 
290                         }
291                         
292                         if (c==',')
293                                 continue;              /* Skip ','s */
294                         
295                         if (c > ' ' && !feof(file))  {
296                                 int i = 0;
297                                 do {
298                                         buff[i++] = c;
299                                         c = getc(file);
300                                 } while (c > ' ' && c != ',' && !feof(file) &&
301                                          (i != LEX_MAX_BUFF-1) );
302                                 if (i == LEX_MAX_BUFF-1) {
303                                         printError("Line too long");
304                                 }
305                                 buff[i] = '\0';
306                                 status = LEX_TOKEN;
307                         }
308                         
309                         if (c== '\r' && !feof(file)) {
310                                 // The Windows support has lead to the
311                                 // possibility of "\r\n" at the end of
312                                 // a line.  This will stop LyX choking
313                                 // when it expected to find a '\n'
314                                 c = getc(file);
315                         }
317                         if (c=='\n')
318                                 ++lineno;
319                         
320                 }
321                 if (status) return true;
322                 
323                 status = (feof(file)) ? LEX_FEOF: LEX_UNDEF;
324                 buff[0] = '\0';
325                 return false;
326         } else {
327                 int c; // getc() returns an int
328                 //int i;
329                 
330                 
331                 status = 0;
332                 while (!feof(file) && !status) { 
333                         c = getc(file);
335                         // skip ','s
336                         if (c==',') continue;
337                         
338                         if (c=='\\') {
339                                 // escape
340                                 int i = 0;
341                                 do {
342                                         if (c == '\\') {
343                                                 // escape the next char
344                                                 c = getc(file);
345                                         }
346                                         buff[i++] = c;
347                                         c = getc(file);
348                                 } while (c > ' ' && c != ',' && !feof(file) &&
349                                          (i != LEX_MAX_BUFF-1) );
350                                 if (i == LEX_MAX_BUFF-1) {
351                                         printError("Line too long");
352                                 }
353                                 buff[i] = '\0';
354                                 status = LEX_TOKEN;
355                                 continue;
356                         }
357                         
358                         if (c=='#') {
359                                 // Read rest of line (fast :-)
360                                 fgets(buff, sizeof(buff), file);
361                                 ++lineno;
362                                 continue;
363                         }
365                         // string
366                         if (c=='\"') {
367                                 int i = -1;
368                                 bool escaped = false;
369                                 do {
370                                         escaped = false;
371                                         c = getc(file);
372                                         if (c == '\r') continue;
373                                         if (c == '\\') {
374                                                 // escape the next char
375                                                 c = getc(file);
376                                                 escaped = true;
377                                         }
378                                         buff[++i] = c;
379                                 
380                                         if (!escaped && c == '\"') break;
381                                 } while (c!='\n' && !feof(file) &&
382                                          i!=(LEX_MAX_BUFF-2));
383                                 
384                                 if (i==(LEX_MAX_BUFF-2)) {
385                                         printError("Line too long");
386                                         c = '\"'; // Pretend we got a "
387                                         ++i;
388                                 }
389                                 
390                                 if (c!='\"') {
391                                         printError("Missing quote");
392                                         if (c=='\n')
393                                                 ++lineno;
394                                 }
395                                 
396                                 buff[i] = '\0';
397                                 status = LEX_DATA;
398                                 break; 
399                         }
400                         
401                         if (c > ' ' && !feof(file))  {
402                                 int i = 0;
403                                 do {
404                                         if (c == '\\') {
405                                                 // escape the next char
406                                                 c = getc(file);
407                                                 //escaped = true;
408                                         }
409                                         buff[i++] = c;
410                                         c = getc(file);
411                                 } while (c > ' ' && c != ',' && !feof(file) &&
412                                          (i != LEX_MAX_BUFF-1) );
413                                 if (i == LEX_MAX_BUFF-1) {
414                                         printError("Line too long");
415                                 }
416                                 buff[i] = '\0';
417                                 status = LEX_TOKEN;
418                         }
420                         // new line
421                         if (c=='\n')
422                                 ++lineno;
423                 }
424                 
425                 if (status) return true;
426                 
427                 status = (feof(file)) ? LEX_FEOF: LEX_UNDEF;
428                 buff[0] = '\0';
429                 return false;   
430         }
434 bool LyXLex::nextToken()
436         int c; // getc() returns an int
437         int i;
438         
439         status = 0;
440         while (!feof(file) && !status) { 
441                 c = getc(file);
442            
443                 if (c >= ' ' && !feof(file))  {
444                         i = 0;
445                         if (c == '\\') { // first char == '\\'
446                                 do {
447                                         buff[i++] = c;
448                                         c = getc(file);
449                                 } while (c > ' ' && c != '\\' && !feof(file) &&
450                                          i != (LEX_MAX_BUFF-1));
451                         } else {
452                                 do {
453                                         buff[i++] = c;
454                                         c = getc(file);
455                                 } while (c >= ' ' && c != '\\' && !feof(file)
456                                          && i != (LEX_MAX_BUFF-1));
457                         }
459                         if (i == (LEX_MAX_BUFF-1)) {
460                                 printError("Line too long");
461                         }
463                         if (c == '\\') ungetc(c,file); // put it back
464                         buff[i] = '\0';
465                         status = LEX_TOKEN;
466                 }
467                   
468                 if (c=='\n')
469                         ++lineno;
470         
471         }
472         if (status)  return true;
473         
474         status = (feof(file)) ? LEX_FEOF: LEX_UNDEF;
475         buff[0] = '\0';
476         return false;
480 int LyXLex::FindToken(char const * str[])
481 {  
482    int i = -1;
483    
484    if (next()) {
485       if (compare(buff, "default")) {
486          for (i = 0; str[i][0] && compare(str[i], buff); ++i);
487          if (!str[i][0]) {
488             printError("Unknown argument `$$Token'");
489             i = -1;
490          }
491       }  
492    } else
493      printError("file ended while scanning string token");
494    return i;
498 int LyXLex::CheckToken(char const * str[], int print_error)
499 {  
500    int i = -1;
501    
502    if (compare(buff, "default")) {
503        for (i = 0; str[i][0] && compare(str[i], buff); i++);
504        if (!str[i][0]) {
505            if (print_error)
506                printError("Unknown argument `$$Token'");
507            i = -1;
508        }
509    }
510    return i;