X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Flyxlex.C;h=c35246550517c7163083d821cdefe58523871399;hb=91a2ea274e9c27f571a3cd4798d2e8ecc1b982a7;hp=f036360a67669472561ff581c5ff8a9d95bc2d70;hpb=0eccdd1c3613e5170deb77b22174dd0afde833e9;p=lyx.git diff --git a/src/lyxlex.C b/src/lyxlex.C index f036360a67..c352465505 100644 --- a/src/lyxlex.C +++ b/src/lyxlex.C @@ -2,10 +2,11 @@ // It can be used for simple syntax parsers, like lyxrc, // texclass and others to come. [asierra30/03/96] // -// (C) 1996 Lyx Team. +// Copyright 1996 Lyx Team. #include +#include #include #ifdef __GNUG__ @@ -13,16 +14,49 @@ #endif #include "lyxlex.h" -#include "error.h" +#include "debug.h" #include "support/filetools.h" +#include "support/lyxalgo.h" + +using std::ios; +using std::lower_bound; +using std::sort; + + +// namespace { +struct compare_tags { + // used by lower_bound + inline + int operator()(keyword_item const & a, char const * const tag) const { + return compare_no_case(a.tag, tag) < 0; + } + // used by sorted and sort + inline + int operator()(keyword_item const & a, keyword_item const & b) const { + return compare_no_case(a.tag, b.tag) < 0; + } +}; +// } // end of anon namespace + LyXLex::LyXLex(keyword_item * tab, int num) - : table(tab), no_items(num) + : is(&fb__), table(tab), no_items(num) { - file = 0; - owns_file = false; - status = 0; + status = 0; pushed = 0; + // Check if the table is sorted and if not, sort it. + if (table && !sorted(table, table + no_items, compare_tags())) { + lyxerr << "The table passed to LyXLex is not sorted!!\n" + << "Tell the developers to fix it!" << endl; + // We sort it anyway to avoid problems. + lyxerr << "\nUnsorted:\n"; + printTable(lyxerr); + + sort(table, table + no_items, + compare_tags()); + lyxerr << "\nSorted:\n"; + printTable(lyxerr); + } } @@ -35,13 +69,25 @@ void LyXLex::pushTable(keyword_item * tab, int num) pushed = tmppu; table = tab; no_items = num; + // Check if the table is sorted and if not, sort it. + if (table && !sorted(table, table + no_items, compare_tags())) { + lyxerr << "The table passed to LyXLex is not sorted!!\n" + << "Tell the developers to fix it!" << endl; + // We sort it anyway to avoid problems. + lyxerr << "\nUnsorted:\n"; + printTable(lyxerr); + + sort(table, table + no_items, compare_tags()); + lyxerr << "\nSorted:\n"; + printTable(lyxerr); + } } void LyXLex::popTable() { if (pushed == 0) - lyxerr.print("LyXLex error: nothing to pop!"); + lyxerr << "LyXLex error: nothing to pop!" << endl; pushed_table * tmp; tmp = pushed; @@ -53,72 +99,73 @@ void LyXLex::popTable() } -void LyXLex::printTable() +void LyXLex::printTable(ostream & os) { - lyxerr.print(string("\nNumber of tags: ") + tostr(no_items)); - for(int i=0; iin_avail()) + lyxerr << "Error in LyXLex::setStream: " + "file or stream already set." << endl; + is.rdbuf(i.rdbuf()); + lineno = 0; } int LyXLex::lex() { //NOTE: possible bug. - if (next() && status==LEX_TOKEN) - return search_kw(buff); - else - return status; + if (next() && status == LEX_TOKEN) + return search_kw(buff); + else + return status; } -int LyXLex::GetInteger() +int LyXLex::GetInteger() const { - if (buff[0]>' ') - return atoi(buff); - else { - printError("Bad integer `$$Token'"); - return -1; - } + if (buff[0] > ' ') + return atoi(buff); + else { + printError("Bad integer `$$Token'"); + return -1; + } } -float LyXLex::GetFloat() +float LyXLex::GetFloat() const { - if (buff[0]>' ') - return (float)strtod(buff, (char**)0); + if (buff[0] > ' ') + return atof(buff); else { printError("Bad float `$$Token'"); return -1; @@ -147,7 +194,8 @@ string LyXLex::getLongString(string const & endtoken) string const token = frontStrip(strip(GetString()), " \t"); - lyxerr.debug("LongString: `"+GetString()+'\'', Error::LEX_PARSER); + lyxerr[Debug::PARSER] << "LongString: `" + << GetString() << '\'' << endl; // We do a case independent comparison, like search_kw // does. @@ -161,8 +209,8 @@ string LyXLex::getLongString(string const & endtoken) prefix += ' '; } firstline = false; - lyxerr.debug("Prefix = `"+prefix+'\'', - Error::LEX_PARSER); + lyxerr[Debug::PARSER] << "Prefix = `" << prefix + << '\'' << endl; } if (!prefix.empty() @@ -181,33 +229,36 @@ string LyXLex::getLongString(string const & endtoken) } -bool LyXLex::GetBool() +bool LyXLex::GetBool() const { - if (compare(buff, "true") == 0) - return true; - else if (compare(buff, "false") != 0) - printError("Bad boolean `$$Token'. Use \"false\" or \"true\""); - return false; + if (compare(buff, "true") == 0) + return true; + else if (compare(buff, "false") != 0) + printError("Bad boolean `$$Token'. Use \"false\" or \"true\""); + return false; } bool LyXLex::EatLine() { - int i=0; - int c = '\0'; // getc() returns an int - - while (!feof(file) && c!='\n' && i!=(LEX_MAX_BUFF-1)) { - c = getc(file); + int i = 0; + unsigned char c = '\0'; + char cc = 0; + while(is && c != '\n' && i != (LEX_MAX_BUFF - 1)) { + is.get(cc); + c = cc; + lyxerr[Debug::LYXLEX] << "LyXLex::EatLine read char: `" + << c << "'" << endl; if (c != '\r') buff[i++] = c; } - if (i==(LEX_MAX_BUFF-1) && c !='\n') { - printError("Line too long"); + if (i == (LEX_MAX_BUFF - 1) && c != '\n') { + printError("Line too long"); c = '\n'; // Pretend we had an end of line --lineno; // but don't increase line counter (netto effect) ++i; // and preserve last character read. } - if (c=='\n') { + if (c == '\n') { ++lineno; buff[--i] = '\0'; // i can never be 0 here, so no danger status = LEX_DATA; @@ -221,69 +272,51 @@ bool LyXLex::EatLine() int LyXLex::search_kw(char const * const tag) const { - int m, k=0 , l= 0, r=no_items; - - while (l < r) { - m = (l+r)/2; - - if (lyxerr.debugging(Error::LEX_PARSER)) { - string my_l; - my_l+="LyXLex::search_kw: elem " ; - my_l+= m; - my_l+=" tag "; - my_l+=table[m].tag; - my_l+=" search tag "; - my_l+= tag; - lyxerr.print(my_l); - } - - if (table[m].tag) - k = compare_no_case(table[m].tag, tag); - if (k==0) - return table[m].code; - else - if (k<0) l = m+1; else r = m; - } - return -1; + keyword_item * res = + lower_bound(table, table + no_items, tag, compare_tags()); + if (res != table + no_items && !compare_no_case(res->tag, tag)) + return res->code; + return LEX_UNDEF; } bool LyXLex::next(bool esc) { - if (!esc) { - int c; // getc() returns an int - int i; - - + unsigned char c = 0; // getc() returns an int + char cc = 0; status = 0; - while (!feof(file) && !status) { - c = getc(file); - if (c=='#') { + while (is && !status) { + is.get(cc); + c = cc; + if (c == '#') { // Read rest of line (fast :-) - fgets(buff, sizeof(buff), file); + is.getline(buff, sizeof(buff)); + lyxerr[Debug::LYXLEX] << "Comment read: `" << c + << buff << "'" << endl; ++lineno; continue; } - if (c=='\"') { - i = -1; + if (c == '\"') { + int i = -1; do { - c = getc(file); + is.get(cc); + c = cc; if (c != '\r') buff[++i] = c; - } while (c!='\"' && c!='\n' && !feof(file) && - i!=(LEX_MAX_BUFF-2)); + } while (c != '\"' && c != '\n' && is && + i != (LEX_MAX_BUFF - 2)); - if (i==(LEX_MAX_BUFF-2)) { + if (i == (LEX_MAX_BUFF - 2)) { printError("Line too long"); c = '\"'; // Pretend we got a " ++i; } - if (c!='\"') { + if (c != '\"') { printError("Missing quote"); - if (c=='\n') + if (c == '\n') ++lineno; } @@ -292,65 +325,73 @@ bool LyXLex::next(bool esc) break; } - if (c==',') + if (c == ',') continue; /* Skip ','s */ - - if (c > ' ' && !feof(file)) { - i = 0; + + // using relational operators with chars other + // than == and != is not safe. And if it is done + // the type _have_ to be unsigned. It usually a + // lot better to use the functions from cctype + if (c > ' ' && is) { + int i = 0; do { buff[i++] = c; - c = getc(file); - } while (c > ' ' && c != ',' && !feof(file) && - (i != LEX_MAX_BUFF-1) ); - if (i == LEX_MAX_BUFF-1) { + is.get(cc); + c = cc; + } while (c > ' ' && c != ',' && is + && (i != LEX_MAX_BUFF - 1) ); + if (i == LEX_MAX_BUFF - 1) { printError("Line too long"); } buff[i] = '\0'; status = LEX_TOKEN; } - if (c== '\r' && !feof(file)) { + if (c == '\r' && is) { // The Windows support has lead to the // possibility of "\r\n" at the end of // a line. This will stop LyX choking // when it expected to find a '\n' - c = getc(file); + is.get(cc); + c = cc; } - if (c=='\n') + if (c == '\n') ++lineno; } if (status) return true; - status = (feof(file)) ? LEX_FEOF: LEX_UNDEF; + status = is.eof() ? LEX_FEOF: LEX_UNDEF; buff[0] = '\0'; return false; } else { - int c; // getc() returns an int - int i; - + unsigned char c = 0; // getc() returns an int + char cc = 0; status = 0; - while (!feof(file) && !status) { - c = getc(file); + while (is && !status) { + is.get(cc); + c = cc; // skip ','s - if (c==',') continue; + if (c == ',') continue; - if (c=='\\') { + if (c == '\\') { // escape - i = 0; + int i = 0; do { if (c == '\\') { // escape the next char - c = getc(file); + is.get(cc); + c = cc; } buff[i++] = c; - c = getc(file); - } while (c > ' ' && c != ',' && !feof(file) && - (i != LEX_MAX_BUFF-1) ); - if (i == LEX_MAX_BUFF-1) { + is.get(cc); + c = cc; + } while (c > ' ' && c != ',' && is + && (i != LEX_MAX_BUFF - 1) ); + if (i == LEX_MAX_BUFF - 1) { printError("Line too long"); } buff[i] = '\0'; @@ -358,41 +399,45 @@ bool LyXLex::next(bool esc) continue; } - if (c=='#') { + if (c == '#') { // Read rest of line (fast :-) - fgets(buff, sizeof(buff), file); + is.getline(buff, sizeof(buff)); + lyxerr[Debug::LYXLEX] << "Comment read: `" << c + << buff << "'" << endl; ++lineno; continue; } // string - if (c=='\"') { - i = -1; + if (c == '\"') { + int i = -1; bool escaped = false; do { escaped = false; - c = getc(file); + is.get(cc); + c = cc; if (c == '\r') continue; if (c == '\\') { // escape the next char - c = getc(file); + is.get(cc); + c = cc; escaped = true; } buff[++i] = c; if (!escaped && c == '\"') break; - } while (c!='\n' && !feof(file) && - i!=(LEX_MAX_BUFF-2)); + } while (c != '\n' && is && + i != (LEX_MAX_BUFF - 2)); - if (i==(LEX_MAX_BUFF-2)) { + if (i == (LEX_MAX_BUFF - 2)) { printError("Line too long"); c = '\"'; // Pretend we got a " ++i; } - if (c!='\"') { + if (c != '\"') { printError("Missing quote"); - if (c=='\n') + if (c == '\n') ++lineno; } @@ -401,80 +446,82 @@ bool LyXLex::next(bool esc) break; } - if (c > ' ' && !feof(file)) { - i = 0; + if (c > ' ' && is) { + int i = 0; do { if (c == '\\') { // escape the next char - c = getc(file); + is.get(cc); + c = cc; //escaped = true; } buff[i++] = c; - c = getc(file); - } while (c > ' ' && c != ',' && !feof(file) && - (i != LEX_MAX_BUFF-1) ); + is.get(cc); + c = cc; + } while (c > ' ' && c != ',' && is + && (i != LEX_MAX_BUFF-1) ); if (i == LEX_MAX_BUFF-1) { printError("Line too long"); } buff[i] = '\0'; status = LEX_TOKEN; } - // new line - if (c=='\n') + if (c == '\n') ++lineno; } if (status) return true; - status = (feof(file)) ? LEX_FEOF: LEX_UNDEF; + status = is.eof() ? LEX_FEOF : LEX_UNDEF; buff[0] = '\0'; - return false; + return false; } } bool LyXLex::nextToken() { - int c; // getc() returns an int - int i; - status = 0; - while (!feof(file) && !status) { - c = getc(file); - - if (c >= ' ' && !feof(file)) { - i = 0; + while (is && !status) { + unsigned char c = 0; + char cc = 0; + is.get(cc); + c = cc; + if (c >= ' ' && is) { + int i = 0; if (c == '\\') { // first char == '\\' do { buff[i++] = c; - c = getc(file); - } while (c > ' ' && c != '\\' && !feof(file) && - i != (LEX_MAX_BUFF-1)); + is.get(cc); + c = cc; + } while (c > ' ' && c != '\\' && is + && i != (LEX_MAX_BUFF-1)); } else { do { buff[i++] = c; - c = getc(file); - } while (c >= ' ' && c != '\\' && !feof(file) + is.get(cc); + c = cc; + } while (c >= ' ' && c != '\\' && is && i != (LEX_MAX_BUFF-1)); } - if (i == (LEX_MAX_BUFF-1)) { + if (i == (LEX_MAX_BUFF - 1)) { printError("Line too long"); } - if (c == '\\') ungetc(c,file); // put it back + if (c == '\\') is.putback(c); // put it back buff[i] = '\0'; status = LEX_TOKEN; } - if (c=='\n') + if (c == '\n') ++lineno; } if (status) return true; - status = (feof(file)) ? LEX_FEOF: LEX_UNDEF; + status = is.eof() ? LEX_FEOF: LEX_UNDEF; buff[0] = '\0'; return false; } @@ -503,7 +550,7 @@ int LyXLex::CheckToken(char const * str[], int print_error) int i = -1; if (compare(buff, "default")) { - for (i = 0; str[i][0] && compare(str[i], buff); i++); + for (i = 0; str[i][0] && compare(str[i], buff); ++i); if (!str[i][0]) { if (print_error) printError("Unknown argument `$$Token'");