1 /***********************************************************************/
2 /* Open Visualization Data Explorer                                    */
3 /* (C) Copyright IBM Corp. 1989,1999                                   */
4 /* ALL RIGHTS RESERVED                                                 */
5 /* This code licensed under the                                        */
6 /*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
7 /***********************************************************************/
8 
9 #include <dxconfig.h>
10 
11 
12 #include <dx/dx.h>
13 #include <fcntl.h>
14 #include "internals.h"
15 
16 #if defined(HAVE_UNISTD_H)
17 #include <unistd.h>
18 #endif
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #if defined(HAVE_SYS_ERRNO_H)
25 #include <sys/errno.h>
26 #endif
27 
28 #if defined(HAVE_ERRNO_H)
29 #include <errno.h>
30 #endif
31 
32 #if defined(HAVE_IO_H)
33 #include <io.h>
34 #endif
35 
36 /*
37  * DXMessage system state.
38  */
39 
40 static struct state {		/* message system state */
41 
42     int error_exit;		/* 2=exit, 1=print, 0=nothing, on error */
43     int trace;			/* enable/disable messages */
44     int enabled[256];		/* enabled debug classes */
45 
46     int nmessages;		/* number of messages */
47     int alloc;			/* allocate size of messages array */
48     char **messages;		/* the messages */
49     char *buf;			/* the buffer for the messages */
50     int translate;              /* use the messages file if available */
51 
52 } *state;
53 
54 
55 Error
_dxf_initmessages(void)56 _dxf_initmessages(void)
57 {
58     char *file, *s, name[100];
59     int fd, mno, size;
60 
61     if (state)
62 	return OK;
63 
64 #if pgcc
65     atexit(DXqflush);
66 #endif
67 
68     /* initialize state vector */
69     state = (struct state *) DXAllocateZero(sizeof(struct state));
70     if (!state)
71 	return ERROR;
72     state->error_exit = 1;
73     state->trace = 1;
74     state->translate = 1;
75 #ifdef DEBUGGED	/* Turn this off for production code, it confuses users */
76     DXEnableDebug("M", 1);
77 #endif
78     if (!_dxf_initmemqueue())
79 	return ERROR;
80 
81     /* read and parse message file */
82     file = getenv("DXMESSAGES");
83     if (file)
84 	sprintf(name, "%s", file);
85     else {
86 	char *root = getenv("DXEXECROOT");
87 	if (!root) root = getenv("DXROOT");
88 	if (!root) root = "/usr/local/dx";
89 	sprintf(name, "%s/lib/messages", root);
90     }
91     fd = open(name, O_RDONLY);
92     if (fd<0) {
93 	DXWarning("message file %s could not be opened", name);
94 	state->translate = 0;
95 	return OK;
96     }
97     size = lseek(fd, 0, 2);
98     lseek(fd, 0, 0);
99     state->buf = DXAllocate(size+1);
100     if (!state->buf)
101 	return ERROR;
102     if (read(fd, state->buf, size) < size) {
103 	DXWarning("message file %s could not be read", name);
104 	state->translate = 0;
105 	close(fd);
106 	return OK;
107     }
108     close(fd);
109     state->buf[size] = '\0';
110     s = state->buf;
111     while (*s!='#' && *s)
112 	s++;
113     while (*s) {
114 	*s = '\0';
115 	s++;
116 	mno = atoi(s);
117 	if (mno >= state->alloc) {
118 	    int n = 2*mno + 1;
119 	    char **m = (char **) DXReAllocate((Pointer)state->messages,
120 					   n * sizeof(char*));
121 	    if (!m)
122 		return ERROR;
123 	    state->messages = m;
124 	    state->alloc = n;
125 	}
126 	while ('0'<=*s && *s<='9')
127 	    s++;
128 	while (*s==' ' || *s=='\t' || *s=='\n')
129 	    s++;
130 	state->messages[mno] = s;
131 	if (mno > state->nmessages)
132 	    state->nmessages = mno;
133 	while (*s!='#' && *s) {
134 	    if (*s=='\n')
135 		*s = ' ';
136 	    s++;
137 	}
138     }
139     return OK;
140 }
141 
142 static char *
translate(char * s,int * messfile)143 translate(char *s, int *messfile)
144 {
145     int i;
146     if (!state || !s || *s!='#' || !state->translate) {
147 	*messfile = 0;
148 	return s;
149     }
150     i = atoi(s+1);
151     if (0<=i && i<=state->nmessages && state->messages[i]) {
152 	*messfile = 1;
153 	return state->messages[i];
154     } else {
155 	*messfile = 0;
156 	return s;
157     }
158 }
159 
160 
161 static void
aqmessage(char * who,char * message,...)162 aqmessage(char *who, char *message, ...)
163 {
164     va_list arg;
165     va_start(arg,message);
166     DXqmessage(who, message, arg);
167     va_end(arg);
168 }
169 
170 
171 
172 /*
173  * Error handling.
174  */
175 
176 static ErrorCode _ErrorCode = ERROR_NONE;
177 static char _ErrorMessage[2000] = "";
178 
179 void
DXSetErrorExit(int t)180 DXSetErrorExit(int t)
181 {
182     if (!state && !DXinitdx())
183 	return;
184     state->error_exit = t;
185 }
186 
DXGetErrorExit()187 int DXGetErrorExit()
188 {
189     if(state)
190         return(state->error_exit);
191     else return(0);
192 }
193 
194 /* mark the messages which don't come from the messages file, so we
195  * can eventually get them all out of the code.  debug version only.
196  */
197 #define TAG "(!file) "
198 #define TAGLEN 8
199 
200 Error
DXSetError(ErrorCode code,char * message,...)201 DXSetError(ErrorCode code, char *message, ...)
202 {
203     va_list arg;
204     int usedmessfile;
205     int offset = 0;
206 
207     message = translate(message, &usedmessfile);
208 
209     /* error code */
210     _ErrorCode = code;
211 
212     /* message */
213 #if DEBUGGED
214     if (!usedmessfile) {
215         strcpy(_ErrorMessage, TAG);
216 	offset = TAGLEN;
217     }
218 #endif
219     va_start(arg,message);
220     vsprintf(_ErrorMessage+offset, message, arg);
221     va_end(arg);
222 
223     /* action */
224     if (!state || state->error_exit == 1)
225 	DXPrintError(NULL);
226     else if (state->error_exit >= 2)
227 	DXErrorExit(NULL);
228 
229     return ERROR;
230 }
231 
232 
233 Error
DXAddMessage(char * message,...)234 DXAddMessage(char *message, ...)
235 {
236     char buf[2000];
237     va_list arg;
238     int usedmessfile;
239 
240     message = translate(message, &usedmessfile);
241 
242     /* message */
243     va_start(arg,message);
244     vsprintf(buf, message, arg);
245     va_end(arg);
246     strcat(_ErrorMessage, " / ");
247     strcat(_ErrorMessage, buf);
248 
249     /* action */
250     if (!state || state->error_exit)
251 	DXMessage("    (%s)", buf);
252 
253     return ERROR;
254 }
255 
256 
257 ErrorCode
DXGetError(void)258 DXGetError(void)
259 {
260     return _ErrorCode;
261 }
262 
263 
264 char *
DXGetErrorMessage(void)265 DXGetErrorMessage(void)
266 {
267     return _ErrorMessage;
268 }
269 
270 
271 void
DXResetError(void)272 DXResetError(void)
273 {
274 #if !defined(HAVE__ERRNO)
275     errno = 0;
276 #endif
277     _ErrorCode = ERROR_NONE;
278     _ErrorMessage[0] = 0;
279 }
280 
281 
282 void
DXPrintError(char * s)283 DXPrintError(char *s)
284 {
285     char *msg, *errnomsg;
286     static int been_here = 0;
287     static char *messages[(int)ERROR_MAX];
288 
289     if (!been_here) {
290 	messages[(int)ERROR_NONE] = "Error code not set";
291 	messages[(int)ERROR_INTERNAL] = "Internal error";
292 	messages[(int)ERROR_UNEXPECTED] = "Unexpected error";
293 	messages[(int)ERROR_ASSERTION] = "Assertion failed";
294 	messages[(int)ERROR_NOT_IMPLEMENTED] = "Operation not implemented";
295 	messages[(int)ERROR_NO_MEMORY] = "Out of memory";
296 	messages[(int)ERROR_BAD_CLASS] = "Bad class";
297 	messages[(int)ERROR_BAD_TYPE] = "Bad type";
298 	messages[(int)ERROR_NO_CAMERA] = "No camera";
299 	messages[(int)ERROR_MISSING_DATA] = "Missing data";
300 	messages[(int)ERROR_DATA_INVALID] = "Invalid data";
301 	messages[(int)ERROR_BAD_PARAMETER] = "Bad parameter";
302 	been_here = 1;
303     }
304 
305     if ((int)_ErrorCode<0
306 	|| (int)_ErrorCode>=ERROR_MAX
307 	|| !messages[(int)_ErrorCode])
308 	msg = "Bad error code";
309     else
310 	msg = messages[(int)_ErrorCode];
311 
312     /* print error message */
313     if (_ErrorCode==ERROR_NONE && errno) {
314     	errnomsg = (char *) strerror(errno); /* sys_errlist[errno]; */
315 	if (s)
316 	    aqmessage("ERROR", "%s: %s", s, errnomsg);
317 	else
318 	    aqmessage("ERROR", "%s", errnomsg);
319     } else {
320 	if (s)
321 	    aqmessage("ERROR", "%s: %s: %s", s, msg, _ErrorMessage);
322 	else
323 	    aqmessage("ERROR", "%s: %s", msg, _ErrorMessage);
324     }
325 }
326 
327 void
DXErrorExit(char * s)328 DXErrorExit(char *s)
329 {
330     DXPrintError(s);
331     exit(DXGetError());
332 }
333 
334 
335 /*
336  * DXMessage, DXWarning, DXUIMessage
337  */
338 #if 0
339 void
340 _dxfTraceMessage(int t)
341 {
342     if (!state && !DXinitdx())
343 	return;
344     state->trace = t;
345 }
346 #endif
347 
348 #define LARGE 2000
349 #define SAFE 1000
350 static char long_buf[LARGE];
351 static int long_n = 0;
352 static int long_message = 0;
353 
354 
355 void
DXBeginLongMessage(void)356 DXBeginLongMessage(void)
357 {
358     long_message = 1;
359 }
360 
361 
362 void
DXEndLongMessage(void)363 DXEndLongMessage(void)
364 {
365     if (long_n > 0)
366 	aqmessage("*", "%s", long_buf);
367     long_n = 0;
368     long_message = 0;
369 }
370 
371 
372 void
DXMessage(char * message,...)373 DXMessage(char *message, ...)
374 {
375     char *p;
376     va_list arg;
377     int usedmessfile;
378 
379     if (state && !state->trace)
380 	return;
381     message = translate(message, &usedmessfile);
382 
383     if (long_message) {
384 	va_start(arg,message);
385 	vsprintf(long_buf+long_n, message, arg);
386 	va_end(arg);
387 	for (p=long_buf+long_n; *p; ) {
388 	    if (*p=='\n') {
389 		*p = '\0';
390 		aqmessage("*", "%s", long_buf);
391 		strcpy(long_buf, p+1);
392 		p = long_buf;
393 	    }
394 	    else
395 		p++;
396 	}
397 	long_n = p-long_buf;
398 	if (long_n > SAFE) {
399 	    *p = '\0';
400 	    aqmessage("*", "%s", long_buf);
401 	    long_n = 0;
402 	}
403     } else {
404 	va_start(arg,message);
405 	DXqmessage(NULL, message, arg);
406 	va_end(arg);
407     }
408 }
409 
410 
411 void
DXWarning(char * message,...)412 DXWarning(char *message, ...)
413 {
414     va_list arg;
415     int usedmessfile;
416 
417     message = translate(message, &usedmessfile);
418     va_start(arg,message);
419     DXqmessage("WARNING", message, arg);
420     va_end(arg);
421 }
422 
423 
424 void
DXUIMessage(char * who,char * message,...)425 DXUIMessage(char *who, char *message, ...)
426 {
427     va_list arg;
428     int usedmessfile;
429 
430     message = translate(message, &usedmessfile);
431     if (state && !state->trace)
432 	return;
433     va_start(arg,message);
434     DXqmessage(who, message, arg);
435     va_end(arg);
436 }
437 
438 
439 void
DXExpandMessage(int enable)440 DXExpandMessage(int enable)
441 {
442     state->translate = enable;
443 }
444 
445 /*
446  * DXDebug mechanism
447  */
448 
449 void
DXEnableDebug(char * classes,int enable)450 DXEnableDebug(char *classes, int enable)
451 {
452     int i;
453     if (!state && !DXinitdx())
454 	return;
455     if (!classes)
456 	for (i=0; i<256; i++)
457 	    state->enabled[i] = enable;
458     else
459 	for (i=0; classes[i]; i++)
460 	    state->enabled[(unsigned char)classes[i]] = enable;
461 }
462 
463 
464 void
DXDebug(char * classes,char * message,...)465 DXDebug(char *classes, char *message, ...)
466 {
467     int i;
468     int usedmessfile;
469 
470     if (!state && !DXinitdx())
471 	return;
472     message = translate(message, &usedmessfile);
473     for (i=0; classes[i]; i++) {
474 	if (!state || state->enabled[(unsigned char)classes[i]]) {
475 	    va_list arg;
476 	    va_start(arg,message);
477 	    DXqmessage(NULL, message, arg);
478 	    va_end(arg);
479 	    return;
480 	}
481     }
482 }
483 
484 int
DXQueryDebug(char * classes)485 DXQueryDebug(char *classes)
486 {
487     int c, i;
488     if (!state && !DXinitdx())
489 	return 0;
490     for (i=0; (c=classes[i])!=0; i++)
491 	if (state->enabled[c])
492 	    return 1;
493     return 0;
494 }
495