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

Generated by: LCOV version 1.13