Inheritance diagram for XMLCannedInput:
Public Methods | |
XMLCannedInput (const string &filename, istream &is) | |
Initializes the XMLTokenizer member variable with the given input stream. | |
bool | execute_one_event (Drawing *) |
Executes one event from the XML input; most work is done here. | |
Private Attributes | |
XMLTokenizer | t |
This is a subclass of CannedInput that reads from XML files; this is the concrete class used by CannedInput to accomplish its tasks.
|
Initializes the XMLTokenizer member variable with the given input stream. If the next token is XMLTokenizer::END, the input stream is empty and an exception is thrown. If this test is passed, it checks to make sure the file starts with an tag before returning. If the file doesn't start with an tag, an exception is thrown.
00055 : CannedInput(filename), t(is) 00056 { 00057 // If EOF immediately, stop. 00058 if (t.next_token() == XMLTokenizer::END) 00059 throw runtime_error("file is empty"); 00060 00061 if (t.curr_token != XMLTokenizer::OPEN || 00062 t.curr_name != "input" || 00063 t.next_token() != XMLTokenizer::CLOSE) { 00064 throw runtime_error("Canned input file does not start with <input> tag."); 00065 } 00066 } |
|
Executes one event from the XML input; most work is done here. In a loop, it reads the next token from the XMLTokenizer, and then takes one of several actions. If the token is one of END, ERROR, TEXT, or a value not covered by other cases, an error is printed to cerr and the function returns false. If the next token is ETAG, it checks to make sure it matches the opening tag, then returns false. If the token is OPEN, then it checks the contents of the command against the possible commands. It executes the command using Drawing member functions on the parameter it's passed, then sets a timer in drawing's canvas so that the next event will be read. Implements CannedInput.
00083 { 00084 for (;;) { 00085 switch (t.next_token()) { 00086 case XMLTokenizer::END: 00087 cerr << "Input file ended before </input> tag" << endl; 00088 return false; 00089 case XMLTokenizer::ERROR: 00090 cerr << filename << ":" << t.get_line_number() << ":" 00091 << t.curr_text; 00092 cerr << " Stopped reading input file." << endl; 00093 return false; 00094 case XMLTokenizer::OPEN: { 00095 string command = t.curr_name; 00096 // do various things depending on command 00097 if (command == "toolbar:click" || command == "click") { 00098 if (t.next_token() != XMLTokenizer::ATTR || 00099 t.curr_name != "position") { 00100 cerr << filename << ":" << t.get_line_number() << ":" 00101 << (t.curr_token == XMLTokenizer::ERROR ? t.curr_text : 00102 string("Expected position attribute")) 00103 << ". Stopped reading input file." << endl; 00104 return false; 00105 } 00106 Position p; 00107 if (Utilities::from_string(t.curr_text,p)) { 00108 drawing->click(p, command == "toolbar:click"); 00109 cout << " clicked " << Utilities::to_string(p) 00110 << (command == "toolbar:click" ? " in tool bar." : ".") 00111 << endl; 00112 drawing->get_canvas()->StartTimer(10); 00113 } else { 00114 cerr << filename << ":" << t.get_line_number() << ":" 00115 << "Malformed position" 00116 << ". Stopped reading input file." << endl; 00117 return false; 00118 } 00119 } else if (command == "sleep") { 00120 if (t.next_token() != XMLTokenizer::ATTR || t.curr_name != "seconds") { 00121 cerr << filename << ":" << t.get_line_number() << ":" 00122 << (t.curr_token == XMLTokenizer::ERROR ? t.curr_text : 00123 string("Expected seconds attribute")) 00124 << ". Stopped reading input file." << endl; 00125 return false; 00126 } 00127 int sec; 00128 if (Utilities::from_string(t.curr_text,sec) && sec > 0) { 00129 drawing->get_canvas()->StartTimer(sec*1000); 00130 } else { 00131 cerr << filename << ":" << t.get_line_number() << ":" 00132 << "Seconds must be a positive integer" 00133 << ". Stopped reading input file." << endl; 00134 return false; 00135 } 00136 } else if (command == "echo") { 00137 if (t.next_token() != XMLTokenizer::ATTR || t.curr_name != "text") { 00138 cerr << filename << ":" << t.get_line_number() << ":" 00139 << (t.curr_token == XMLTokenizer::ERROR ? t.curr_text : 00140 string("Expected 'text' attribute")) 00141 << ". Stopped reading input file." << endl; 00142 return false; 00143 } 00144 cout << t.curr_text << endl; 00145 drawing->get_canvas()->StartTimer(10); 00146 } else if (command == "quit") { 00147 Terminate(); 00148 } else { 00149 cerr << filename << ":" << t.get_line_number() << ":" 00150 << "Unknown command " << command 00151 << ". Stopped reading input file." << endl; 00152 return false; 00153 } 00154 // permit /> or ></command> 00155 if (t.next_token() != XMLTokenizer::ECLOSE && 00156 (t.curr_token != XMLTokenizer::CLOSE || 00157 t.next_token() != XMLTokenizer::ETAG || 00158 t.curr_name != command)) { 00159 // We can't return false here, because 00160 // the time has already been set. Instead, 00161 // we leave an ERROR token in the input: 00162 if (t.curr_token != XMLTokenizer::ERROR) { 00163 t.curr_text = "Expected </" + command + ">"; 00164 t.curr_token = XMLTokenizer::ERROR; 00165 } 00166 t.save_token(); 00167 } 00168 return true; 00169 } 00170 case XMLTokenizer::ETAG: 00171 if (t.curr_name != "input") { 00172 cerr << filename << ":" << t.get_line_number() << ":" 00173 << "<input> tag matched with </" << t.curr_name << "> end tag." 00174 << " Stopped reading input file." << endl; 00175 return false; 00176 } 00177 if (t.next_token() != XMLTokenizer::END) { 00178 cerr << filename << ":" << t.get_line_number() << ":" 00179 << "Extra text after </input> tag." << endl; 00180 } 00181 return false; 00182 case XMLTokenizer::TEXT: 00183 cerr << filename << ":" << t.get_line_number() << ":" 00184 << "Stray text in input file. Stopped reading input file." << endl; 00185 return false; 00186 default: 00187 cerr << filename << ":" << t.get_line_number() << ":" 00188 << "Internal error 1-" << t.curr_token 00189 << ". Stopped reading input file." << endl; 00190 return false; 00191 } 00192 } 00193 } |
|
|