LCOV - code coverage report
Current view: top level - src/apps/unittests - common.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 111 129 86.0 %
Date: 2026-11-07 23:58:45 Functions: 13 15 86.7 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 2024-2026  Frediano Ziglio
       3             :  *
       4             :  * This library is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU Library General Public
       6             :  * License as published by the Free Software Foundation; either
       7             :  * version 2 of the License, or (at your option) any later version.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * Library General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU Library General Public
      15             :  * License along with this library; if not, write to the
      16             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      17             :  * Boston, MA 02111-1307, USA.
      18             :  */
      19             : 
      20             : #include "common.h"
      21             : 
      22             : #if HAVE_STRING_H
      23             : #include <string.h>
      24             : #endif /* HAVE_STRING_H */
      25             : 
      26             : #ifdef HAVE_UNISTD_H
      27             : #include <unistd.h>
      28             : #endif
      29             : 
      30             : #include <freetds/sysdep_private.h>
      31             : #include <freetds/utils/path.h>
      32             : 
      33             : static void
      34           0 : no_space(void)
      35             : {
      36           0 :         fprintf(stderr, "No space left on buffer\n");
      37           0 :         exit(1);
      38             : }
      39             : 
      40             : /* This is used when comparing defncopy output to expected output */
      41             : void
      42         160 : normalize_spaces(char *s)
      43             : {
      44             :         char *p, *dest, prev;
      45             : 
      46             :         /* replace all tabs & newlines with spaces */
      47       44936 :         for (p = s; *p; ++p)
      48       44776 :                 if (*p == '\t' || *p == '\n' || *p == '\r')
      49        1510 :                         *p = ' ';
      50             : 
      51             :         /* replace duplicate spaces with a single space */
      52             :         prev = 'x';
      53       44776 :         for (dest = s, p = s; *p; ++p) {
      54       44776 :                 if (prev == ' ' && *p == ' ')
      55        1480 :                         continue;
      56       43296 :                 *dest++ = prev = *p;
      57             :         }
      58             : 
      59             :         /* trailing space not significant */
      60         300 :         while (dest > s && dest[-1] == ' ')
      61         140 :                 --dest;
      62         160 :         *dest = 0;
      63             : 
      64             :         /* spaces between , and ] not significant */
      65         382 :         while ((p = strstr(s, ", ]")) != NULL)
      66          62 :                 memmove(p + 1, p + 2, strlen(p + 2) + 1);
      67         160 : }
      68             : 
      69             : void
      70          40 : cat(const char *fn, FILE *out)
      71             : {
      72             :         char line[1024];
      73          40 :         FILE *f = fopen(fn, "r");
      74             : 
      75          40 :         if (!f) {
      76             :                 /* Can happen if e.g. .exe file not found, so no output */
      77           0 :                 fputs("<output file not found>\n", out);
      78           0 :                 return;
      79             :         }
      80             : 
      81         432 :         while (fgets(line, sizeof(line), f)) {
      82         392 :                 fputs("  ", out);
      83         392 :                 fputs(line, out);
      84             :         }
      85          40 :         fclose(f);
      86             : }
      87             : 
      88             : /* read a text file into memory, return it as a string */
      89             : char *
      90          80 : read_file(const char *fn)
      91             : {
      92             :         long pos;
      93             :         char *buf;
      94             :         size_t readed, size;
      95             : 
      96          80 :         FILE *f = fopen(fn, "r");
      97             : 
      98          80 :         assert(f);
      99          80 :         assert(fseek(f, 0, SEEK_END) == 0);
     100          80 :         pos = ftell(f);
     101          80 :         assert(pos >= 0 && pos <= 0x1000000);
     102          80 :         size = (size_t) pos;
     103          80 :         assert(fseek(f, 0, SEEK_SET) == 0);
     104          80 :         buf = malloc(size + 10);        /* allocate some more space */
     105          80 :         assert(buf);
     106          80 :         readed = fread(buf, 1, size + 1ul, f);
     107          80 :         assert(readed <= size);
     108          80 :         assert(feof(f));
     109          80 :         fclose(f);
     110          80 :         buf[readed] = 0;
     111          80 :         return buf;
     112             : }
     113             : 
     114             : #define CHECK(n) do {\
     115             :         if (dest + (n) > dest_end) \
     116             :                 no_space(); \
     117             : } while(0)
     118             : 
     119             : char *
     120        1690 : quote_arg(char *dest, char *const dest_end, const char *arg)
     121             : {
     122             : #if !defined(_WIN32) && !defined(__VMS)
     123        1690 :         CHECK(1);
     124        1690 :         *dest++ = '\'';
     125       15840 :         for (; *arg; ++arg) {
     126       14150 :                 if (*arg == '\'') {
     127           0 :                         CHECK(3);
     128           0 :                         strcpy(dest, "'\\'");
     129           0 :                         dest += 3;
     130             :                 }
     131       14150 :                 CHECK(1);
     132       14150 :                 *dest++ = *arg;
     133             :         }
     134        1690 :         CHECK(1);
     135        1690 :         *dest++ = '\'';
     136             : #else
     137             :         CHECK(1);
     138             :         *dest++ = '\"';
     139             :         for (; *arg; ++arg) {
     140             :                 if (*arg == '\\' || *arg == '\"') {
     141             :                         CHECK(1);
     142             :                         *dest++ = '\\';
     143             :                 }
     144             :                 CHECK(1);
     145             :                 *dest++ = *arg;
     146             :         }
     147             :         CHECK(1);
     148             :         *dest++ = '\"';
     149             : #endif
     150        1690 :         return dest;
     151             : }
     152             : 
     153             : char *
     154        3050 : add_string(char *dest, char *const dest_end, const char *str)
     155             : {
     156        3050 :         size_t len = strlen(str);
     157             : 
     158        3050 :         CHECK(len);
     159        3050 :         memcpy(dest, str, len);
     160        3050 :         return dest + len;
     161             : }
     162             : 
     163             : #undef CHECK
     164             : 
     165             : char *
     166         350 : add_server(char *dest, char *const dest_end)
     167             : {
     168         350 :         dest = add_string(dest, dest_end, " -S ");
     169         350 :         dest = quote_arg(dest, dest_end, common_pwd.server);
     170         350 :         dest = add_string(dest, dest_end, " -U ");
     171         350 :         dest = quote_arg(dest, dest_end, common_pwd.user);
     172         350 :         dest = add_string(dest, dest_end, " -P ");
     173         350 :         dest = quote_arg(dest, dest_end, common_pwd.password);
     174         350 :         if (common_pwd.database[0]) {
     175         350 :                 dest = add_string(dest, dest_end, " -D ");
     176         350 :                 dest = quote_arg(dest, dest_end, common_pwd.database);
     177             :         }
     178         350 :         return dest;
     179             : }
     180             : 
     181             : char *
     182          50 : add_login(char *dest, char *const dest_end)
     183             : {
     184          50 :         dest = add_string(dest, dest_end, " -S ");
     185          50 :         dest = quote_arg(dest, dest_end, common_pwd.server);
     186          50 :         dest = add_string(dest, dest_end, " -U ");
     187          50 :         dest = quote_arg(dest, dest_end, common_pwd.user);
     188          50 :         dest = add_string(dest, dest_end, " -P ");
     189          50 :         dest = quote_arg(dest, dest_end, common_pwd.password);
     190          50 :         return dest;
     191             : }
     192             : 
     193             : void
     194          20 : update_path(void)
     195             : {
     196             :         static const tds_dir_char name[] = TDS_DIR("PATH");
     197          20 :         tds_dir_char *path = tds_dir_getenv(name);
     198             : 
     199             : #ifndef _WIN32
     200             :         int len;
     201             : 
     202          20 :         if (!path) {
     203           0 :                 setenv(name, "..", 1);
     204           0 :                 return;
     205             :         }
     206             : 
     207          20 :         len = asprintf(&path, "..:%s", path);
     208          20 :         assert(len > 0);
     209          20 :         setenv(name, path, 1);
     210             : #else
     211             :         const tds_dir_char *only = L"PATH=..";
     212             :         const tds_dir_char *start = L"PATH=..;%s";
     213             :         tds_dir_char *p;
     214             :         size_t len;
     215             : 
     216             : #ifdef CMAKE_INTDIR
     217             :         if (CMAKE_INTDIR[0]) {
     218             :                 only = L"PATH=..\\" TDS_DIR(CMAKE_INTDIR);
     219             :                 start = L"PATH=..\\" TDS_DIR(CMAKE_INTDIR) L";%s";
     220             :         }
     221             : #endif
     222             : 
     223             :         if (!path) {
     224             :                 _wputenv(only);
     225             :                 return;
     226             :         }
     227             : 
     228             :         len = tds_dir_len(path) + 100;
     229             :         p = tds_new(tds_dir_char, len);
     230             :         assert(p);
     231             :         tds_dir_snprintf(p, len, start, path);
     232             :         path = p;
     233             :         _wputenv(path);
     234             : #endif
     235          20 :         free(path);
     236             : }
     237             : 
     238             : static char *
     239         270 : tsql_generic(const char *input_data, bool get_output)
     240             : {
     241             :         char cmd[2048];
     242         270 :         char *const end = cmd + sizeof(cmd) - 1;
     243             :         char *p;
     244         270 :         char *output = NULL;
     245             :         FILE *f;
     246             :         bool success;
     247             : 
     248         270 :         f = fopen(input_fn(), "w");
     249         270 :         assert(f);
     250         270 :         fputs(input_data, f);
     251         270 :         fclose(f);
     252             : 
     253         270 :         strcpy(cmd, VMS_APP_EXE_INVOKE "tsql" EXE_SUFFIX " -o q");
     254         270 :         p = strchr(cmd, 0);
     255         270 :         p = add_server(p, end);
     256         270 :         p = add_string(p, end, " <");
     257         270 :         p = add_string(p, end, input_fn());
     258         270 :         p = add_string(p, end, " >");
     259         270 :         p = add_string(p, end, output_fn());
     260         270 :         *p = 0;
     261         270 :         printf("Executing: %s\n", cmd);
     262         270 :         success = (system(cmd) == 0);
     263         270 :         unlink(input_fn());
     264         270 :         if (!success) {
     265           0 :                 printf("Output is:\n");
     266           0 :                 cat(output_fn(), stdout);
     267           0 :                 unlink(output_fn());
     268           0 :                 fprintf(stderr, "Failed command\n");
     269           0 :                 exit(1);
     270             :         }
     271         270 :         if (get_output)
     272           0 :                 output = read_file(output_fn());
     273         270 :         unlink(output_fn());
     274         270 :         return output;
     275             : }
     276             : 
     277             : void
     278         270 : tsql(const char *input_data)
     279             : {
     280         270 :         tsql_generic(input_data, false);
     281         270 : }
     282             : 
     283             : char *
     284           0 : tsql_out(const char *input_data)
     285             : {
     286           0 :         return tsql_generic(input_data, true);
     287             : }
     288             : 
     289             : static const char *
     290        1780 : get_fn(char *buf, const char *prefix)
     291             : {
     292        1780 :         if (!buf[0])
     293          40 :                 sprintf(buf, "%s.%d", prefix, (int) getpid());
     294        1780 :         return buf;
     295             : }
     296             : 
     297             : const char *
     298         150 : input_fn(void)
     299             : {
     300             :         static char buf[32] = { 0 };
     301             : 
     302         960 :         return get_fn(buf, "input");
     303             : }
     304             : 
     305             : const char *
     306         280 : output_fn(void)
     307             : {
     308             :         static char buf[32] = { 0 };
     309             : 
     310         820 :         return get_fn(buf, "output");
     311             : }

Generated by: LCOV version 1.13