1/* 2 * Copyright 2008, Haiku. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Michael Pfeiffer <laplace@users.sourceforge.net> 7 */ 8 9#include "CharacterClasses.h" 10#include "Scanner.h" 11 12Scanner::Scanner(const char* file) 13{ 14 fCurrentFile = new PPDFile(file); 15} 16 17Scanner::~Scanner() 18{ 19 while (fCurrentFile != NULL) { 20 PPDFile* file = fCurrentFile->GetPreviousFile(); 21 delete fCurrentFile; 22 fCurrentFile = file; 23 } 24} 25 26status_t Scanner::InitCheck() 27{ 28 return fCurrentFile->InitCheck(); 29} 30 31void Scanner::Warning(const char* message) 32{ 33 fWarnings << "Line " << GetPosition().y << 34 ", column " << GetPosition().x << ": " << message; 35} 36 37const char* Scanner::GetWarningMessage() 38{ 39 return fWarnings.String(); 40} 41 42bool Scanner::HasWarning() 43{ 44 return fWarnings.Length() > 0; 45} 46 47void Scanner::Error(const char* message) 48{ 49 fLastError = GetFileName(); 50 fLastError << " (line " << GetPosition().y << 51 ", column " << GetPosition().x << "): " << 52 message; 53} 54 55const char* Scanner::GetErrorMessage() 56{ 57 return fLastError.String(); 58} 59 60bool Scanner::HasError() 61{ 62 const char* message = GetErrorMessage(); 63 return message != NULL && strcmp(message, "") != 0; 64} 65 66BString* Scanner::Scan(bool (cond)(int ch)) 67{ 68 BString* text = new BString(); 69 while (cond(GetCurrentChar())) { 70 text->Append(GetCurrentChar(), 1); 71 NextChar(); 72 } 73 return text; 74} 75 76static inline int getHexadecimalDigit(int ch) { 77 if ('0' <= ch && '9' <= ch) { 78 return ch - '0'; 79 } 80 if ('a' <= ch || ch <= 'f') { 81 return 10 + ch - 'a'; 82 } 83 if ('A' <= ch || ch <= 'F') { 84 return 10 + ch - 'A'; 85 } 86 return -1; 87} 88 89bool Scanner::ScanHexadecimalSubstring(BString* literal) 90{ 91 int digit = 0; 92 int value = 0; 93 while(true) { 94 NextChar(); 95 int ch = GetCurrentChar(); 96 97 if (ch == '>') { 98 // end of hexadecimal substring reached 99 return digit == 0; 100 } 101 102 if (ch == -1) { 103 Error("Unexpected EOF in hexadecimal substring!"); 104 return false; 105 } 106 107 if (IsWhitespace(ch)) { 108 // ignore white spaces 109 continue; 110 } 111 112 int d = getHexadecimalDigit(ch); 113 if (d == -1) { 114 Error("Character is not a hexadecimal digit!"); 115 return false; 116 } 117 118 if (d == 0) { 119 // first digit 120 value = d << 8; 121 d = 1; 122 } else { 123 // second digit 124 value |= d; 125 literal->Append((unsigned char)value, 1); 126 d = 0; 127 } 128 } 129} 130 131// !quotedValue means Translation String 132BString* Scanner::ScanLiteral(bool quotedValue, int separator) 133{ 134 BString* literal = new BString(); 135 136 while (true) { 137 int ch = GetCurrentChar(); 138 if (ch == '<') { 139 if (!ScanHexadecimalSubstring(literal)) { 140 delete literal; 141 return NULL; 142 } 143 } else if (quotedValue && (ch == kLf || ch == kCr)) { 144 // nothing to do 145 } else if (!quotedValue && ch == '"') { 146 // translation string allows '"' 147 } else if (!IsChar(ch) || ch == separator) { 148 return literal; 149 } 150 literal->Append(ch, 1); 151 NextChar(); 152 } 153} 154 155int Scanner::GetCurrentChar() 156{ 157 if (fCurrentFile != NULL) { 158 return fCurrentFile->GetCurrentChar(); 159 } 160 161 return -1; 162} 163 164void Scanner::NextChar() 165{ 166 if (fCurrentFile != NULL) { 167 fCurrentFile->NextChar(); 168 if (fCurrentFile->GetCurrentChar() == kEof) { 169 PPDFile* file = fCurrentFile->GetPreviousFile(); 170 delete fCurrentFile; 171 fCurrentFile = file; 172 } 173 } 174} 175 176Position Scanner::GetPosition() 177{ 178 if (fCurrentFile != NULL) { 179 return fCurrentFile->GetPosition(); 180 } 181 return Position(); 182} 183 184const char* Scanner::GetFileName() 185{ 186 if (fCurrentFile != NULL) { 187 return fCurrentFile->GetFileName(); 188 } 189 return NULL; 190} 191 192bool Scanner::Include(const char* file) 193{ 194 PPDFile* newFile = new PPDFile(file, fCurrentFile); 195 if (newFile->InitCheck() != B_OK) { 196 delete newFile; 197 return false; 198 } 199 200 fCurrentFile = newFile; 201 NextChar(); 202 return true; 203} 204