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