LCOV - code coverage report
Current view: top level - src/apps/unittests - common.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 108 124 87.1 %
Date: 2026-07-04 10:37:34 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             : void
      41          40 : normalize_spaces(char *s)
      42             : {
      43             :         char *p, *dest, prev;
      44             : 
      45             :         /* replace all tabs with spaces */
      46       18038 :         for (p = s; *p; ++p)
      47       17998 :                 if (*p == '\t')
      48         242 :                         *p = ' ';
      49             : 
      50             :         /* replace duplicate spaces with a single space */
      51             :         prev = 'x';
      52       17998 :         for (dest = s, p = s; *p; ++p) {
      53       17998 :                 if (prev == ' ' && *p == ' ')
      54         774 :                         continue;
      55       17224 :                 *dest++ = prev = *p;
      56             :         }
      57          40 :         *dest = 0;
      58          40 : }
      59             : 
      60             : void
      61          40 : cat(const char *fn, FILE *out)
      62             : {
      63             :         char line[1024];
      64          40 :         FILE *f = fopen(fn, "r");
      65             : 
      66          40 :         assert(f);
      67         582 :         while (fgets(line, sizeof(line), f)) {
      68         542 :                 fputs("  ", out);
      69         542 :                 fputs(line, out);
      70             :         }
      71          40 :         fclose(f);
      72          40 : }
      73             : 
      74             : /* read a text file into memory, return it as a string */
      75             : char *
      76          40 : read_file(const char *fn)
      77             : {
      78             :         long pos;
      79             :         char *buf;
      80             :         size_t readed, size;
      81             : 
      82          40 :         FILE *f = fopen(fn, "r");
      83             : 
      84          40 :         assert(f);
      85          40 :         assert(fseek(f, 0, SEEK_END) == 0);
      86          40 :         pos = ftell(f);
      87          40 :         assert(pos >= 0 && pos <= 0x1000000);
      88          40 :         size = (size_t) pos;
      89          40 :         assert(fseek(f, 0, SEEK_SET) == 0);
      90          40 :         buf = malloc(size + 10);        /* allocate some more space */
      91          40 :         assert(buf);
      92          40 :         readed = fread(buf, 1, size + 1ul, f);
      93          40 :         assert(readed <= size);
      94          40 :         assert(feof(f));
      95          40 :         fclose(f);
      96          40 :         buf[readed] = 0;
      97          40 :         return buf;
      98             : }
      99             : 
     100             : #define CHECK(n) do {\
     101             :         if (dest + (n) > dest_end) \
     102             :                 no_space(); \
     103             : } while(0)
     104             : 
     105             : char *
     106        1170 : quote_arg(char *dest, char *const dest_end, const char *arg)
     107             : {
     108             : #ifndef _WIN32
     109        1170 :         CHECK(1);
     110        1170 :         *dest++ = '\'';
     111       10528 :         for (; *arg; ++arg) {
     112        9358 :                 if (*arg == '\'') {
     113           0 :                         CHECK(3);
     114           0 :                         strcpy(dest, "'\\'");
     115           0 :                         dest += 3;
     116             :                 }
     117        9358 :                 CHECK(1);
     118        9358 :                 *dest++ = *arg;
     119             :         }
     120        1170 :         CHECK(1);
     121        1170 :         *dest++ = '\'';
     122             : #else
     123             :         CHECK(1);
     124             :         *dest++ = '\"';
     125             :         for (; *arg; ++arg) {
     126             :                 if (*arg == '\\' || *arg == '\"') {
     127             :                         CHECK(1);
     128             :                         *dest++ = '\\';
     129             :                 }
     130             :                 CHECK(1);
     131             :                 *dest++ = *arg;
     132             :         }
     133             :         CHECK(1);
     134             :         *dest++ = '\"';
     135             : #endif
     136        1170 :         return dest;
     137             : }
     138             : 
     139             : char *
     140        2270 : add_string(char *dest, char *const dest_end, const char *str)
     141             : {
     142        2270 :         size_t len = strlen(str);
     143             : 
     144        2270 :         CHECK(len);
     145        2270 :         memcpy(dest, str, len);
     146        2270 :         return dest + len;
     147             : }
     148             : 
     149             : #undef CHECK
     150             : 
     151             : char *
     152         270 : add_server(char *dest, char *const dest_end)
     153             : {
     154         270 :         dest = add_string(dest, dest_end, " -S ");
     155         270 :         dest = quote_arg(dest, dest_end, common_pwd.server);
     156         270 :         dest = add_string(dest, dest_end, " -U ");
     157         270 :         dest = quote_arg(dest, dest_end, common_pwd.user);
     158         270 :         dest = add_string(dest, dest_end, " -P ");
     159         270 :         dest = quote_arg(dest, dest_end, common_pwd.password);
     160         270 :         if (common_pwd.database[0]) {
     161         270 :                 dest = add_string(dest, dest_end, " -D ");
     162         270 :                 dest = quote_arg(dest, dest_end, common_pwd.database);
     163             :         }
     164         270 :         return dest;
     165             : }
     166             : 
     167             : char *
     168          10 : add_login(char *dest, char *const dest_end)
     169             : {
     170          10 :         dest = add_string(dest, dest_end, " -S ");
     171          10 :         dest = quote_arg(dest, dest_end, common_pwd.server);
     172          10 :         dest = add_string(dest, dest_end, " -U ");
     173          10 :         dest = quote_arg(dest, dest_end, common_pwd.user);
     174          10 :         dest = add_string(dest, dest_end, " -P ");
     175          10 :         dest = quote_arg(dest, dest_end, common_pwd.password);
     176          10 :         return dest;
     177             : }
     178             : 
     179             : void
     180          20 : update_path(void)
     181             : {
     182             :         static const tds_dir_char name[] = TDS_DIR("PATH");
     183          20 :         tds_dir_char *path = tds_dir_getenv(name);
     184             : 
     185             : #ifndef _WIN32
     186             :         int len;
     187             : 
     188          20 :         if (!path) {
     189           0 :                 setenv(name, "..", 1);
     190           0 :                 return;
     191             :         }
     192             : 
     193          20 :         len = asprintf(&path, "..:%s", path);
     194          20 :         assert(len > 0);
     195          20 :         setenv(name, path, 1);
     196             : #else
     197             :         const tds_dir_char *only = L"PATH=..";
     198             :         const tds_dir_char *start = L"PATH=..;%s";
     199             :         tds_dir_char *p;
     200             :         size_t len;
     201             : 
     202             : #ifdef CMAKE_INTDIR
     203             :         if (CMAKE_INTDIR[0]) {
     204             :                 only = L"PATH=..\\" TDS_DIR(CMAKE_INTDIR);
     205             :                 start = L"PATH=..\\" TDS_DIR(CMAKE_INTDIR) L";%s";
     206             :         }
     207             : #endif
     208             : 
     209             :         if (!path) {
     210             :                 _wputenv(only);
     211             :                 return;
     212             :         }
     213             : 
     214             :         len = tds_dir_len(path) + 100;
     215             :         p = tds_new(tds_dir_char, len);
     216             :         assert(p);
     217             :         tds_dir_snprintf(p, len, start, path);
     218             :         path = p;
     219             :         _wputenv(path);
     220             : #endif
     221          20 :         free(path);
     222             : }
     223             : 
     224             : static char *
     225         230 : tsql_generic(const char *input_data, bool get_output)
     226             : {
     227             :         char cmd[2048];
     228         230 :         char *const end = cmd + sizeof(cmd) - 1;
     229             :         char *p;
     230         230 :         char *output = NULL;
     231             :         FILE *f;
     232             :         bool success;
     233             : 
     234         230 :         f = fopen(input_fn(), "w");
     235         230 :         assert(f);
     236         230 :         fputs(input_data, f);
     237         230 :         fclose(f);
     238             : 
     239         230 :         strcpy(cmd, "tsql" EXE_SUFFIX " -o q");
     240         230 :         p = strchr(cmd, 0);
     241         230 :         p = add_server(p, end);
     242         230 :         p = add_string(p, end, "<");
     243         230 :         p = add_string(p, end, input_fn());
     244         230 :         p = add_string(p, end, " >");
     245         230 :         p = add_string(p, end, output_fn());
     246         230 :         *p = 0;
     247         230 :         printf("Executing: %s\n", cmd);
     248         230 :         success = (system(cmd) == 0);
     249         230 :         unlink(input_fn());
     250         230 :         if (!success) {
     251           0 :                 printf("Output is:\n");
     252           0 :                 cat(output_fn(), stdout);
     253           0 :                 unlink(output_fn());
     254           0 :                 fprintf(stderr, "Failed command\n");
     255           0 :                 exit(1);
     256             :         }
     257         230 :         if (get_output)
     258           0 :                 output = read_file(output_fn());
     259         230 :         unlink(output_fn());
     260         230 :         return output;
     261             : }
     262             : 
     263             : void
     264         230 : tsql(const char *input_data)
     265             : {
     266         230 :         tsql_generic(input_data, false);
     267         230 : }
     268             : 
     269             : char *
     270           0 : tsql_out(const char *input_data)
     271             : {
     272           0 :         return tsql_generic(input_data, true);
     273             : }
     274             : 
     275             : static const char *
     276        1450 : get_fn(char *buf, const char *prefix)
     277             : {
     278        1450 :         if (!buf[0])
     279          40 :                 sprintf(buf, "%s.%d", prefix, (int) getpid());
     280        1450 :         return buf;
     281             : }
     282             : 
     283             : const char *
     284         140 : input_fn(void)
     285             : {
     286             :         static char buf[32] = { 0 };
     287             : 
     288         830 :         return get_fn(buf, "input");
     289             : }
     290             : 
     291             : const char *
     292         160 : output_fn(void)
     293             : {
     294             :         static char buf[32] = { 0 };
     295             : 
     296         620 :         return get_fn(buf, "output");
     297             : }

Generated by: LCOV version 1.13