LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/ecpglib - misc.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 244 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 16 0
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* src/interfaces/ecpg/ecpglib/misc.c */
       2              : 
       3              : #define POSTGRES_ECPG_INTERNAL
       4              : #include "postgres_fe.h"
       5              : 
       6              : #include <limits.h>
       7              : #include <unistd.h>
       8              : 
       9              : #include "ecpg-pthread-win32.h"
      10              : #include "ecpgerrno.h"
      11              : #include "ecpglib.h"
      12              : #include "ecpglib_extern.h"
      13              : #include "ecpgtype.h"
      14              : #include "pg_config_paths.h"
      15              : #include "pgtypes_date.h"
      16              : #include "pgtypes_interval.h"
      17              : #include "pgtypes_numeric.h"
      18              : #include "pgtypes_timestamp.h"
      19              : #include "sqlca.h"
      20              : 
      21              : #ifndef LONG_LONG_MIN
      22              : #ifdef LLONG_MIN
      23              : #define LONG_LONG_MIN LLONG_MIN
      24              : #else
      25              : #define LONG_LONG_MIN LONGLONG_MIN
      26              : #endif                                                  /* LLONG_MIN */
      27              : #endif                                                  /* LONG_LONG_MIN */
      28              : 
      29              : bool            ecpg_internal_regression_mode = false;
      30              : 
      31              : static struct sqlca_t sqlca_init =
      32              : {
      33              :         {
      34              :                 'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
      35              :         },
      36              :         sizeof(struct sqlca_t),
      37              :         0,
      38              :         {
      39              :                 0,
      40              :                 {
      41              :                         0
      42              :                 }
      43              :         },
      44              :         {
      45              :                 'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
      46              :         },
      47              :         {
      48              :                 0, 0, 0, 0, 0, 0
      49              :         },
      50              :         {
      51              :                 0, 0, 0, 0, 0, 0, 0, 0
      52              :         },
      53              :         {
      54              :                 '0', '0', '0', '0', '0'
      55              :         }
      56              : };
      57              : 
      58              : static pthread_key_t sqlca_key;
      59              : static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT;
      60              : 
      61              : static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
      62              : static pthread_mutex_t debug_init_mutex = PTHREAD_MUTEX_INITIALIZER;
      63              : static volatile int simple_debug = 0;
      64              : static FILE *debugstream = NULL;
      65              : 
      66              : void
      67            0 : ecpg_init_sqlca(struct sqlca_t *sqlca)
      68              : {
      69            0 :         memcpy(sqlca, &sqlca_init, sizeof(struct sqlca_t));
      70            0 : }
      71              : 
      72              : bool
      73            0 : ecpg_init(const struct connection *con, const char *connection_name, const int lineno)
      74              : {
      75            0 :         struct sqlca_t *sqlca = ECPGget_sqlca();
      76              : 
      77            0 :         if (sqlca == NULL)
      78              :         {
      79            0 :                 ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY,
      80              :                                    NULL);
      81            0 :                 return false;
      82              :         }
      83              : 
      84            0 :         ecpg_init_sqlca(sqlca);
      85            0 :         if (con == NULL)
      86              :         {
      87            0 :                 ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
      88            0 :                                    connection_name ? connection_name : ecpg_gettext("NULL"));
      89            0 :                 return false;
      90              :         }
      91              : 
      92            0 :         return true;
      93            0 : }
      94              : 
      95              : static void
      96            0 : ecpg_sqlca_key_destructor(void *arg)
      97              : {
      98            0 :         free(arg);                                      /* sqlca structure allocated in ECPGget_sqlca */
      99            0 : }
     100              : 
     101              : static void
     102            0 : ecpg_sqlca_key_init(void)
     103              : {
     104            0 :         pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor);
     105            0 : }
     106              : 
     107              : struct sqlca_t *
     108            0 : ECPGget_sqlca(void)
     109              : {
     110            0 :         struct sqlca_t *sqlca;
     111              : 
     112            0 :         pthread_once(&sqlca_key_once, ecpg_sqlca_key_init);
     113              : 
     114            0 :         sqlca = pthread_getspecific(sqlca_key);
     115            0 :         if (sqlca == NULL)
     116              :         {
     117            0 :                 sqlca = malloc(sizeof(struct sqlca_t));
     118            0 :                 if (sqlca == NULL)
     119            0 :                         return NULL;
     120            0 :                 ecpg_init_sqlca(sqlca);
     121            0 :                 pthread_setspecific(sqlca_key, sqlca);
     122            0 :         }
     123            0 :         return sqlca;
     124            0 : }
     125              : 
     126              : bool
     127            0 : ECPGstatus(int lineno, const char *connection_name)
     128              : {
     129            0 :         struct connection *con = ecpg_get_connection(connection_name);
     130              : 
     131            0 :         if (!ecpg_init(con, connection_name, lineno))
     132            0 :                 return false;
     133              : 
     134              :         /* are we connected? */
     135            0 :         if (con->connection == NULL)
     136              :         {
     137            0 :                 ecpg_raise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, con->name);
     138            0 :                 return false;
     139              :         }
     140              : 
     141            0 :         return true;
     142            0 : }
     143              : 
     144              : PGTransactionStatusType
     145            0 : ECPGtransactionStatus(const char *connection_name)
     146              : {
     147            0 :         const struct connection *con;
     148              : 
     149            0 :         con = ecpg_get_connection(connection_name);
     150            0 :         if (con == NULL)
     151              :         {
     152              :                 /* transaction status is unknown */
     153            0 :                 return PQTRANS_UNKNOWN;
     154              :         }
     155              : 
     156            0 :         return PQtransactionStatus(con->connection);
     157            0 : }
     158              : 
     159              : bool
     160            0 : ECPGtrans(int lineno, const char *connection_name, const char *transaction)
     161              : {
     162            0 :         PGresult   *res;
     163            0 :         struct connection *con = ecpg_get_connection(connection_name);
     164              : 
     165            0 :         if (!ecpg_init(con, connection_name, lineno))
     166            0 :                 return false;
     167              : 
     168            0 :         ecpg_log("ECPGtrans on line %d: action \"%s\"; connection \"%s\"\n", lineno, transaction, con ? con->name : "null");
     169              : 
     170              :         /* if we have no connection we just simulate the command */
     171            0 :         if (con && con->connection)
     172              :         {
     173              :                 /*
     174              :                  * If we got a transaction command but have no open transaction, we
     175              :                  * have to start one, unless we are in autocommit, where the
     176              :                  * developers have to take care themselves. However, if the command is
     177              :                  * a begin statement, we just execute it once. And if the command is
     178              :                  * commit or rollback prepared, we don't execute it.
     179              :                  */
     180            0 :                 if (PQtransactionStatus(con->connection) == PQTRANS_IDLE &&
     181            0 :                         !con->autocommit &&
     182            0 :                         strncmp(transaction, "begin", 5) != 0 &&
     183            0 :                         strncmp(transaction, "start", 5) != 0 &&
     184            0 :                         strncmp(transaction, "commit prepared", 15) != 0 &&
     185            0 :                         strncmp(transaction, "rollback prepared", 17) != 0)
     186              :                 {
     187            0 :                         res = PQexec(con->connection, "begin transaction");
     188            0 :                         if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
     189            0 :                                 return false;
     190            0 :                         PQclear(res);
     191            0 :                 }
     192              : 
     193            0 :                 res = PQexec(con->connection, transaction);
     194            0 :                 if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
     195            0 :                         return false;
     196            0 :                 PQclear(res);
     197            0 :         }
     198              : 
     199            0 :         return true;
     200            0 : }
     201              : 
     202              : 
     203              : void
     204            0 : ECPGdebug(int n, FILE *dbgs)
     205              : {
     206              :         /* Interlock against concurrent executions of ECPGdebug() */
     207            0 :         pthread_mutex_lock(&debug_init_mutex);
     208              : 
     209              :         /* Prevent ecpg_log() from printing while we change settings */
     210            0 :         pthread_mutex_lock(&debug_mutex);
     211              : 
     212            0 :         if (n > 100)
     213              :         {
     214            0 :                 ecpg_internal_regression_mode = true;
     215            0 :                 simple_debug = n - 100;
     216            0 :         }
     217              :         else
     218            0 :                 simple_debug = n;
     219              : 
     220            0 :         debugstream = dbgs;
     221              : 
     222              :         /* We must release debug_mutex before invoking ecpg_log() ... */
     223            0 :         pthread_mutex_unlock(&debug_mutex);
     224              : 
     225              :         /* ... but keep holding debug_init_mutex to avoid racy printout */
     226            0 :         ecpg_log("ECPGdebug: set to %d\n", simple_debug);
     227              : 
     228            0 :         pthread_mutex_unlock(&debug_init_mutex);
     229            0 : }
     230              : 
     231              : void
     232            0 : ecpg_log(const char *format,...)
     233              : {
     234            0 :         va_list         ap;
     235            0 :         const char *intl_format;
     236            0 :         int                     bufsize;
     237            0 :         char       *fmt;
     238            0 :         struct sqlca_t *sqlca;
     239              : 
     240              :         /*
     241              :          * For performance reasons, inspect simple_debug without taking the mutex.
     242              :          * This could be problematic if fetching an int isn't atomic, but we
     243              :          * assume that it is in many other places too.
     244              :          */
     245            0 :         if (!simple_debug)
     246            0 :                 return;
     247              : 
     248              :         /* localize the error message string */
     249            0 :         intl_format = ecpg_gettext(format);
     250              : 
     251              :         /*
     252              :          * Insert PID into the format, unless ecpg_internal_regression_mode is set
     253              :          * (regression tests want unchanging output).
     254              :          */
     255            0 :         bufsize = strlen(intl_format) + 100;
     256            0 :         fmt = (char *) malloc(bufsize);
     257            0 :         if (fmt == NULL)
     258            0 :                 return;
     259              : 
     260            0 :         if (ecpg_internal_regression_mode)
     261            0 :                 snprintf(fmt, bufsize, "[NO_PID]: %s", intl_format);
     262              :         else
     263            0 :                 snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format);
     264              : 
     265            0 :         sqlca = ECPGget_sqlca();
     266              : 
     267            0 :         pthread_mutex_lock(&debug_mutex);
     268              : 
     269              :         /* Now that we hold the mutex, recheck simple_debug */
     270            0 :         if (simple_debug)
     271              :         {
     272            0 :                 va_start(ap, format);
     273            0 :                 vfprintf(debugstream, fmt, ap);
     274            0 :                 va_end(ap);
     275              : 
     276              :                 /* dump out internal sqlca variables */
     277            0 :                 if (ecpg_internal_regression_mode && sqlca != NULL)
     278              :                 {
     279            0 :                         fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n",
     280            0 :                                         sqlca->sqlcode, sqlca->sqlstate);
     281            0 :                 }
     282              : 
     283            0 :                 fflush(debugstream);
     284            0 :         }
     285              : 
     286            0 :         pthread_mutex_unlock(&debug_mutex);
     287              : 
     288            0 :         free(fmt);
     289            0 : }
     290              : 
     291              : void
     292            0 : ECPGset_noind_null(enum ECPGttype type, void *ptr)
     293              : {
     294            0 :         switch (type)
     295              :         {
     296              :                 case ECPGt_char:
     297              :                 case ECPGt_unsigned_char:
     298              :                 case ECPGt_string:
     299            0 :                         *((char *) ptr) = '\0';
     300            0 :                         break;
     301              :                 case ECPGt_short:
     302              :                 case ECPGt_unsigned_short:
     303            0 :                         *((short int *) ptr) = SHRT_MIN;
     304            0 :                         break;
     305              :                 case ECPGt_int:
     306              :                 case ECPGt_unsigned_int:
     307            0 :                         *((int *) ptr) = INT_MIN;
     308            0 :                         break;
     309              :                 case ECPGt_long:
     310              :                 case ECPGt_unsigned_long:
     311              :                 case ECPGt_date:
     312            0 :                         *((long *) ptr) = LONG_MIN;
     313            0 :                         break;
     314              :                 case ECPGt_long_long:
     315              :                 case ECPGt_unsigned_long_long:
     316            0 :                         *((long long *) ptr) = LONG_LONG_MIN;
     317            0 :                         break;
     318              :                 case ECPGt_float:
     319            0 :                         memset(ptr, 0xff, sizeof(float));
     320            0 :                         break;
     321              :                 case ECPGt_double:
     322            0 :                         memset(ptr, 0xff, sizeof(double));
     323            0 :                         break;
     324              :                 case ECPGt_varchar:
     325            0 :                         *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
     326            0 :                         ((struct ECPGgeneric_varchar *) ptr)->len = 0;
     327            0 :                         break;
     328              :                 case ECPGt_bytea:
     329            0 :                         ((struct ECPGgeneric_bytea *) ptr)->len = 0;
     330            0 :                         break;
     331              :                 case ECPGt_decimal:
     332            0 :                         memset(ptr, 0, sizeof(decimal));
     333            0 :                         ((decimal *) ptr)->sign = NUMERIC_NULL;
     334            0 :                         break;
     335              :                 case ECPGt_numeric:
     336            0 :                         memset(ptr, 0, sizeof(numeric));
     337            0 :                         ((numeric *) ptr)->sign = NUMERIC_NULL;
     338            0 :                         break;
     339              :                 case ECPGt_interval:
     340            0 :                         memset(ptr, 0xff, sizeof(interval));
     341            0 :                         break;
     342              :                 case ECPGt_timestamp:
     343            0 :                         memset(ptr, 0xff, sizeof(timestamp));
     344            0 :                         break;
     345              :                 default:
     346            0 :                         break;
     347              :         }
     348            0 : }
     349              : 
     350              : static bool
     351            0 : _check(const unsigned char *ptr, int length)
     352              : {
     353            0 :         for (length--; length >= 0; length--)
     354            0 :                 if (ptr[length] != 0xff)
     355            0 :                         return false;
     356              : 
     357            0 :         return true;
     358            0 : }
     359              : 
     360              : bool
     361            0 : ECPGis_noind_null(enum ECPGttype type, const void *ptr)
     362              : {
     363            0 :         switch (type)
     364              :         {
     365              :                 case ECPGt_char:
     366              :                 case ECPGt_unsigned_char:
     367              :                 case ECPGt_string:
     368            0 :                         if (*((const char *) ptr) == '\0')
     369            0 :                                 return true;
     370            0 :                         break;
     371              :                 case ECPGt_short:
     372              :                 case ECPGt_unsigned_short:
     373            0 :                         if (*((const short int *) ptr) == SHRT_MIN)
     374            0 :                                 return true;
     375            0 :                         break;
     376              :                 case ECPGt_int:
     377              :                 case ECPGt_unsigned_int:
     378            0 :                         if (*((const int *) ptr) == INT_MIN)
     379            0 :                                 return true;
     380            0 :                         break;
     381              :                 case ECPGt_long:
     382              :                 case ECPGt_unsigned_long:
     383              :                 case ECPGt_date:
     384            0 :                         if (*((const long *) ptr) == LONG_MIN)
     385            0 :                                 return true;
     386            0 :                         break;
     387              :                 case ECPGt_long_long:
     388              :                 case ECPGt_unsigned_long_long:
     389            0 :                         if (*((const long long *) ptr) == LONG_LONG_MIN)
     390            0 :                                 return true;
     391            0 :                         break;
     392              :                 case ECPGt_float:
     393            0 :                         return _check(ptr, sizeof(float));
     394              :                         break;
     395              :                 case ECPGt_double:
     396            0 :                         return _check(ptr, sizeof(double));
     397              :                         break;
     398              :                 case ECPGt_varchar:
     399            0 :                         if (*(((const struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
     400            0 :                                 return true;
     401            0 :                         break;
     402              :                 case ECPGt_bytea:
     403            0 :                         if (((const struct ECPGgeneric_bytea *) ptr)->len == 0)
     404            0 :                                 return true;
     405            0 :                         break;
     406              :                 case ECPGt_decimal:
     407            0 :                         if (((const decimal *) ptr)->sign == NUMERIC_NULL)
     408            0 :                                 return true;
     409            0 :                         break;
     410              :                 case ECPGt_numeric:
     411            0 :                         if (((const numeric *) ptr)->sign == NUMERIC_NULL)
     412            0 :                                 return true;
     413            0 :                         break;
     414              :                 case ECPGt_interval:
     415            0 :                         return _check(ptr, sizeof(interval));
     416              :                         break;
     417              :                 case ECPGt_timestamp:
     418            0 :                         return _check(ptr, sizeof(timestamp));
     419              :                         break;
     420              :                 default:
     421            0 :                         break;
     422              :         }
     423              : 
     424            0 :         return false;
     425            0 : }
     426              : 
     427              : #ifdef WIN32
     428              : 
     429              : int
     430              : pthread_mutex_init(pthread_mutex_t *mp, void *attr)
     431              : {
     432              :         mp->initstate = 0;
     433              :         return 0;
     434              : }
     435              : 
     436              : int
     437              : pthread_mutex_lock(pthread_mutex_t *mp)
     438              : {
     439              :         /* Initialize the csection if not already done */
     440              :         if (mp->initstate != 1)
     441              :         {
     442              :                 LONG            istate;
     443              : 
     444              :                 while ((istate = InterlockedExchange(&mp->initstate, 2)) == 2)
     445              :                         Sleep(0);                       /* wait, another thread is doing this */
     446              :                 if (istate != 1)
     447              :                         InitializeCriticalSection(&mp->csection);
     448              :                 InterlockedExchange(&mp->initstate, 1);
     449              :         }
     450              :         EnterCriticalSection(&mp->csection);
     451              :         return 0;
     452              : }
     453              : 
     454              : int
     455              : pthread_mutex_unlock(pthread_mutex_t *mp)
     456              : {
     457              :         if (mp->initstate != 1)
     458              :                 return EINVAL;
     459              :         LeaveCriticalSection(&mp->csection);
     460              :         return 0;
     461              : }
     462              : 
     463              : static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
     464              : 
     465              : void
     466              : win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
     467              : {
     468              :         if (!*once)
     469              :         {
     470              :                 pthread_mutex_lock(&win32_pthread_once_lock);
     471              :                 if (!*once)
     472              :                 {
     473              :                         fn();
     474              :                         *once = true;
     475              :                 }
     476              :                 pthread_mutex_unlock(&win32_pthread_once_lock);
     477              :         }
     478              : }
     479              : #endif                                                  /* WIN32 */
     480              : 
     481              : #ifdef ENABLE_NLS
     482              : 
     483              : char *
     484            0 : ecpg_gettext(const char *msgid)
     485              : {
     486              :         /*
     487              :          * At least on Windows, there are gettext implementations that fail if
     488              :          * multiple threads call bindtextdomain() concurrently.  Use a mutex and
     489              :          * flag variable to ensure that we call it just once per process.  It is
     490              :          * not known that similar bugs exist on non-Windows platforms, but we
     491              :          * might as well do it the same way everywhere.
     492              :          */
     493              :         static volatile bool already_bound = false;
     494              :         static pthread_mutex_t binddomain_mutex = PTHREAD_MUTEX_INITIALIZER;
     495              : 
     496            0 :         if (!already_bound)
     497              :         {
     498              :                 /* dgettext() preserves errno, but bindtextdomain() doesn't */
     499              : #ifdef WIN32
     500              :                 int                     save_errno = GetLastError();
     501              : #else
     502            0 :                 int                     save_errno = errno;
     503              : #endif
     504              : 
     505            0 :                 (void) pthread_mutex_lock(&binddomain_mutex);
     506              : 
     507            0 :                 if (!already_bound)
     508              :                 {
     509            0 :                         const char *ldir;
     510              : 
     511              :                         /*
     512              :                          * No relocatable lookup here because the calling executable could
     513              :                          * be anywhere
     514              :                          */
     515            0 :                         ldir = getenv("PGLOCALEDIR");
     516            0 :                         if (!ldir)
     517            0 :                                 ldir = LOCALEDIR;
     518            0 :                         bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
     519            0 :                         already_bound = true;
     520            0 :                 }
     521              : 
     522            0 :                 (void) pthread_mutex_unlock(&binddomain_mutex);
     523              : 
     524              : #ifdef WIN32
     525              :                 SetLastError(save_errno);
     526              : #else
     527            0 :                 errno = save_errno;
     528              : #endif
     529            0 :         }
     530              : 
     531            0 :         return dgettext(PG_TEXTDOMAIN("ecpglib"), msgid);
     532              : }
     533              : #endif                                                  /* ENABLE_NLS */
     534              : 
     535              : struct var_list *ivlist = NULL;
     536              : 
     537              : void
     538            0 : ECPGset_var(int number, void *pointer, int lineno)
     539              : {
     540            0 :         struct var_list *ptr;
     541              : 
     542            0 :         struct sqlca_t *sqlca = ECPGget_sqlca();
     543              : 
     544            0 :         if (sqlca == NULL)
     545              :         {
     546            0 :                 ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
     547              :                                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     548            0 :                 return;
     549              :         }
     550              : 
     551            0 :         ecpg_init_sqlca(sqlca);
     552              : 
     553            0 :         for (ptr = ivlist; ptr != NULL; ptr = ptr->next)
     554              :         {
     555            0 :                 if (ptr->number == number)
     556              :                 {
     557              :                         /* already known => just change pointer value */
     558            0 :                         ptr->pointer = pointer;
     559            0 :                         return;
     560              :                 }
     561            0 :         }
     562              : 
     563              :         /* a new one has to be added */
     564            0 :         ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
     565            0 :         if (!ptr)
     566              :         {
     567            0 :                 sqlca = ECPGget_sqlca();
     568              : 
     569            0 :                 if (sqlca == NULL)
     570              :                 {
     571            0 :                         ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
     572              :                                            ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     573            0 :                         return;
     574              :                 }
     575              : 
     576            0 :                 sqlca->sqlcode = ECPG_OUT_OF_MEMORY;
     577            0 :                 strncpy(sqlca->sqlstate, "YE001", sizeof(sqlca->sqlstate));
     578            0 :                 snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "out of memory on line %d", lineno);
     579            0 :                 sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
     580              :                 /* free all memory we have allocated for the user */
     581            0 :                 ECPGfree_auto_mem();
     582            0 :         }
     583              :         else
     584              :         {
     585            0 :                 ptr->number = number;
     586            0 :                 ptr->pointer = pointer;
     587            0 :                 ptr->next = ivlist;
     588            0 :                 ivlist = ptr;
     589              :         }
     590            0 : }
     591              : 
     592              : void *
     593            0 : ECPGget_var(int number)
     594              : {
     595            0 :         struct var_list *ptr;
     596              : 
     597            0 :         for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
     598            0 :         return (ptr) ? ptr->pointer : NULL;
     599            0 : }
        

Generated by: LCOV version 2.3.2-1