Line data Source code
1 : /*****************************************************************************
2 : * myerror.c
3 : *
4 : * DESCRIPTION
5 : * This file contains the code to handle error messages. Instead of simply
6 : * printing the error to stdio, it allocates some memory and stores the
7 : * message in it. This is so that one can pass the error message back to
8 : * Tcl/Tk or another GUI program when there is no stdio.
9 : * In addition a version of sprintf is provided which allocates memory for
10 : * the calling routine, so that one doesn't have to guess the maximum bounds
11 : * of the message.
12 : *
13 : * HISTORY
14 : * 9/2002 Arthur Taylor (MDL / RSIS): Created.
15 : * 12/2002 Rici Yu, Fangyu Chi, Mark Armstrong, & Tim Boyer
16 : * (RY,FC,MA,&TB): Code Review 2.
17 : * 12/2005 AAT Added myWarn routines.
18 : *
19 : * NOTES
20 : * See Kernighan & Ritchie C book (2nd edition) page 156.
21 : *****************************************************************************
22 : */
23 : #include <stdarg.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include "myassert.h"
27 : #include "myerror.h"
28 : #ifdef MEMWATCH
29 : #include "memwatch.h"
30 : #endif
31 :
32 : /*****************************************************************************
33 : * AllocSprintf() -- Arthur Taylor / MDL (Review 12/2002)
34 : *
35 : * PURPOSE
36 : * Based on minprintf (see K&R C book (2nd edition) page 156. This code
37 : * tries to provide some of the functionality of sprintf, while at the same
38 : * time it handles the memory allocation.
39 : * In addition, it provides a %S option, which allows one to pass in an
40 : * array of strings, and get back a comma delimited string.
41 : *
42 : * ARGUMENTS
43 : * Ptr = An array of data that is of size LenBuff. (Input/Output)
44 : * LenBuff = The allocated length of Ptr. (Input/Output)
45 : * fmt = Format similar to the one used by sprintf to define how to
46 : * print the message (Input)
47 : * ap = argument list initialized by a call to va_start. Contains the
48 : * data needed by fmt. (Input)
49 : *
50 : * RETURNS: void
51 : *
52 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
53 : * 12/2002 (RY,FC,MA,&TB): Code Review.
54 : * 12/2002 AAT: Fixed the mallocSprintf ("") error.
55 : * 2/2003 AAT: increased bufpart[80] to bufpart[330] because the largest
56 : * 64 bit double is: +1.7E+308, and I want 20 "slots" for stuff
57 : * after the decimal place. There is the possibility of "Long
58 : * doubles" (80 bits) which would have a max of: +3.4E+4932, but
59 : * that is excessive for now.
60 : * 2/2004 AAT: if lenBuff != 0, switch from ipos-- to strlen (buffer);
61 : * 3/2004 AAT: Added %c option.
62 : * 11/2005 AAT: Added %e option.
63 : * 1/2006 AAT: Found a bug with multiple errSprintf. Doesn't seem to be
64 : * able to handle lenBuff > strlen(buffer) when procedure is
65 : * first called. Something like format = "aaa%s", lenBuff = 3,
66 : * buff = 'n' would result in 'naaa__<string>', instead of
67 : * 'naaa<string>'. Simple solution set lenBuff = strlen (buff).
68 : * better solution: Maybe calculate correct place for ipos
69 : * before switch.
70 : *
71 : * NOTES
72 : * Supported formats:
73 : * %0.4f => float, double
74 : * %03d %ld %10ld => int, sInt4.
75 : * %s => Null terminated char string. (no range specification)
76 : * %S => take a char ** and turn it into a comma delimited string.
77 : *
78 : * Assumes that no individual float or int will be more than 80 characters
79 : * Assumes that no % option is more than 20 char.
80 : *****************************************************************************
81 : */
82 3841 : static void AllocSprintf (char **Ptr, size_t *LenBuff, const char *fmt,
83 : va_list ap)
84 : {
85 3841 : char *buffer = *Ptr; /* Local copy of Ptr. */
86 3841 : size_t lenBuff = *LenBuff; /* Local copy of LenBuff. */
87 : const char *p; /* Points to % char in % option. */
88 : const char *p1; /* Points to end of % option. */
89 : char bufpart[330]; /* Used for formatting the int / float options. */
90 : char format[20]; /* Used to store the % option. */
91 : char *sval; /* For pulling strings off va_list. */
92 : char **Sval; /* For pulling lists of strings off va_list. */
93 : size_t slen; /* Length of used part of temp. */
94 : char f_inLoop; /* Flag to state whether we got into %S , loop. */
95 : char flag; /* If they have a l,L,h in string. */
96 : /* size_t ipos = *LenBuff; *//* The current index to start storing data. */
97 : size_t ipos; /* The current index to start storing data. */
98 : int c_type; /* Used when handling %c option. */
99 :
100 : myAssert (sizeof (char) == 1);
101 :
102 3841 : if ((fmt == nullptr) || (strlen (fmt) == 0)) {
103 0 : return;
104 : }
105 3841 : p = fmt;
106 : /* If lenBuff = 0, then make room for the '\0' character. */
107 3841 : if (lenBuff == 0) {
108 3027 : lenBuff++;
109 3027 : buffer = (char *) realloc ((void *) buffer, lenBuff);
110 : /* Added following 1 line on 1/2006 */
111 3027 : ipos = 0;
112 : } else {
113 : /* Added following 3 lines on 1/2006 */
114 814 : myAssert (lenBuff >= strlen (buffer) + 1);
115 814 : lenBuff = strlen (buffer) + 1;
116 814 : ipos = lenBuff - 1;
117 : /* ipos = strlen (buffer); */
118 : }
119 12073 : while (p < fmt + strlen (fmt)) {
120 10395 : p1 = p;
121 10395 : p = strchr (p1, '%');
122 : /* Handle simple case when no more % in format string. */
123 10395 : if (p == nullptr) {
124 : /* No more format strings; copy rest of format and return */
125 2163 : lenBuff += strlen (p1);
126 2163 : buffer = (char *) realloc ((void *) buffer, lenBuff);
127 2163 : strcpy (buffer + ipos, p1);
128 2163 : goto done;
129 : }
130 : /* Handle data up to the current % in format string. */
131 8232 : lenBuff += p - p1;
132 8232 : buffer = (char *) realloc ((void *) buffer, lenBuff);
133 8232 : strncpy (buffer + ipos, p1, p - p1);
134 8232 : ipos = lenBuff - 1;
135 : /* Start dealing with % of format. */
136 8232 : p1 = p + strspn (p + 1, "0123456789.");
137 8232 : p1++;
138 : /* p1 points to first letter after %. */
139 8232 : switch (*p1) {
140 2 : case 'h':
141 : case 'l':
142 : case 'L':
143 2 : flag = *p1;
144 2 : p1++;
145 2 : break;
146 0 : case '\0':
147 : /* Handle improper use of '%' for example: '%##' */
148 0 : lenBuff += p1 - p - 1;
149 0 : buffer = (char *) realloc ((void *) buffer, lenBuff);
150 0 : strncpy (buffer + ipos, p + 1, p1 - p - 1);
151 0 : goto done;
152 8230 : default:
153 8230 : flag = ' ';
154 : }
155 8232 : if ((p1 - p + 1) > (int) (sizeof (format)) - 1) {
156 : /* Protect against overflow of format string. */
157 0 : lenBuff += p1 - p + 1;
158 0 : buffer = (char *) realloc ((void *) buffer, lenBuff);
159 0 : strncpy (buffer + ipos, p, p1 - p + 1);
160 0 : ipos = lenBuff - 1;
161 : } else {
162 8232 : strncpy (format, p, p1 - p + 1);
163 8232 : format[p1 - p + 1] = '\0';
164 8232 : switch (*p1) {
165 1893 : case 'd':
166 1893 : switch (flag) {
167 2 : case 'l':
168 : case 'L':
169 2 : snprintf (bufpart, sizeof(bufpart), format, va_arg (ap, sInt4));
170 2 : break;
171 : /*
172 : * gcc warning for 'h': "..." promotes short int to
173 : * int. Could get rid of 'h' option but decided to
174 : * leave it in since we might have a different
175 : * compiler.
176 : */
177 : /*
178 : case 'h':
179 : snprintf (bufpart, sizeof(bufpart), format, va_arg(ap, short int));
180 : break;
181 : */
182 1891 : default:
183 1891 : snprintf (bufpart, sizeof(bufpart), format, va_arg (ap, int));
184 : }
185 1893 : slen = strlen (bufpart);
186 1893 : lenBuff += slen;
187 1893 : buffer = (char *) realloc ((void *) buffer, lenBuff);
188 1893 : memcpy (buffer + ipos, bufpart, slen);
189 1893 : ipos = lenBuff - 1;
190 1893 : break;
191 4 : case 'f':
192 4 : snprintf (bufpart, sizeof(bufpart), format, va_arg (ap, double));
193 4 : slen = strlen (bufpart);
194 4 : lenBuff += slen;
195 4 : buffer = (char *) realloc ((void *) buffer, lenBuff);
196 4 : memcpy (buffer + ipos, bufpart, slen);
197 4 : ipos = lenBuff - 1;
198 4 : break;
199 0 : case 'e':
200 0 : snprintf (bufpart, sizeof(bufpart), format, va_arg (ap, double));
201 0 : slen = strlen (bufpart);
202 0 : lenBuff += slen;
203 0 : buffer = (char *) realloc ((void *) buffer, lenBuff);
204 0 : memcpy (buffer + ipos, bufpart, slen);
205 0 : ipos = lenBuff - 1;
206 0 : break;
207 0 : case 'g':
208 0 : snprintf (bufpart, sizeof(bufpart), format, va_arg (ap, double));
209 0 : slen = strlen (bufpart);
210 0 : lenBuff += slen;
211 0 : buffer = (char *) realloc ((void *) buffer, lenBuff);
212 0 : memcpy (buffer + ipos, bufpart, slen);
213 0 : ipos = lenBuff - 1;
214 0 : break;
215 0 : case 'c':
216 0 : c_type = va_arg (ap, int);
217 0 : lenBuff += 1;
218 0 : buffer = (char *) realloc ((void *) buffer, lenBuff);
219 0 : buffer[ipos] = (char) c_type;
220 0 : buffer[ipos + 1] = '\0';
221 0 : ipos = lenBuff - 1;
222 0 : break;
223 6335 : case 's':
224 6335 : if ((p1 - p) == 1) {
225 6335 : sval = va_arg (ap, char *);
226 : /* printf (":: sval :: '%s'\n", sval);*/
227 6335 : slen = strlen (sval);
228 6335 : lenBuff += slen;
229 6335 : buffer = (char *) realloc ((void *) buffer, lenBuff);
230 6335 : memcpy (buffer + ipos, sval, slen);
231 6335 : ipos = lenBuff - 1;
232 6335 : break;
233 : }
234 : [[fallthrough]];
235 : case 'S':
236 0 : if ((p1 - p) == 1) {
237 0 : f_inLoop = 0;
238 0 : for (Sval = va_arg (ap, char **); *Sval; Sval++) {
239 0 : slen = strlen (*Sval);
240 0 : lenBuff += slen + 1;
241 0 : buffer = (char *) realloc ((void *) buffer, lenBuff);
242 0 : strcpy (buffer + ipos, *Sval);
243 0 : strcat (buffer + ipos + slen, ",");
244 0 : ipos = lenBuff - 1;
245 0 : f_inLoop = 1;
246 : }
247 0 : if (f_inLoop) {
248 0 : lenBuff--;
249 0 : buffer[lenBuff] = '\0';
250 0 : ipos = lenBuff - 1;
251 : }
252 0 : break;
253 : }
254 : [[fallthrough]];
255 : default:
256 0 : lenBuff += p1 - p;
257 0 : buffer = (char *) realloc ((void *) buffer, lenBuff);
258 0 : strncpy (buffer + ipos, p + 1, p1 - p);
259 0 : ipos = lenBuff - 1;
260 0 : break;
261 : }
262 : }
263 8232 : p = p1 + 1;
264 : }
265 1678 : done:
266 3841 : buffer[lenBuff - 1] = '\0';
267 3841 : *Ptr = buffer;
268 3841 : *LenBuff = lenBuff;
269 : }
270 :
271 : /*****************************************************************************
272 : * mallocSprintf() -- Arthur Taylor / MDL (Review 12/2002)
273 : *
274 : * PURPOSE
275 : * This is a front end for AllocSprintf, when you want to malloc memory.
276 : * In other words when the pointer is not pointing to anything in particular.
277 : * It allocates the memory, prints the message, and then sets Ptr to point to
278 : * it.
279 : *
280 : * ARGUMENTS
281 : * Ptr = Place to point to new memory which contains the message (Output)
282 : * fmt = Format similar to the one used by sprintf to define how to print the
283 : * message (Input)
284 : *
285 : * RETURNS: void
286 : *
287 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
288 : * 12/2002 (RY,FC,MA,&TB): Code Review.
289 : *
290 : * NOTES
291 : * Supported formats: See AllocSprintf
292 : *****************************************************************************
293 : */
294 794 : void mallocSprintf (char **Ptr, const char *fmt, ...)
295 : {
296 : va_list ap; /* Contains the data needed by fmt. */
297 794 : size_t buff_len = 0; /* Allocated length of buffer. */
298 :
299 794 : *Ptr = nullptr;
300 794 : if (fmt != nullptr) {
301 794 : va_start (ap, fmt); /* make ap point to 1st unnamed arg. */
302 794 : AllocSprintf (Ptr, &buff_len, fmt, ap);
303 794 : va_end (ap); /* clean up when done. */
304 : }
305 794 : }
306 :
307 : /*****************************************************************************
308 : * reallocSprintf() -- Arthur Taylor / MDL (Review 12/2002)
309 : *
310 : * PURPOSE
311 : * This is a front end for AllocSprintf, when you want to realloc memory.
312 : * In other words, the pointer is pointing to NULL, or to some memory that
313 : * you want to tack a message onto the end of. It allocates extra memory,
314 : * and prints the message.
315 : *
316 : * KEY WORDS: "Tack a message onto the end of"
317 : *
318 : * ARGUMENTS
319 : * Ptr = Pointer to memory to add the message to. (Input/Output)
320 : * fmt = Format similar to the one used by sprintf to define how to print the
321 : * message (Input)
322 : *
323 : * RETURNS: void
324 : *
325 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
326 : * 12/2002 (RY,FC,MA,&TB): Code Review.
327 : *
328 : * NOTES
329 : * Supported formats: See AllocSprintf
330 : *****************************************************************************
331 : */
332 2671 : void reallocSprintf (char **Ptr, const char *fmt, ...)
333 : {
334 : va_list ap; /* Contains the data needed by fmt. */
335 : size_t buff_len; /* Allocated length of buffer. */
336 :
337 2671 : if (fmt != nullptr) {
338 2671 : va_start (ap, fmt); /* make ap point to 1st unnamed arg. */
339 2671 : if (*Ptr == nullptr) {
340 1877 : buff_len = 0;
341 : } else {
342 794 : buff_len = strlen (*Ptr) + 1;
343 : }
344 2671 : AllocSprintf (Ptr, &buff_len, fmt, ap);
345 2671 : va_end (ap); /* clean up when done. */
346 : }
347 2671 : }
348 :
349 : /*****************************************************************************
350 : * errSprintf() -- Arthur Taylor / MDL (Review 12/2002)
351 : *
352 : * PURPOSE
353 : * This uses AllocSprintf to generate a message, which it stores in a static
354 : * variable. If it is called with a (NULL), it returns the built up message,
355 : * and resets its pointer to NULL. The idea being that errors can be stacked
356 : * up, and you pop them off when you need to report them. The reporting could
357 : * be done by printing them to stdio, or by passing them back to Tcl/Tk.
358 : * Note: It is the caller's responsibility to free the memory, and it is
359 : * the caller's responsibility to make sure the last call to this is with
360 : * (NULL), or else the memory won't get freed.
361 : *
362 : * ARGUMENTS
363 : * fmt = Format similar to the one used by sprintf to define how to print the
364 : * message (Input)
365 : *
366 : * RETURNS: char *
367 : * if (fmt == NULL) returns built up string
368 : * else returns NULL.
369 : *
370 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
371 : * 12/2002 (RY,FC,MA,&TB): Code Review.
372 : *
373 : * NOTES
374 : * Supported formats: See AllocSprintf
375 : *****************************************************************************
376 : */
377 : /* Following 2 variables used in both errSprintf and preErrSprintf */
378 : static thread_local char *errBuffer = nullptr; /* Stores the current built up message. */
379 : static thread_local size_t errBuff_len = 0; /* Allocated length of errBuffer. */
380 :
381 899 : char *errSprintf (const char *fmt, ...)
382 : {
383 : va_list ap; /* Contains the data needed by fmt. */
384 : char *ans; /* Pointer to the final message while we reset
385 : * buffer. */
386 :
387 899 : if (fmt == nullptr) {
388 532 : ans = errBuffer;
389 532 : errBuffer = nullptr;
390 532 : errBuff_len = 0;
391 532 : return ans;
392 : }
393 367 : va_start (ap, fmt); /* make ap point to 1st unnamed arg. */
394 367 : AllocSprintf (&errBuffer, &errBuff_len, fmt, ap);
395 367 : va_end (ap); /* clean up when done. */
396 367 : return nullptr;
397 : }
398 :
399 : /*****************************************************************************
400 : * preErrSprintf() -- Arthur Taylor / MDL
401 : *
402 : * PURPOSE
403 : * This uses AllocSprintf to generate a message, which it prepends to the
404 : * static variable used by errSprinf. If it is called with a (NULL), it
405 : * does nothing... Use errSprintf (NULL) to get the message, and reset the
406 : * pointer to NULL.
407 : * The idea here is that we want to prepend calling info when there was an
408 : * error.
409 : * Note: It is the caller's responsibility to free the memory, by
410 : * eventually making one last call to errSprintf (NULL) and freeing the
411 : * returned memory.
412 : *
413 : * ARGUMENTS
414 : * fmt = Format similar to the one used by sprintf to define how to print the
415 : * message (Input)
416 : *
417 : * RETURNS: void
418 : *
419 : * 12/2002 Arthur Taylor (MDL/RSIS): Created.
420 : *
421 : * NOTES
422 : * Supported formats: See AllocSprintf
423 : *****************************************************************************
424 : */
425 9 : void preErrSprintf (const char *fmt, ...)
426 : {
427 9 : char *preBuffer = nullptr; /* Stores the prepended message. */
428 9 : size_t preBuff_len = 0; /* Allocated length of preBuffer. */
429 : va_list ap; /* Contains the data needed by fmt. */
430 :
431 : myAssert (sizeof (char) == 1);
432 :
433 9 : if (fmt == nullptr) {
434 0 : return;
435 : }
436 9 : va_start (ap, fmt); /* make ap point to 1st unnamed arg. */
437 9 : AllocSprintf (&preBuffer, &preBuff_len, fmt, ap);
438 9 : va_end (ap); /* clean up when done. */
439 :
440 9 : if (errBuff_len != 0) {
441 : /* Increase preBuffer to have enough room for errBuffer */
442 9 : preBuff_len += errBuff_len;
443 9 : preBuffer = (char *) realloc ((void *) preBuffer, preBuff_len);
444 : /* concat errBuffer to end of preBuffer, and free errBuffer */
445 9 : strcat (preBuffer, errBuffer);
446 9 : free (errBuffer);
447 : }
448 : /* Finally point errBuffer to preBuffer, and update errBuff_len. */
449 9 : errBuffer = preBuffer;
450 9 : errBuff_len = preBuff_len;
451 9 : return;
452 : }
453 :
454 : #ifdef unused_by_GDAL
455 : /*****************************************************************************
456 : * _myWarn() -- Arthur Taylor / MDL
457 : *
458 : * PURPOSE
459 : * This is an update to my errSprintf routines. This procedure uses
460 : * AllocSprintf to generate a message, which it stores in a static variable.
461 : * It allows for prepending or appending error messages, and allows one to
462 : * set the error level of a message.
463 : *
464 : * ARGUMENTS
465 : * f_errCode = 0 => append notation msg, 1 => append warning msg
466 : * 2 => append error msg, 3 => prepend notation msg
467 : * 4 => prepend warning msg, 5 => prepend error msg (Input)
468 : * fmt = Format to define how to print the msg (Input)
469 : * ap = The arguments for the message. (Input)
470 : *
471 : * RETURNS: void
472 : *
473 : * 12/2005 Arthur Taylor (MDL): Created.
474 : *
475 : * NOTES:
476 : *****************************************************************************
477 : */
478 : /* Following variables used in the myWarn routines */
479 : static char *warnBuff = NULL; /* Stores the current built up message. */
480 : static size_t warnBuffLen = 0; /* Allocated length of warnBuff. */
481 : static sChar warnLevel = -1; /* Current warning level. */
482 : static uChar warnOutType = 0; /* Output type as set in myWarnSet. */
483 : static uChar warnDetail = 0; /* Detail level as set in myWarnSet. */
484 : static uChar warnFileDetail = 0; /* Detail level as set in myWarnSet. */
485 : static FILE *warnFP = NULL; /* Warn File as set in myWarnSet. */
486 :
487 : static void _myWarn (uChar f_errCode, const char *fmt, va_list ap)
488 : {
489 : char *buff = NULL; /* Stores the message. */
490 : size_t buffLen = 0; /* Allocated length of buff. */
491 : uChar f_prepend = 0; /* Flag to prepend (or not) the message. */
492 : uChar f_filePrt = 1; /* Flag to print to file. */
493 : uChar f_memPrt = 1; /* Flag to print to memory. */
494 :
495 : if (fmt == NULL) {
496 : return;
497 : }
498 : if (f_errCode > 5) {
499 : f_errCode = 0;
500 : }
501 : if (f_errCode > 2) {
502 : f_errCode -= (uChar) 3;
503 : f_prepend = 1;
504 : }
505 : /* Update the warning level */
506 : if (f_errCode > warnLevel) {
507 : warnLevel = f_errCode;
508 : }
509 :
510 : /* Check if the warnDetail level allows this message. */
511 : if ((warnOutType >= 4) ||
512 : (warnDetail == 2) || ((warnDetail == 1) && (f_errCode < 2))) {
513 : f_memPrt = 0;
514 : }
515 : if ((warnOutType == 0) ||
516 : (warnFileDetail == 2) || ((warnFileDetail == 1) && (f_errCode < 2))) {
517 : if (!f_memPrt) {
518 : return;
519 : }
520 : f_filePrt = 0;
521 : }
522 :
523 : AllocSprintf (&buff, &buffLen, fmt, ap);
524 :
525 : /* Handle the file writing. */
526 : if (f_filePrt) {
527 : fprintf (warnFP, "%s", buff);
528 : }
529 : /* Handle the memory writing. */
530 : if (f_memPrt) {
531 : if (f_prepend) {
532 : if (warnBuffLen != 0) {
533 : /* Add warnBuff to end of buff, and free warnBuff. */
534 : buffLen += warnBuffLen;
535 : myAssert (sizeof (char) == 1);
536 : buff = (char *) realloc (buff, buffLen);
537 : strcat (buff, warnBuff);
538 : free (warnBuff);
539 : }
540 : /* Point warnBuff to buff. */
541 : warnBuff = buff;
542 : warnBuffLen = buffLen;
543 : } else {
544 : if (warnBuffLen == 0) {
545 : warnBuff = buff;
546 : warnBuffLen = buffLen;
547 : } else {
548 : warnBuffLen += buffLen;
549 : myAssert (sizeof (char) == 1);
550 : warnBuff = (char *) realloc (warnBuff, warnBuffLen);
551 : strcat (warnBuff, buff);
552 : free (buff);
553 : }
554 : }
555 : }
556 : }
557 :
558 : /*****************************************************************************
559 : * myWarn() -- Arthur Taylor / MDL
560 : *
561 : * PURPOSE
562 : * This does the transformation of the "..." parameters, and calls _myWarn.
563 : * This was broken out when we started to implement myWarnRet, so we had two
564 : * ways to call _myWarn. A complicated way (myWarnRet), and a simpler way
565 : * (myWarn). After creating the myWarnW# #defines, thought to deprecate use
566 : * of myWarn by making it static. Still need it, because myWarnRet uses it.
567 : *
568 : * ARGUMENTS
569 : * f_errCode = 0 => append notation msg, 1 => append warning msg
570 : * 2 => append error msg, 3 => prepend notation msg
571 : * 4 => prepend warning msg, 5 => prepend error msg (Input)
572 : * fmt = Format to define how to print the msg (Input)
573 : * ... = The actual message arguments. (Input)
574 : *
575 : * RETURNS: void
576 : *
577 : * 12/2005 Arthur Taylor (MDL): Created.
578 : *
579 : * NOTES:
580 : *****************************************************************************
581 : */
582 : static void myWarn (uChar f_errCode, const char *fmt, ...)
583 : {
584 : va_list ap; /* Contains the data needed by fmt. */
585 :
586 : /* Create the message in buff. */
587 : va_start (ap, fmt); /* make ap point to 1st unnamed arg. */
588 : _myWarn (f_errCode, fmt, ap);
589 : va_end (ap); /* clean up when done. */
590 : }
591 :
592 : /*****************************************************************************
593 : * myWarnRet() -- Arthur Taylor / MDL
594 : *
595 : * PURPOSE
596 : * This does the transformation of the "..." parameters, and calls _myWarn.
597 : * This was created, so that the user could pass in where (file and line
598 : * number) the error took place, and get a uniform handling of the file and
599 : * line numbers. In addition the user could pass in a value for the procedure
600 : * to return, which allows the user to have something like:
601 : * "return myWarnW2 (-1, "foobar\n");"
602 : * Which after the #define is evaluated becomes:
603 : * "return myWarnRet (1, -1, __FILE__, __LINE__, "foobar\n");
604 : *
605 : * Without myWarnRet, one would need something like:
606 : * "myWarn (1, "(%s line %d) foobar\n", __FILE__, __LINE__);"
607 : * "return (-1);
608 : * Trying to come up with a #define to make that easier on the user was
609 : * difficult. The first attempt was:
610 : * #define myWarnLine myWarn(1, "(%s, line %d) " __FILE__, __LINE__); myWarn
611 : * but this had difficulties with "if () myWarnLine" since it became two
612 : * statements, which could confuse the use of {}. A better solition was:
613 : * #define myWarnLineW1(f) myWarnLine (1, __FILE__, __LINE__, f)
614 : * Particularly since the user didn't have to remember that Warn is flag of 1,
615 : * and error is flag of 2. Since I already had to create myWarnW# #defines,
616 : * it was easy to add the user specified return values.
617 : *
618 : * ARGUMENTS
619 : * f_errCode = 0 => append notation msg, 1 => append warning msg
620 : * 2 => append error msg, 3 => prepend notation msg
621 : * 4 => prepend warning msg, 5 => prepend error msg (Input)
622 : * appErrCode = User defined error code for myWarnRet to return.
623 : * file = Filename that the call to myWarnRet was in. (Input)
624 : * If NULL, then it skips the __FILE__, __LINE__ print routine.
625 : * lineNum = Line number of call to myWarnRet. (Input)
626 : * fmt = Format to define how to print the msg (Input)
627 : * ... = The actual message arguments. (Input)
628 : *
629 : * RETURNS: int
630 : * The value of appErrCode.
631 : *
632 : * 12/2005 Arthur Taylor (MDL): Created.
633 : *
634 : * NOTES:
635 : * Is in "Quiet" mode if "file" is NULL (no __FILE__, __LINE__ prints)
636 : *****************************************************************************
637 : */
638 : int myWarnRet (uChar f_errCode, int appErrCode, const char *file,
639 : int lineNum, const char *fmt, ...)
640 : {
641 : va_list ap; /* Contains the data needed by fmt. */
642 :
643 : if (fmt != NULL) {
644 : if (file != NULL) {
645 : myWarn (f_errCode, "(%s, line %d) ", file, lineNum);
646 : }
647 : /* Create the message in buff. */
648 : va_start (ap, fmt); /* make ap point to 1st unnamed arg. */
649 : _myWarn (f_errCode, fmt, ap);
650 : va_end (ap); /* clean up when done. */
651 : } else if (file != NULL) {
652 : myWarn (f_errCode, "(%s, line %d)\n", file, lineNum);
653 : }
654 : return appErrCode;
655 : }
656 :
657 : /*****************************************************************************
658 : * myWarnSet() -- Arthur Taylor / MDL
659 : *
660 : * PURPOSE
661 : * This sets warnOutType, warnDetail, and warnFile for myWarn.
662 : *
663 : * ARGUMENTS
664 : * f_outType = 0 => memory, 1 => memory + stdout, 2 => memory + stderr,
665 : * 3 => memory + warnFile, 4 => stdout, 5 => stderr,
666 : * 6 => warnFile. (Input)
667 : * f_detail = 0 => report all, 1 => report errors, 2 => silent. (Input)
668 : * f_fileDetail = 0 => report all, 1 => report errors, 2 => silent. (Input)
669 : * warnFile = An already opened alternate file to log errors to. (Input)
670 : *
671 : * RETURNS: void
672 : *
673 : * 12/2005 Arthur Taylor (MDL): Created.
674 : *
675 : * NOTES:
676 : * The reason someone may want memory + warnFile is so that they can log the
677 : * errors in a logFile, but still have something come to stdout.
678 : *****************************************************************************
679 : */
680 : void myWarnSet (uChar f_outType, uChar f_detail, uChar f_fileDetail,
681 : FILE *warnFile)
682 : {
683 : if (f_outType > 6) {
684 : f_outType = 0;
685 : }
686 : if (f_detail > 2) {
687 : f_detail = 0;
688 : }
689 : warnOutType = f_outType;
690 : warnDetail = f_detail;
691 : warnFileDetail = f_fileDetail;
692 : if ((f_outType == 1) || (f_outType == 4)) {
693 : warnFP = stdout;
694 : } else if ((f_outType == 2) || (f_outType == 5)) {
695 : warnFP = stderr;
696 : } else if ((f_outType == 3) || (f_outType == 6)) {
697 : if (warnFile == NULL) {
698 : warnFP = stderr;
699 : } else {
700 : warnFP = warnFile;
701 : }
702 : } else {
703 : warnFP = NULL;
704 : }
705 : }
706 :
707 : /*****************************************************************************
708 : * myWarnClear() -- Arthur Taylor / MDL
709 : *
710 : * PURPOSE
711 : * This clears the warning stack, returns what is on there in msg, resets
712 : * the memory to NULL, and returns the error code.
713 : *
714 : * ARGUMENTS
715 : * msg = Whatever has been written to the warning memory
716 : * (NULL, or allocated memory) (Out)
717 : * f_closeFile = flag to close the warnFile or not (Input)
718 : *
719 : * RETURNS: sChar
720 : * -1 means no messages in msg (msg should be null)
721 : * 0 means up to notation msg in msg, but msg should not be null.
722 : * 1 means up to warning messages in msg, msg should not be null.
723 : * 2 means up to error messages in msg, msg should not be null.
724 : *
725 : * 12/2005 Arthur Taylor (MDL): Created.
726 : *
727 : * NOTES:
728 : *****************************************************************************
729 : */
730 : sChar myWarnClear (char **msg, uChar f_closeFile)
731 : {
732 : sChar ans;
733 :
734 : *msg = warnBuff;
735 : warnBuff = NULL;
736 : warnBuffLen = 0;
737 : ans = warnLevel;
738 : warnLevel = -1;
739 : if (f_closeFile) {
740 : fclose (warnFP);
741 : }
742 : return ans;
743 : }
744 :
745 : /*****************************************************************************
746 : * myWarnNotEmpty() -- Arthur Taylor / MDL
747 : *
748 : * PURPOSE
749 : * This returns whether the warning message is null or not.
750 : *
751 : * ARGUMENTS
752 : *
753 : * RETURNS: uChar
754 : * 0 => msg == null, 1 => msg != null
755 : *
756 : * 12/2005 Arthur Taylor (MDL): Created.
757 : *
758 : * NOTES:
759 : *****************************************************************************
760 : */
761 : uChar myWarnNotEmpty ()
762 : {
763 : return (uChar) ((warnBuff != NULL) ? 1 : 0);
764 : }
765 :
766 : /*****************************************************************************
767 : * myWarnLevel() -- Arthur Taylor / MDL
768 : *
769 : * PURPOSE
770 : * This returns the status of the warnLevel.
771 : *
772 : * ARGUMENTS
773 : *
774 : * RETURNS: sChar
775 : * -1 means no messages in msg (msg should be null)
776 : * 0 means up to notation msg in msg, but msg should not be null.
777 : * 1 means up to warning messages in msg, msg should not be null.
778 : * 2 means up to error messages in msg, msg should not be null.
779 : *
780 : * 12/2005 Arthur Taylor (MDL): Created.
781 : *
782 : * NOTES:
783 : *****************************************************************************
784 : */
785 : sChar myWarnLevel ()
786 : {
787 : return warnLevel;
788 : }
789 : #endif // unused_by_GDAL
790 :
791 : #ifdef TEST_MYERROR
792 : /*****************************************************************************
793 : * The following 2 procedures are included only to test myerror.c, and only
794 : * if TEST_MYERROR is defined.
795 : *****************************************************************************
796 : */
797 :
798 : /*****************************************************************************
799 : * checkAns() -- Arthur Taylor / MDL (Review 12/2002)
800 : *
801 : * PURPOSE
802 : * To verify that a test gives the expected result.
803 : *
804 : * ARGUMENTS
805 : * ptr = The results of the test. (Input)
806 : * Ans = An array of correct answers. (Input)
807 : * test = Which test we are checking. (Input)
808 : *
809 : * RETURNS: void
810 : *
811 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
812 : * 12/2002 (RY,FC,MA,&TB): Code Review.
813 : *
814 : * NOTES
815 : *****************************************************************************
816 : */
817 : static void checkAns (char *ptr, char **Ans, int test)
818 : {
819 : if (ptr == NULL) {
820 : printf ("-----Check test (%d)--(ptr == NULL)-----\n", test);
821 : return;
822 : }
823 : if (strcmp (ptr, Ans[test]) != 0) {
824 : printf ("-----Failed test %d-------\n", test);
825 : printf ("%s %d =?= %s %d\n", ptr, strlen (ptr),
826 : Ans[test], strlen (Ans[test]));
827 : } else {
828 : printf ("passed test %d\n", test);
829 : }
830 : }
831 :
832 : /*****************************************************************************
833 : * main() -- Arthur Taylor / MDL (Review 12/2002)
834 : *
835 : * PURPOSE
836 : * To test reallocSprint, mallocSprint, and errSprintf, to make sure that
837 : * they pass certain basic tests. I will be adding more tests, as more bugs
838 : * are found, and features added.
839 : *
840 : * ARGUMENTS
841 : * argc = The number of arguments on the command line. (Input)
842 : * argv = The arguments on the command line. (Input)
843 : *
844 : * RETURNS: int
845 : *
846 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
847 : * 12/2002 (RY,FC,MA,&TB): Code Review.
848 : *
849 : * NOTES
850 : *****************************************************************************
851 : */
852 : int main (int argc, char **argv)
853 : {
854 : char *ptr;
855 : uChar warn;
856 : static char *Cmd[] = { "configure", "inquire", "convert", NULL };
857 : sInt4 li_temp = 100000L;
858 : short int sect = 5;
859 : char varName[] = "Helium is a gas";
860 : sInt4 lival = 22;
861 : char unit[] = "km", sval[] = "ans";
862 : double dval = 2.71828;
863 :
864 : char *buffer = NULL;
865 : short int ssect = 0;
866 : char vvarName[] = "DataType";
867 : sInt4 llival = 0;
868 : char ssval[] = "Meteorological products";
869 :
870 : static char *Ans[] = { "S0 | DataType | 0 (Meteorological products)\n",
871 : "<testing>", "<05><3.1415><D><20>",
872 : "<configure,inquire,convert> ?options?",
873 : "100000", "25.123", "02s", "01234567890123456789012345",
874 : "25.123,05, hello world",
875 : "This is a test 5... Here I am\n",
876 : "Parse error Section 0\nErrorERROR: Problems opening c:--goober for "
877 : "write.Projection code requires Earth with Rad = 6367.47 not "
878 : "6400.010000",
879 : "ERROR IS1 not labeled correctly. 5000000\n"
880 : "Should be 1196575042 2 25\nERROR IS0 has unexpected values: "
881 : "100000 100000 100000\n",
882 : "S5 | Helium is a gas | 22 (ans)\nS5 | Helium is a gas | 22\n"
883 : "S5 | Helium is a gas | 22 (ans (km))\nS5 | Helium is a gas | ans\n"
884 : "S5 | Helium is a gas | 2.718280\nS5 | Helium is a gas | "
885 : "2.718280 (km)\n",
886 : "ERROR IS1 not labeled correctly. 5000000\n"
887 : "Should be 1196575042 2 25\nERROR IS0 has unexpected values: "
888 : "100000 100000 100000\n",
889 : "5.670000e+001"
890 : };
891 :
892 : /* Test -2. (See if it can handle blank). */
893 : mallocSprintf (&ptr, "");
894 : free (ptr);
895 : ptr = NULL;
896 :
897 : mallocSprintf (&ptr, " ");
898 : free (ptr);
899 : ptr = NULL;
900 :
901 :
902 : /* Test -1. (see if checkAns is ok) */
903 : ptr = errSprintf (NULL);
904 : checkAns (ptr, Ans, -1);
905 :
906 : /* Test 0 */
907 : reallocSprintf (&buffer, "S%d | %s | %ld (%s)\n", ssect, vvarName,
908 : llival, ssval);
909 : checkAns (buffer, Ans, 0);
910 : free (buffer);
911 :
912 : /* Test 1. */
913 : ptr = NULL;
914 : reallocSprintf (&ptr, "<testing>");
915 : checkAns (ptr, Ans, 1);
916 : free (ptr);
917 :
918 : /* Test 2. */
919 : ptr = NULL;
920 : reallocSprintf (&ptr, "<%02d><%.4f><%D><%ld>", 5, 3.1415, 20, 24);
921 : checkAns (ptr, Ans, 2);
922 : free (ptr);
923 :
924 : /* Test 3. */
925 : ptr = NULL;
926 : reallocSprintf (&ptr, "<%S> ?options?", Cmd);
927 : checkAns (ptr, Ans, 3);
928 : free (ptr);
929 :
930 : /* Test 4. */
931 : ptr = NULL;
932 : reallocSprintf (&ptr, "%ld", li_temp);
933 : checkAns (ptr, Ans, 4);
934 : free (ptr);
935 :
936 : /* Test 5. */
937 : ptr = NULL;
938 : reallocSprintf (&ptr, "%.3f", 25.1234);
939 : checkAns (ptr, Ans, 5);
940 : free (ptr);
941 :
942 : /* Test 6. */
943 : ptr = NULL;
944 : reallocSprintf (&ptr, "%02s", 25.1234);
945 : checkAns (ptr, Ans, 6);
946 : free (ptr);
947 :
948 : /* Test 7. */
949 : ptr = NULL;
950 : reallocSprintf (&ptr, "%01234567890123456789012345");
951 : checkAns (ptr, Ans, 7);
952 : free (ptr);
953 :
954 : /* Test 8. */
955 : mallocSprintf (&ptr, "%.3f", 25.1234);
956 : reallocSprintf (&ptr, ",%02d", 5);
957 : reallocSprintf (&ptr, ", %s", "hello world");
958 : checkAns (ptr, Ans, 8);
959 : free (ptr);
960 : ptr = NULL;
961 :
962 : /* Test 9. */
963 : errSprintf ("This is a test %d... ", 5);
964 : errSprintf ("Here I am\n");
965 : ptr = errSprintf (NULL);
966 : checkAns (ptr, Ans, 9);
967 : free (ptr);
968 :
969 : /* Test 10. */
970 : errSprintf ("Parse error Section 0\n%s", "Error");
971 : errSprintf ("ERROR: Problems opening %s for write.", "c:--goober");
972 : errSprintf ("Projection code requires Earth with Rad = 6367.47 not %f",
973 : 6400.01);
974 : ptr = errSprintf (NULL);
975 : checkAns (ptr, Ans, 10);
976 : free (ptr);
977 :
978 : /* Test 11. */
979 : errSprintf ("ERROR IS1 not labeled correctly. %ld\n", 5000000L);
980 : errSprintf ("Should be %ld %d %ld\n", 1196575042L, 2, 25);
981 : errSprintf ("ERROR IS0 has unexpected values: %ld %ld %ld\n", li_temp,
982 : li_temp, li_temp);
983 : ptr = errSprintf (NULL);
984 : checkAns (ptr, Ans, 11);
985 : free (ptr);
986 :
987 : /* Test 12. */
988 : ptr = NULL;
989 : reallocSprintf (&ptr, "S%d | %s | %ld (%s)\n", sect, varName, lival, sval);
990 : reallocSprintf (&ptr, "S%d | %s | %ld\n", sect, varName, lival);
991 : reallocSprintf (&ptr, "S%d | %s | %ld (%s (%s))\n", sect, varName, lival,
992 : sval, unit);
993 : reallocSprintf (&ptr, "S%d | %s | %s\n", sect, varName, sval);
994 : reallocSprintf (&ptr, "S%d | %s | %f\n", sect, varName, dval);
995 : reallocSprintf (&ptr, "S%d | %s | %f (%s)\n", sect, varName, dval, unit);
996 : checkAns (ptr, Ans, 12);
997 : free (ptr);
998 :
999 : /* Test 13. */
1000 : preErrSprintf ("Should be %ld %d %ld\n", 1196575042L, 2, 25);
1001 : errSprintf ("ERROR IS0 has unexpected values: %ld %ld %ld\n", li_temp,
1002 : li_temp, li_temp);
1003 : preErrSprintf ("ERROR IS1 not labeled correctly. %ld\n", 5000000L);
1004 : ptr = errSprintf (NULL);
1005 : checkAns (ptr, Ans, 13);
1006 : free (ptr);
1007 :
1008 : /* Test 14. */
1009 : ptr = NULL;
1010 : reallocSprintf (&ptr, "%e", 56.7);
1011 : checkAns (ptr, Ans, 14);
1012 : free (ptr);
1013 :
1014 : myWarnSet (1, 0, 1, NULL);
1015 : myWarnW2 (0, "This is a test of Warn\n");
1016 : myWarnE2 (0, "This is a test of Err\n");
1017 : myWarnQ2 (0, "This is a quiet note\n");
1018 : myWarnPW2 (0, "This is a test2 of Error\n");
1019 : myWarnW4 (0, "This is a test of WarnLnW3 %d %d\n", 10, 20);
1020 : myWarnE3 (0, "This is a test of WarnLnE2 %d\n", 10);
1021 : printf ("\tTest myWarnRet: %d\n", myWarnW1 (-1));
1022 : printf ("\tTest myWarnRet: %d\n", myWarnE2 (-2, "Hello nurse\n"));
1023 : if (myWarnNotEmpty ()) {
1024 : ptr = NULL;
1025 : warn = myWarnClear (&ptr, 0);
1026 : printf ("WarnLevel=%d\n%s", warn, ptr);
1027 : free (ptr);
1028 : }
1029 :
1030 : return 0;
1031 : }
1032 : #endif
|