1 /*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is the Sablotron XSLT Processor.
13 *
14 * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15 * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16 * Ginger Alliance Ltd. All Rights Reserved.
17 *
18 * Contributor(s):
19 *
20 * Alternatively, the contents of this file may be used under the
21 * terms of the GNU General Public License Version 2 or later (the
22 * "GPL"), in which case the provisions of the GPL are applicable
23 * instead of those above. If you wish to allow use of your
24 * version of this file only under the terms of the GPL and not to
25 * allow others to use your version of this file under the MPL,
26 * indicate your decision by deleting the provisions above and
27 * replace them with the notice and other provisions required by
28 * the GPL. If you do not delete the provisions above, a recipient
29 * may use your version of this file under either the MPL or the
30 * GPL.
31 */
32
33 #include <time.h>
34 #include "base.h"
35 #include "situa.h"
36 #include "verts.h"
37 #include "encoding.h"
38 #include "tree.h"
39 #include "domprovider.h"
40 #include "platform.h"
41
42 // GP: clean
43
operator =(const SituaInfo & other)44 SituaInfo& SituaInfo::operator=(const SituaInfo& other)
45 {
46 pending = other.pending;
47 currV = other.currV;
48 currFile = other.currFile;
49 currMsg = other.currMsg;
50 currLine = other.currLine;
51 SDOMExceptionCode = other.SDOMExceptionCode;
52 return *this;
53 }
54
clear()55 void SituaInfo::clear()
56 {
57 pending = E_OK;
58 currV = NULL;
59 currFile.empty();
60 currMsg.empty();
61 currLine = 0;
62 SDOMExceptionCode = 0;
63 }
64
65
66 /*****************************************************************
67
68 S i t u a t i o n
69
70 *****************************************************************/
71
Situation()72 Situation::Situation()
73 {
74 theRecoder = new Recoder;
75 clear();
76 proc = NULL;
77 logfile = errwfile = NULL;
78 openDefaultFiles();
79 flags = 0;
80
81 // define this symbol to disable adding the meta tag
82 #ifdef SABLOT_DISABLE_ADDING_META
83 flags |= SAB_DISABLE_ADDING_META;
84 #endif
85
86 //define thos symbol to avoid errors in document() when not found
87 #ifdef SABLOT_DISABLE_DOC_ERRORS
88 flags |= SAB_IGNORE_DOC_NOT_FOUND;
89 #endif
90
91 sxpOptions = 0;
92 theProvider = new DOMProviderUniversal();
93 }
94
~Situation()95 Situation::~Situation()
96 {
97 theRecoder -> clear(*this);
98 cdelete(theRecoder);
99 if (logfile) stdclose(logfile);
100 if (errwfile) stdclose(errwfile);
101 cdelete(theProvider);
102 }
103
recoder() const104 Recoder& Situation::recoder() const
105 {
106 return *theRecoder;
107 }
108
setFlag(SablotFlag f)109 void Situation::setFlag(SablotFlag f)
110 {
111 flags |= f;
112 }
113
hasFlag(SablotFlag f)114 Bool Situation::hasFlag(SablotFlag f)
115 {
116 return flags & f;
117 }
118
resetFlag(SablotFlag f)119 void Situation::resetFlag(SablotFlag f)
120 {
121 flags &= ~f;
122 }
123
setFlags(int f)124 void Situation::setFlags(int f)
125 {
126 flags = f;
127 }
128
getFlags()129 int Situation::getFlags()
130 {
131 return flags;
132 }
133
timeStr()134 Str Situation::timeStr()
135 {
136 time_t currtime;
137 time(&currtime);
138 return asctime(localtime(&currtime));
139 }
140
setCurrV(Vertex * v)141 void Situation::setCurrV(Vertex *v)
142 {
143 info.currV = v;
144 if (v)
145 {
146 info.currLine = v -> lineno;
147 }
148 }
149
setCurrVDoc(Vertex * v)150 void Situation::setCurrVDoc(Vertex *v)
151 {
152 setCurrV(v);
153 if (v)
154 {
155 info.currFile = v -> getSubtreeInfo() -> getBaseURI();
156 }
157 }
158
setCurrLine(int lno)159 void Situation::setCurrLine(int lno)
160 {
161 info.currLine = lno;
162 }
163
setCurrSAXLine(int lno)164 void Situation::setCurrSAXLine(int lno)
165 {
166 info.currSAXLine = lno;
167 }
168
getCurrSAXLine()169 int Situation::getCurrSAXLine()
170 {
171 return info.currSAXLine;
172 }
173
setCurrFile(const Str & fname)174 void Situation::setCurrFile(const Str& fname)
175 {
176 info.currFile = fname;
177 };
178
openDefaultFiles()179 eFlag Situation::openDefaultFiles()
180 {
181 E( msgOutputFile((char *) "/__stderr", NULL) );
182 return OK;
183 }
184
closeFiles()185 eFlag Situation::closeFiles()
186 {
187 if (logfile)
188 stdclose(logfile);
189 logfile = NULL;
190 if (errwfile)
191 stdclose(errwfile);
192 errwfile = NULL;
193 return OK;
194 }
195
eraseLog(char * newLogFile)196 eFlag Situation::eraseLog(char *newLogFile)
197 {
198 if (logfile)
199 stdclose(logfile);
200 logfile = NULL;
201 if (newLogFile)
202 {
203 if (!(logfile = stdopen(newLogFile,"w")))
204 Err1(this, E_FILE_OPEN, newLogFile);
205 setlinebuf__(logfile);
206 }
207 return OK;
208 }
209
msgOutputFile(char * _errwfn,char * _logfn)210 eFlag Situation::msgOutputFile(char *_errwfn, char *_logfn)
211 {
212 E( closeFiles() );
213 if (_logfn)
214 {
215 if (!(logfile = stdopen(_logfn,"a")))
216 Err1(this, E_FILE_OPEN, _logfn);
217 setlinebuf__(logfile);
218 }
219 if (_errwfn)
220 {
221 if (!(errwfile = stdopen(_errwfn,"w")))
222 Err1(this, E_FILE_OPEN, _errwfn);
223 setlinebuf__(errwfile);
224 }
225 return OK;
226 }
227
228 // constructMsgFields
229 // called to transform a List of Str's to a NULL-terminated array
230 // of char*'s. Stores just POINTERS so make sure the strings don't change.
231 // Dispose of the return value using delete[].
232
constructMsgFields(PList<DStr * > & strings)233 char** constructMsgFields(PList<DStr*>& strings)
234 {
235 int len = strings.number();
236 char **p = new char*[len + 1];
237 p[len] = NULL;
238 int i;
239 for (i = 0; i < len; i++)
240 p[i] = (char*)(*strings[i]);
241 return p;
242 }
243
244 #define __numargs 3
safeFormat(char * dest,int size,const char * format,const char * arg1,const char * arg2,const char * arg3)245 void safeFormat(char* dest, int size, const char* format,
246 const char* arg1, const char* arg2, const char* arg3)
247 {
248 int l[__numargs];
249 char *b[__numargs];
250 const char* a[__numargs];
251 int i;
252 int total = 0, num = 0;
253
254 a[0] = arg1;
255 a[1] = arg2;
256 a[2] = arg3;
257 memset(l, 0, 3 * sizeof(int));
258 memset(b, 0, 3 * sizeof(char*));
259 num = 0;
260
261 //read lengths
262 for (i = 0; i < __numargs; i++)
263 if (a[i]) { l[i] = strlen(a[i]); num++; total += l[i];}
264
265 //replace too long buffers
266 for (i = 0; i < __numargs; i++)
267 {
268 if (l[i] > size / __numargs)
269 {
270 b[i] = new char[size / __numargs + 1];
271 strcpy(b[i], "...");
272 strcpy(b[i] + 3, a[i] + (l[i] - size / __numargs + 3));
273 }
274 }
275 //format
276 sprintf(dest, format,
277 b[0] ? b[0] : a[0],
278 b[1] ? b[1] : a[1],
279 b[2] ? b[2] : a[2]);
280
281 //delete allocated
282 for (i = 0; i < __numargs; i++)
283 if (b[i]) delete[] b[i];
284 }
285
286 #define __MSG_BUFSIZE 512
generateMessage(MsgType type,MsgCode code,const Str & arg1,const Str & arg2,Str & theMessage)287 void Situation::generateMessage(MsgType type, MsgCode code,
288 const Str& arg1, const Str& arg2,
289 Str& theMessage)
290 {
291 char buf[__MSG_BUFSIZE];
292 PList<DStr*> out;
293 void *messengerUD = NULL;
294 MessageHandler *messenger = NULL;
295 if (proc)
296 messenger = proc -> getMessageHandler(&messengerUD);
297 if (messenger)
298 {
299 out.append(new DStr("msgtype:"));
300 switch(type) {
301 case MT_ERROR: *(out[0]) += "error"; break;
302 case MT_WARN: *(out[0]) += "warning"; break;
303 case MT_LOG: *(out[0]) += "log"; break;
304 };
305 }
306 if (type != MT_LOG)
307 {
308 sprintf(buf,"code:%d",code);
309 out.append(new DStr(buf));
310 }
311 if (messenger)
312 out.append(new DStr("module:Sablotron"));
313 if (!info.currFile.isEmpty())
314 {
315 //check for buffer overflow
316 //sprintf(buf,"URI:%s",(char*)(info.currFile));
317 safeFormat(buf, __MSG_BUFSIZE - 5,
318 "URI:%s",
319 (char*)(info.currFile),
320 NULL, NULL);
321 out.append(new DStr(buf));
322 }
323 if (info.currLine && type != MT_LOG)
324 {
325 sprintf(buf,"line:%d",info.currLine);
326 out.append(new DStr(buf));
327 }
328 if (info.currV && type != MT_LOG)
329 {
330 //may overflow for extremly (~500 bytes) long tag names
331 DStr nameStr;
332 info.currV -> speak(nameStr, SM_NAME);
333 //sprintf(buf,"node:%s%s'%s'",
334 // vertexTypeNames[info.currV -> vt & VT_BASE],
335 // (info.currV -> vt == VT_VERTEX ? "" : " "),
336 // (char *) nameStr);
337 safeFormat(buf, __MSG_BUFSIZE - 10,
338 "node:%s%s'%s'",
339 vertexTypeNames[info.currV -> vt & VT_BASE],
340 (info.currV -> vt == VT_VERTEX ? "" : " "),
341 (char *) nameStr);
342 out.append(new DStr(buf));
343 }
344
345 SabMsg *p = GetMessage(code);
346 if (p -> text[0])
347 {
348 //check buffer overflow
349 DStr msgText = messenger ? (char*)"msg:" : (char*)"";
350 //sprintf(buf,p -> text,(char*)(Str&)arg1,(char*)(Str&)arg2);
351 safeFormat(buf, __MSG_BUFSIZE - strlen(p -> text),
352 p -> text,
353 (char*)(Str&)arg1,
354 (char*)(Str&)arg2,
355 NULL);
356 msgText += buf;
357 out.append(new DStr(msgText));
358 }
359
360 if (messenger && !(flags & SAB_NO_ERROR_REPORTING))
361 {
362 // construct the message fields
363 char **msgFields = constructMsgFields(out);
364 MH_ERROR externalCode =
365 messenger -> makeCode(messengerUD, proc,
366 type == MT_ERROR ? 1 : 0,
367 MH_FACILITY_SABLOTRON, (unsigned short)code);
368
369 // FIXME: casting to MH_LEVEL -- necessary?
370 switch(type) {
371 case MT_ERROR:
372 {
373 messenger -> error(messengerUD, proc,
374 externalCode, (MH_LEVEL) MH_LEVEL_ERROR,
375 msgFields);
376 }; break;
377 case MT_WARN:
378 {
379 messenger -> log(messengerUD, proc,
380 externalCode, (MH_LEVEL) MH_LEVEL_WARN,
381 msgFields);
382 }; break;
383 case MT_LOG:
384 {
385 messenger -> log(messengerUD, proc,
386 externalCode, (MH_LEVEL) MH_LEVEL_INFO,
387 msgFields);
388 }; break;
389 }
390 delete[] msgFields;
391 // note that the strings pointed at by msgFields members are deleted
392 // upon destruction of 'out'
393 };
394
395 // in any case, construct the message and return it in theMessage
396 // construct the message
397 DStr fullout;
398 if (type != MT_LOG)
399 {
400 fullout = GetMessage((MsgCode)(MSG_ERROR + type)) -> text;
401 fullout += " ";
402 int outnum = out.number();
403 for (int j = 0; j < outnum; j++)
404 {
405 if (j < outnum - 1)
406 fullout += "[";
407 fullout += *out[j];
408 if (j < outnum - 1)
409 fullout += "] ";
410 if (j == outnum-2)
411 fullout += "\n ";
412 }
413 }
414 else
415 {
416 if (out.number())
417 fullout = *(out.last());
418 }
419
420 if (!messenger && !(type == MT_ERROR && (flags & SAB_NO_ERROR_REPORTING)))
421 {
422 // display the message yourself
423 FILE *thefile = (type == MT_LOG ? logfile : errwfile);
424 if (thefile)
425 fprintf(thefile,"%s\n",(char*) fullout);
426 }
427
428 theMessage = fullout;
429
430 // dispose of the temp string array
431 out.freeall(FALSE);
432 }
433
message(MsgType type,MsgCode code,const Str & arg1,const Str & arg2)434 void Situation::message(MsgType type, MsgCode code,
435 const Str& arg1, const Str& arg2)
436 {
437 if (code == E2_SDOM)
438 {
439 infoDOM = info;
440 info.clear();
441 }
442 else
443 {
444 if (type == MT_ERROR)
445 infoDOM.clear();
446 }
447
448 Str temp;
449 if (type == MT_ERROR)
450 info.pending = code;
451 generateMessage(type, code, arg1, arg2, temp);
452 info.currMsg = temp;
453
454 // only log errors and warnings if we are using our own reporter
455 if ((type == MT_ERROR || type == MT_WARN) &&
456 (!proc || !proc -> getMessageHandler(NULL)))
457 generateMessage(MT_LOG, code, arg1, arg2, temp);
458
459 #ifdef SABLOT_ABORT_ON_ERROR
460 if (type == MT_ERROR) abort();
461 #endif
462
463 }
464
report(Situation * sit,MsgType type,MsgCode code,const Str & str1,const Str & str2)465 void Situation::report(Situation *sit, MsgType type, MsgCode code, const Str &str1, const Str &str2)
466 {
467 message(type, code, str1, str2);
468 }
469
470
isError()471 Bool Situation::isError()
472 {
473 return (Bool) (info.pending != E_OK);
474 };
475
getError() const476 int Situation::getError() const
477 {
478 return info.pending;
479 }
480
clearError()481 void Situation::clearError()
482 {
483 info.pending = E_OK;
484 info.currMsg.empty();
485 }
486
clear()487 void Situation::clear()
488 {
489 info.clear();
490 infoDOM.clear();
491 }
492
setSDOMExceptionCode(int code)493 void Situation::setSDOMExceptionCode(int code)
494 {
495 info.SDOMExceptionCode = code;
496 }
497
getSDOMExceptionCode() const498 int Situation::getSDOMExceptionCode() const
499 {
500 // the exception code was moved to infoDOM by message()
501 return infoDOM.SDOMExceptionCode;
502 }
503
getSDOMExceptionExtra(MsgCode & theCode,Str & theMessage,Str & theDocument,int & theLine) const504 void Situation::getSDOMExceptionExtra(MsgCode& theCode,
505 Str& theMessage, Str& theDocument, int& theLine) const
506 {
507 theCode = infoDOM.pending;
508 theMessage = infoDOM.currMsg;
509 theDocument = infoDOM.currFile;
510 theLine = infoDOM.currLine;
511 }
512
swapProcessor(void * & proc_)513 void Situation::swapProcessor(void *& proc_)
514 {
515 void *temp = proc;
516 proc = (Processor*) proc_;
517 proc_ = temp;
518 }
519
findBaseURI(const Str & unmappedBase)520 const Str& Situation::findBaseURI(const Str& unmappedBase)
521 {
522 if (proc)
523 return proc -> findBaseURI(*this, unmappedBase);
524 else
525 return unmappedBase;
526 }
527
setSXPOptions(unsigned long options)528 void Situation::setSXPOptions(unsigned long options)
529 {
530 theProvider -> setOptions(options);
531 }
532
getSXPOptions()533 unsigned long Situation::getSXPOptions()
534 {
535 return theProvider -> getOptions();
536 }
537
setSXPMaskBit(int mask)538 void Situation::setSXPMaskBit(int mask)
539 {
540 theProvider -> setMaskBit(mask);
541 }
542
getSXPMaskBit()543 int Situation::getSXPMaskBit()
544 {
545 return theProvider -> getMaskBit();
546 }
547
setDOMProvider(DOMHandler * domh,void * udata)548 void Situation::setDOMProvider(DOMHandler *domh, void* udata)
549 {
550 theProvider -> setExtProvider(domh, udata);
551 }
552
553