LCOV - code coverage report
Current view: top level - src/odbc/unittests - parser.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 137 167 82.0 %
Date: 2024-04-18 21:21:48 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /*
       2             :  * Test reading data with SQLBindCol
       3             :  */
       4             : #include "common.h"
       5             : #include <assert.h>
       6             : #include <ctype.h>
       7             : #include "parser.h"
       8             : 
       9             : unsigned int odbc_line_num;
      10             : 
      11             : void
      12           0 : odbc_fatal(const char *msg, ...)
      13             : {
      14             :         va_list ap;
      15             : 
      16           0 :         va_start(ap, msg);
      17           0 :         if (msg[0] == ':')
      18           0 :                 fprintf(stderr, "Line %u", odbc_line_num);
      19           0 :         vfprintf(stderr, msg, ap);
      20           0 :         va_end(ap);
      21             : 
      22           0 :         exit(1);
      23             : }
      24             : 
      25             : #define SEP " \t\n"
      26             : 
      27             : const char *
      28       22430 : odbc_get_tok(char **p)
      29             : {
      30       22430 :         char *s = *p, *end;
      31       22430 :         s += strspn(s, SEP);
      32       22430 :         if (!*s) return NULL;
      33       21326 :         end = s + strcspn(s, SEP);
      34       21326 :         *end = 0;
      35       21326 :         *p = end+1;
      36       21326 :         return s;
      37             : }
      38             : 
      39             : static void
      40        2056 : parse_cstr(char *s)
      41             : {
      42             :         char hexbuf[4];
      43        2056 :         char *d = s;
      44             : 
      45       39600 :         while (*s) {
      46       35488 :                 if (*s != '\\') {
      47       35440 :                         *d++ = *s++;
      48       35440 :                         continue;
      49             :                 }
      50             : 
      51          48 :                 switch (*++s) {
      52           0 :                 case '\"':
      53           0 :                         *d++ = *s++;
      54           0 :                         break;
      55           0 :                 case '\\':
      56           0 :                         *d++ = *s++;
      57           0 :                         break;
      58          48 :                 case 'x':
      59          48 :                         if (strlen(s) < 3)
      60           0 :                                 odbc_fatal(": wrong string format\n");
      61          48 :                         memcpy(hexbuf, ++s, 2);
      62          48 :                         hexbuf[2] = 0;
      63          48 :                         *d++ = (char) strtoul(hexbuf, NULL, 16);
      64          48 :                         s += 2;
      65          48 :                         break;
      66           0 :                 default:
      67           0 :                         odbc_fatal(": wrong string format\n");
      68             :                 }
      69             :         }
      70        2056 :         *d = 0;
      71        2056 : }
      72             : 
      73             : const char *
      74        9368 : odbc_get_str(char **p)
      75             : {
      76        9368 :         char *s = *p, *end;
      77        9368 :         s += strspn(s, SEP);
      78        9368 :         if (!*s) odbc_fatal(": unable to get string\n");
      79             : 
      80        9368 :         if (strncmp(s, "\"\"\"", 3) == 0) {
      81          80 :                 s += 3;
      82          80 :                 end = strstr(s, "\"\"\"");
      83          80 :                 if (!end) odbc_fatal(": string not terminated\n");
      84          80 :                 *end = 0;
      85          80 :                 *p = end+3;
      86        9288 :         } else if (s[0] == '\"') {
      87        2056 :                 ++s;
      88        2056 :                 end = strchr(s, '\"');
      89        2056 :                 if (!end) odbc_fatal(": string not terminated\n");
      90        2056 :                 *end = 0;
      91        2056 :                 parse_cstr(s);
      92        2056 :                 *p = end+1;
      93             :         } else {
      94        7232 :                 return odbc_get_tok(p);
      95             :         }
      96             :         return s;
      97             : }
      98             : 
      99             : enum { MAX_BOOLS = 64 };
     100             : typedef struct {
     101             :         char *name;
     102             :         int value;
     103             : } bool_t;
     104             : static bool_t bools[MAX_BOOLS];
     105             : 
     106             : void
     107         156 : odbc_set_bool(const char *name, int value)
     108             : {
     109             :         unsigned n;
     110         156 :         value = !!value;
     111         678 :         for (n = 0; n < MAX_BOOLS && bools[n].name; ++n)
     112         566 :                 if (!strcmp(bools[n].name, name)) {
     113          44 :                         bools[n].value = value;
     114          44 :                         return;
     115             :                 }
     116             : 
     117         112 :         if (n == MAX_BOOLS)
     118           0 :                 odbc_fatal(": no more boolean variable free\n");
     119         112 :         bools[n].name = strdup(name);
     120         112 :         if (!bools[n].name) odbc_fatal(": out of memory\n");
     121         112 :         bools[n].value = value;
     122             : }
     123             : 
     124             : static int
     125         228 : get_bool(const char *name)
     126             : {
     127             :         unsigned n;
     128         228 :         if (!name)
     129           0 :                 odbc_fatal(": boolean variable not provided\n");
     130         670 :         for (n = 0; n < MAX_BOOLS && bools[n].name; ++n)
     131         898 :                 if (!strcmp(bools[n].name, name))
     132         228 :                         return bools[n].value;
     133             : 
     134           0 :         odbc_fatal(": boolean variable %s not found\n", name);
     135             :         return 0;
     136             : }
     137             : 
     138             : /** initialize booleans, call after connection */
     139             : void
     140          16 : odbc_init_bools(void)
     141             : {
     142          16 :         int big_endian = 1;
     143             : 
     144             :         if (((char *) &big_endian)[0] == 1)
     145          16 :                 big_endian = 0;
     146          16 :         odbc_set_bool("bigendian", big_endian);
     147             : 
     148          16 :         odbc_set_bool("msdb", odbc_db_is_microsoft());
     149          16 :         odbc_set_bool("freetds", odbc_driver_is_freetds());
     150          16 : }
     151             : 
     152             : void
     153          16 : odbc_clear_bools(void)
     154             : {
     155             :         unsigned n;
     156         128 :         for (n = 0; n < MAX_BOOLS && bools[n].name; ++n) {
     157         112 :                 free(bools[n].name);
     158         112 :                 bools[n].name = NULL;
     159             :         }
     160          16 : }
     161             : 
     162             : enum { MAX_CONDITIONS = 32 };
     163             : static char conds[MAX_CONDITIONS];
     164             : static unsigned cond_level = 0;
     165             : 
     166             : static int
     167             : pop_condition(void)
     168             : {
     169         272 :         if (cond_level == 0) odbc_fatal(": no related if\n");
     170         272 :         return conds[--cond_level];
     171             : }
     172             : 
     173             : static void
     174         272 : push_condition(int cond)
     175             : {
     176         272 :         if (cond != 0 && cond != 1) odbc_fatal(": invalid cond value %d\n", cond);
     177         272 :         if (cond_level >= MAX_CONDITIONS) odbc_fatal(": too much nested conditions\n");
     178         272 :         conds[cond_level++] = cond;
     179         272 : }
     180             : 
     181             : static int
     182         228 : get_not_cond(char **p)
     183             : {
     184             :         int cond;
     185         228 :         const char *tok = odbc_get_tok(p);
     186         228 :         if (!tok) odbc_fatal(": wrong condition syntax\n");
     187             : 
     188         228 :         if (!strcmp(tok, "not"))
     189          70 :                 cond = !get_bool(odbc_get_tok(p));
     190             :         else
     191         158 :                 cond = get_bool(tok);
     192             : 
     193         228 :         return cond;
     194             : }
     195             : 
     196             : static int
     197         200 : get_condition(char **p)
     198             : {
     199         200 :         int cond1 = get_not_cond(p), cond2;
     200             :         const char *tok;
     201             : 
     202         428 :         while ((tok=odbc_get_tok(p)) != NULL) {
     203             : 
     204          28 :                 cond2 = get_not_cond(p);
     205             : 
     206          28 :                 if (!strcmp(tok, "or"))
     207           0 :                         cond1 = cond1 || cond2;
     208          28 :                 else if (!strcmp(tok, "and"))
     209          28 :                         cond1 = cond1 && cond2;
     210           0 :                 else odbc_fatal(": wrong condition syntax\n");
     211             :         }
     212         200 :         return cond1;
     213             : }
     214             : 
     215             : static FILE *parse_file;
     216             : static char line_buf[1024];
     217             : 
     218             : void
     219          16 : odbc_init_parser(FILE *f)
     220             : {
     221          16 :         if (parse_file)
     222           0 :                 odbc_fatal("parser file already setup\n");
     223          16 :         parse_file = f;
     224          16 :         odbc_line_num = 0;
     225          16 :         odbc_tds_version();
     226          16 : }
     227             : 
     228             : const char *
     229        6656 : odbc_get_cmd_line(char **p_s, int *cond)
     230             : {
     231       15080 :         while (fgets(line_buf, sizeof(line_buf), parse_file)) {
     232        8408 :                 char *p = line_buf;
     233             :                 const char *cmd;
     234             : 
     235        8408 :                 ++odbc_line_num;
     236             : 
     237        8408 :                 cmd = odbc_get_tok(&p);
     238             : 
     239             :                 /* skip comments */
     240        8408 :                 if (!cmd || cmd[0] == '#' || cmd[0] == 0 || cmd[0] == '\n')
     241        2960 :                         continue;
     242             : 
     243             :                 /* conditional statement */
     244        7216 :                 if (!strcmp(cmd, "else")) {
     245          16 :                         int c = pop_condition();
     246          16 :                         push_condition(c);
     247          16 :                         *cond = c && !*cond;
     248          16 :                         continue;
     249             :                 }
     250        7200 :                 if (!strcmp(cmd, "endif")) {
     251         256 :                         *cond = pop_condition();
     252         256 :                         continue;
     253             :                 }
     254        6944 :                 if (!strcmp(cmd, "if")) {
     255         256 :                         push_condition(*cond);
     256         256 :                         if (*cond)
     257         200 :                                 *cond = get_condition(&p);
     258         256 :                         continue;
     259             :                 }
     260             : 
     261        6688 :                 if (strcmp(cmd, "tds_version_cmp") == 0) {
     262          48 :                         const char *bool_name = odbc_get_tok(&p);
     263          48 :                         const char *cmp = odbc_get_tok(&p);
     264          48 :                         const char *s_ver = odbc_get_tok(&p);
     265          48 :                         int ver = odbc_tds_version();
     266             :                         int expected;
     267             :                         int res;
     268             :                         unsigned M, m;
     269             : 
     270          48 :                         if (!cmp || !s_ver)
     271           0 :                                 odbc_fatal(": missing parameters\n");
     272          48 :                         if (sscanf(s_ver, "%u.%u", &M, &m) != 2)
     273           0 :                                 odbc_fatal(": invalid version %s\n", s_ver);
     274          48 :                         expected = M * 0x100u + m;
     275             : 
     276          48 :                         if (strcmp(cmp, ">") == 0)
     277           0 :                                 res = ver > expected;
     278          48 :                         else if (strcmp(cmp, ">=") == 0)
     279          32 :                                 res = ver >= expected;
     280          16 :                         else if (strcmp(cmp, "<") == 0)
     281           0 :                                 res = ver < expected;
     282          16 :                         else if (strcmp(cmp, "<=") == 0)
     283           0 :                                 res = ver <= expected;
     284          16 :                         else if (strcmp(cmp, "==") == 0)
     285          16 :                                 res = ver == expected;
     286           0 :                         else if (strcmp(cmp, "!=") == 0)
     287           0 :                                 res = ver != expected;
     288             :                         else
     289           0 :                                 odbc_fatal(": invalid operator %s\n", cmp);
     290             : 
     291          48 :                         if (*cond)
     292          42 :                                 odbc_set_bool(bool_name, res);
     293          48 :                         continue;
     294             :                 }
     295             : 
     296        6640 :                 *p_s = p;
     297        6640 :                 return cmd;
     298             :         }
     299             :         return NULL;
     300             : }
     301             : 

Generated by: LCOV version 1.13