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
Scanner(const char * file)12 Scanner::Scanner(const char* file)
13 {
14 fCurrentFile = new PPDFile(file);
15 }
16
~Scanner()17 Scanner::~Scanner()
18 {
19 while (fCurrentFile != NULL) {
20 PPDFile* file = fCurrentFile->GetPreviousFile();
21 delete fCurrentFile;
22 fCurrentFile = file;
23 }
24 }
25
InitCheck()26 status_t Scanner::InitCheck()
27 {
28 return fCurrentFile->InitCheck();
29 }
30
Warning(const char * message)31 void Scanner::Warning(const char* message)
32 {
33 fWarnings << "Line " << GetPosition().y <<
34 ", column " << GetPosition().x << ": " << message;
35 }
36
GetWarningMessage()37 const char* Scanner::GetWarningMessage()
38 {
39 return fWarnings.String();
40 }
41
HasWarning()42 bool Scanner::HasWarning()
43 {
44 return fWarnings.Length() > 0;
45 }
46
Error(const char * message)47 void Scanner::Error(const char* message)
48 {
49 fLastError = GetFileName();
50 fLastError << " (line " << GetPosition().y <<
51 ", column " << GetPosition().x << "): " <<
52 message;
53 }
54
GetErrorMessage()55 const char* Scanner::GetErrorMessage()
56 {
57 return fLastError.String();
58 }
59
HasError()60 bool Scanner::HasError()
61 {
62 const char* message = GetErrorMessage();
63 return message != NULL && strcmp(message, "") != 0;
64 }
65
Scan(bool (cond)(int ch))66 BString* 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
getHexadecimalDigit(int ch)76 static 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
ScanHexadecimalSubstring(BString * literal)89 bool 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
ScanLiteral(bool quotedValue,int separator)132 BString* 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
GetCurrentChar()155 int Scanner::GetCurrentChar()
156 {
157 if (fCurrentFile != NULL) {
158 return fCurrentFile->GetCurrentChar();
159 }
160
161 return -1;
162 }
163
NextChar()164 void 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
GetPosition()176 Position Scanner::GetPosition()
177 {
178 if (fCurrentFile != NULL) {
179 return fCurrentFile->GetPosition();
180 }
181 return Position();
182 }
183
GetFileName()184 const char* Scanner::GetFileName()
185 {
186 if (fCurrentFile != NULL) {
187 return fCurrentFile->GetFileName();
188 }
189 return NULL;
190 }
191
Include(const char * file)192 bool 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