LCOV - code coverage report
Current view: top level - frmts/grib/degrib/degrib - myerror.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 114 169 67.5 %
Date: 2024-04-27 17:22:41 Functions: 5 5 100.0 %

          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

Generated by: LCOV version 1.14