LCOV - code coverage report
Current view: top level - monetdb5/modules/mal - mal_io.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 194 331 58.6 %
Date: 2024-10-07 21:21:43 Functions: 6 9 66.7 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * author N.J. Nes, M.L. Kersten
      15             :  * 01/07/1996, 31/01/2002
      16             :  *
      17             :  * Input/Output module
      18             :  * The IO module provides simple @sc{ascii-io} rendering options.
      19             :  * It is modeled after the tuple formats, but does not
      20             :  * attempt to outline the results. Instead, it is geared at speed,
      21             :  * which also means that some functionality regarding the built-in
      22             :  * types is duplicated from the atoms definitions.
      23             :  *
      24             :  * A functional limited form of formatted printf is also provided.
      25             :  * It accepts at most one variable.
      26             :  * A more complete approach is the tablet module.
      27             :  *
      28             :  * The commands to load and save a BAT from/to an ASCII dump
      29             :  * are efficient, but work only for binary tables.
      30             :  */
      31             : 
      32             : /*
      33             :  * Printing
      34             :  * The print commands are implemented as single instruction rules,
      35             :  * because they need access to the calling context.
      36             :  * At a later stage we can look into the issues related to
      37             :  * parsing the format string as part of the initialization phase.
      38             :  * The old method in V4 essentially causes a lot of overhead
      39             :  * because you have to prepare for the worst (e.g. mismatch format
      40             :  * identifier and argument value)
      41             :  * Beware, the types of the objects to be printed should be
      42             :  * obtained from the stack, because the symbol table may actually
      43             :  * allow for any type to be assigned.
      44             :  */
      45             : #include "monetdb_config.h"
      46             : #include "mal.h"
      47             : #include "mal_instruction.h"
      48             : #include "mal_interpreter.h"
      49             : #include "mutils.h"
      50             : #include "mal_exception.h"
      51             : 
      52             : #define MAXFORMAT 64*1024
      53             : 
      54             : static str
      55           0 : io_stdin(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
      56             : {
      57           0 :         bstream **ret = (bstream **) getArgReference(stk, pci, 0);
      58           0 :         (void) mb;
      59           0 :         if (cntxt->fdin == NULL)
      60           0 :                 throw(MAL, "io.print", SQLSTATE(HY002) "Input channel missing");
      61           0 :         *ret = cntxt->fdin;
      62           0 :         return MAL_SUCCEED;
      63             : }
      64             : 
      65             : static str
      66           0 : io_stdout(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
      67             : {
      68           0 :         stream **ret = (stream **) getArgReference(stk, pci, 0);
      69           0 :         (void) mb;
      70           0 :         if (cntxt->fdout == NULL)
      71           0 :                 throw(MAL, "io.print", SQLSTATE(HY002) "Output channel missing");
      72           0 :         *ret = cntxt->fdout;
      73           0 :         return MAL_SUCCEED;
      74             : }
      75             : 
      76             : static str
      77        1355 : IOprintBoth(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int indx,
      78             :                         str hd, str tl, int nobat)
      79             : {
      80        1355 :         int tpe = getArgType(mb, pci, indx);
      81        1355 :         ptr val = getArgReference(stk, pci, indx);
      82        1355 :         stream *fp = cntxt->fdout;
      83             : 
      84        1355 :         (void) mb;
      85        1355 :         if (cntxt->fdout == NULL)
      86           0 :                 throw(MAL, "io.print", SQLSTATE(HY002) "Output channel missing");
      87             : 
      88        1355 :         if (tpe == TYPE_any)
      89           1 :                 tpe = stk->stk[pci->argv[indx]].vtype;
      90        1355 :         if (val == NULL || tpe == TYPE_void) {
      91           2 :                 if (hd)
      92           2 :                         mnstr_printf(fp, "%s", hd);
      93           2 :                 mnstr_printf(fp, "nil");
      94           2 :                 if (tl)
      95           2 :                         mnstr_printf(fp, "%s", tl);
      96           2 :                 return MAL_SUCCEED;
      97             :         }
      98        1353 :         if (isaBatType(tpe)) {
      99         636 :                 BAT *b;
     100             : 
     101         636 :                 if (is_bat_nil(*(bat *) val)) {
     102           2 :                         if (hd)
     103           2 :                                 mnstr_printf(fp, "%s", hd);
     104           2 :                         mnstr_printf(fp, "nil");
     105           2 :                         if (tl)
     106           2 :                                 mnstr_printf(fp, "%s", tl);
     107           2 :                         return MAL_SUCCEED;
     108             :                 }
     109         634 :                 b = BATdescriptor(*(bat *) val);
     110         634 :                 if (b == NULL) {
     111           0 :                         throw(MAL, "io.print", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     112             :                 }
     113         634 :                 if (nobat) {
     114           0 :                         if (hd)
     115           0 :                                 mnstr_printf(fp, "%s", hd);
     116           0 :                         mnstr_printf(fp, "<%s>", BBP_logical(b->batCacheid));
     117           0 :                         if (tl)
     118           0 :                                 mnstr_printf(fp, "%s", tl);
     119             :                 } else {
     120         634 :                         BATprint(cntxt->fdout, b);
     121             :                 }
     122         634 :                 BBPunfix(b->batCacheid);
     123         634 :                 return MAL_SUCCEED;
     124             :         }
     125         717 :         if (hd)
     126         717 :                 mnstr_printf(fp, "%s", hd);
     127             : 
     128         717 :         if (ATOMextern(tpe))
     129         440 :                 ATOMprint(tpe, *(ptr *) val, fp);
     130             :         else
     131         277 :                 ATOMprint(tpe, val, fp);
     132             : 
     133         717 :         if (tl)
     134         716 :                 mnstr_printf(fp, "%s", tl);
     135             :         return MAL_SUCCEED;
     136             : }
     137             : 
     138             : static str
     139        1354 : IOprint_val(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     140             : {
     141        1354 :         int i;
     142        1354 :         str msg;
     143             : 
     144        1354 :         (void) cntxt;
     145        1354 :         if (p->argc == 2)
     146        1353 :                 msg = IOprintBoth(cntxt, mb, stk, p, 1, "[ ", " ]\n", 0);
     147             :         else {
     148           1 :                 msg = IOprintBoth(cntxt, mb, stk, p, 1, "[ ", 0, 1);
     149           1 :                 if (msg)
     150             :                         return msg;
     151           1 :                 for (i = 2; i < p->argc - 1; i++)
     152           0 :                         if ((msg = IOprintBoth(cntxt, mb, stk, p, i, ", ", 0, 1)) != NULL)
     153           0 :                                 return msg;
     154           1 :                 msg = IOprintBoth(cntxt, mb, stk, p, i, ", ", "]\n", 1);
     155             :         }
     156             :         return msg;
     157             : 
     158             : }
     159             : 
     160             : /*
     161             :  * The IOprintf_() gets a format str, and a sequence of (ptr,int) parameters
     162             :  * containing values and their type numbers. The printf() proved to be a
     163             :  * great risk; people formatting badly their "%s" format strings were crashing
     164             :  * the kernel. This function will prevent you from doing so.
     165             :  *
     166             :  * New implementation that repeatedly invokes sprintf => hacking the va_alist
     167             :  * for using vfsprintf proved to be too compiler-dependent (OLD approach).
     168             :  */
     169             : #define writemem(X1)                                                                                                    \
     170             :         do {                                                                                                                            \
     171             :                 if (dst+X1 > buf+size) {                                                                             \
     172             :                         ptrdiff_t offset = dst - buf;                                                           \
     173             :                         char *tmp;                                                                                                      \
     174             :                         do {                                                                                                            \
     175             :                                 size *= 2;                                                                                              \
     176             :                         } while (dst+X1 > buf+size);                                                         \
     177             :                         tmp = GDKrealloc(buf, size);                                                            \
     178             :                         if (tmp == NULL) {                                                                                      \
     179             :                                 va_end(ap);                                                                                             \
     180             :                                 GDKfree(buf);                                                                                   \
     181             :                                 GDKfree(add);                                                                                   \
     182             :                                 throw(MAL, "io.printf", SQLSTATE(HY013) MAL_MALLOC_FAIL); \
     183             :                         }                                                                                                                       \
     184             :                         buf = tmp;                                                                                                      \
     185             :                         dst = buf + offset;                                                                                     \
     186             :                 }                                                                                                                               \
     187             :         } while (0)
     188             : 
     189             : #define m5sprintf(X1)\
     190             :         if (width > adds) {\
     191             :                 str newadd;\
     192             :                 newadd = GDKrealloc(add, width + 10);\
     193             :                 if (newadd != NULL) {\
     194             :                         adds = width + 10;\
     195             :                         add = newadd;\
     196             :                 }\
     197             :         }\
     198             :         n = snprintf(add, adds, meta, X1);\
     199             :         while (n < 0 || (size_t) n >= adds) {\
     200             :                 size_t newadds;\
     201             :                 str newadd;\
     202             : \
     203             :                 if (n >= 0)     /* glibc 2.1 */\
     204             :                         newadds = n + 1;   /* precisely what is needed */\
     205             :                 else            /* glibc 2.0 */\
     206             :                         newadds = n * 2;     /* twice the old size */\
     207             : \
     208             :                 newadd = GDKrealloc(add, newadds);\
     209             :                 if (newadd == NULL)\
     210             :                         break;\
     211             : \
     212             :                 adds = newadds;\
     213             :                 add = newadd;\
     214             :                 n = snprintf(add, adds, meta, X1);\
     215             :         }
     216             : 
     217             : 
     218             : static const char toofew_error[80] =
     219             :                 OPERATION_FAILED " At least %d parameter(s) expected.\n";
     220             : static const char format_error[80] =
     221             :                 OPERATION_FAILED " Error in format before param %d.\n";
     222             : static const char type_error[80] =
     223             :                 OPERATION_FAILED " Illegal type in param %d.\n";
     224             : 
     225             : #define return_error(x)                                                 \
     226             :         do {                                                                            \
     227             :                 GDKfree(buf);                                                   \
     228             :                 GDKfree(add);                                                   \
     229             :                 throw(MAL,"io.printf", x,argc);                       \
     230             :         } while (0)
     231             : 
     232             : static const char niltext[4] = "nil";
     233             : 
     234             : static str
     235         138 : IOprintf_(str *res, const char *format, ...)
     236             : {
     237         138 :         va_list ap;
     238         138 :         int n;
     239             : 
     240         138 :         int prec = 0, dotseen = 0, escaped = 0, type, size, argc = 1;
     241         138 :         size_t adds = 100, width = 0;
     242         138 :         char *add, *dst, *buf;
     243         138 :         const char *paramseen = NULL;
     244         138 :         char *p;
     245             : 
     246         138 :         if (format == NULL) {
     247           0 :                 throw(MAL, "io.printf",
     248             :                           ILLEGAL_ARGUMENT " NULL pointer passed as format.\n");
     249         138 :         } else if (strchr(format, '%') == NULL) {
     250          30 :                 *res = GDKstrdup(format);
     251          30 :                 if (*res == NULL)
     252           0 :                         throw(MAL, "io.printf", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     253             :                 return MAL_SUCCEED;
     254             :         }
     255         108 :         buf = dst = (str) GDKmalloc(size = 80);
     256         108 :         if (buf == NULL)
     257           0 :                 throw(MAL, "io.printf", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     258         108 :         *res = NULL;
     259             : 
     260         108 :         add = GDKmalloc(adds);
     261         108 :         if (add == NULL) {
     262           0 :                 GDKfree(buf);
     263           0 :                 throw(MAL, "io.printf", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     264             :         }
     265             : 
     266         108 :         va_start(ap, format);
     267        1383 :         for (const char *cur = format; *cur; cur++) {
     268        1276 :                 if (paramseen) {
     269         130 :                         char meta[100];
     270         130 :                         ptrdiff_t extra = 0;
     271         130 :                         ptrdiff_t len;
     272             : 
     273         130 :                         if (GDKisdigit(*cur)) {
     274          10 :                                 if (dotseen) {
     275           2 :                                         prec = 10 * prec + (*cur - '0');
     276             :                                 } else {
     277           8 :                                         width = 10 * width + (*cur - '0');
     278             :                                 }
     279          15 :                                 continue;
     280         120 :                         } else if (dotseen == 0 && *cur == '.') {
     281           2 :                                 dotseen = 1;
     282           2 :                                 continue;
     283         118 :                         } else if (cur == paramseen + 1
     284         110 :                                            && (*cur == '+' || *cur == '-' || *cur == ' ')) {
     285           3 :                                 continue;
     286         115 :                         } else if (*cur == 'l') {
     287           0 :                                 cur++;
     288           0 :                                 if (*cur == 'l') {
     289           0 :                                         cur++;
     290             :                                         /* start of ll */
     291           0 :                                         extra = (cur - paramseen) - 2;
     292             :                                 }
     293             :                         }
     294         115 :                         if ((p = va_arg(ap, char *)) == NULL) {
     295           1 :                                 va_end(ap);
     296           1 :                                 return_error(toofew_error);
     297             :                         }
     298         114 :                         type = va_arg(ap, int);
     299         114 :                         type = ATOMbasetype(type);
     300             : 
     301         114 :                         len = 1 + (cur - paramseen);
     302         114 :                         memcpy(meta, paramseen, len);
     303         114 :                         meta[len] = 0;
     304         114 :                         if (ATOMcmp(type, ATOMnilptr(type), p) == 0) {
     305             :                                 /* value is nil; attempt to print formatted 'nil'
     306             :                                    without generating %ls etc. */
     307             :                                 char *ctrg = meta;
     308             : 
     309          39 :                                 for (const char *csrc = paramseen; csrc < cur; csrc++) {
     310          23 :                                         if (*csrc == '.')
     311             :                                                 break;
     312          22 :                                         if (GDKisdigit(*csrc) || *csrc == '-')
     313           4 :                                                 *(++ctrg) = *csrc;
     314             :                                 }
     315          17 :                                 *(++ctrg) = 's';
     316          17 :                                 *(++ctrg) = 0;
     317          34 :                                 m5sprintf(niltext);
     318          97 :                         } else if (strchr("cdiouxX", *cur) && !extra) {
     319          78 :                                 int ival;
     320             : 
     321          78 :                                 if (dotseen) {
     322           0 :                                         va_end(ap);
     323           0 :                                         return_error(format_error);
     324          78 :                                 } else if (type == TYPE_bte) {
     325           3 :                                         ival = (int) *(bte *) p;
     326             :                                 } else if (type == TYPE_sht) {
     327           0 :                                         ival = (int) *(sht *) p;
     328             :                                 } else if (type == TYPE_flt) {
     329           0 :                                         ival = (int) *(flt *) p;
     330             :                                 } else if (type == TYPE_lng) {
     331          23 :                                         goto largetypes;
     332             : #ifdef HAVE_HGE
     333             :                                 } else if (type == TYPE_hge) {
     334             :                                         /* Does this happen?
     335             :                                          * If so, what do we have TODO ? */
     336           0 :                                         va_end(ap);
     337           0 :                                         return_error(type_error);
     338             : #endif
     339             :                                 } else if (type == TYPE_int) {
     340          52 :                                         ival = *(int *) p;
     341             :                                 } else {
     342           0 :                                         va_end(ap);
     343           0 :                                         return_error(type_error);
     344             :                                 }
     345         110 :                                 m5sprintf(ival);
     346          19 :                         } else if (strchr("diouxX", *cur)) {
     347             : #ifdef NATIVE_WIN32
     348             :                                 ptrdiff_t i;
     349             : #endif
     350           0 :                                 lng lval;
     351             : 
     352           0 :                                 if (dotseen) {
     353           0 :                                         va_end(ap);
     354           0 :                                         return_error(format_error);
     355             :                                 }
     356           0 :   largetypes:
     357          23 :                                 if (type == TYPE_bte) {
     358           0 :                                         lval = (lng) *(bte *) p;
     359          23 :                                 } else if (type == TYPE_sht) {
     360           0 :                                         lval = (lng) *(sht *) p;
     361             :                                 } else if (type == TYPE_int) {
     362           0 :                                         lval = (lng) *(int *) p;
     363             :                                 } else if (type == TYPE_flt) {
     364           0 :                                         lval = (lng) *(flt *) p;
     365             :                                 } else if (type == TYPE_dbl) {
     366           0 :                                         lval = (lng) *(dbl *) p;
     367             :                                 } else if (type == TYPE_lng) {
     368          23 :                                         lval = *(lng *) p;
     369             : #ifdef HAVE_HGE
     370           0 :                                 } else if (type == TYPE_hge) {
     371             :                                         /* Does this happen?
     372             :                                          * If so, what do we have TODO ? */
     373           0 :                                         va_end(ap);
     374           0 :                                         return_error(type_error);
     375             : #endif
     376             :                                 } else {
     377           0 :                                         va_end(ap);
     378           0 :                                         return_error(type_error);
     379             :                                 }
     380          23 :                                 if (!extra) {
     381          23 :                                         meta[len + 2] = meta[len];
     382          23 :                                         meta[len + 1] = meta[len - 1];
     383          23 :                                         meta[len] = 'l';
     384          23 :                                         meta[len - 1] = 'l';
     385          23 :                                         len += 2;
     386          23 :                                         extra = len - 3;
     387             :                                 }
     388             : #ifdef NATIVE_WIN32
     389             :                                 for (i = len; i >= (extra + 2); i--) {
     390             :                                         meta[i + 1] = meta[i];
     391             :                                 }
     392             :                                 meta[extra] = 'I';
     393             :                                 meta[extra + 1] = '6';
     394             :                                 meta[extra + 2] = '4';
     395             : #endif
     396          46 :                                 m5sprintf(lval);
     397          19 :                         } else if (strchr("feEgG", *cur)) {
     398           2 :                                 dbl dval;
     399             : 
     400           2 :                                 if (type == TYPE_flt) {
     401           2 :                                         dval = (dbl) *(flt *) p;
     402           0 :                                 } else if (type == TYPE_dbl) {
     403           0 :                                         dval = *(dbl *) p;
     404             :                                 } else {
     405           0 :                                         va_end(ap);
     406           0 :                                         return_error(type_error);
     407             :                                 }
     408           2 :                                 width += (1 + prec);
     409           4 :                                 m5sprintf(dval);
     410          17 :                         } else if (*cur == 's') {
     411          17 :                                 size_t length;
     412             : 
     413          17 :                                 if (extra) {
     414           0 :                                         va_end(ap);
     415           0 :                                         return_error(format_error);
     416          17 :                                 } else if (type != TYPE_str) {
     417           0 :                                         va_end(ap);
     418           0 :                                         return_error(type_error);
     419             :                                 }
     420          17 :                                 length = strLen(p);
     421          17 :                                 width++;
     422          17 :                                 prec++;                 /* account for '\0' */
     423          17 :                                 if (dotseen && (size_t) prec < length)
     424          17 :                                         length = (size_t) prec;
     425          17 :                                 if (length > width)
     426             :                                         width = length;
     427          34 :                                 m5sprintf(p);
     428             :                         } else {
     429           0 :                                 va_end(ap);
     430           0 :                                 return_error(format_error);
     431             :                         }
     432         114 :                         width = strlen(add);
     433         114 :                         writemem(width);
     434         114 :                         memcpy(dst, add, width);
     435         114 :                         dst += width;
     436         114 :                         paramseen = NULL;
     437         114 :                         argc++;
     438        1146 :                 } else if (!escaped) {
     439        1146 :                         if (*cur == '\\' || (*cur == '%' && cur[1] == '%')) {
     440             :                                 escaped = 1;
     441        1146 :                         } else if (*cur == '%') {
     442             :                                 paramseen = cur;
     443             :                                 dotseen = prec = 0;
     444             :                                 width = 0;
     445             :                         } else {
     446        1031 :                                 writemem(1);
     447        1031 :                                 *dst++ = *cur;
     448             :                         }
     449             :                 } else {
     450           0 :                         escaped = 0;
     451           0 :                         writemem(1);
     452           0 :                         *dst++ = *cur;
     453             :                 }
     454             :         }
     455             : 
     456             : /*
     457             :         if ( va_arg(ap, char *) != NULL){
     458             :                 GDKfree(buf);
     459             :                 throw(MAL,"io.printf", "params %d and beyond ignored %s.\n",argc);
     460             :         }
     461             : */
     462             : 
     463         107 :         writemem(1);
     464         107 :         va_end(ap);
     465         107 :         *dst = 0;
     466         107 :         *res = buf;
     467         107 :         GDKfree(add);
     468         107 :         return MAL_SUCCEED;
     469             : }
     470             : 
     471             : #define getArgValue(s,p,k) VALptr(&(s)->stk[(p)->argv[k]])
     472             : 
     473             : #define G(X) getArgValue(stk,pci,X), getArgType(mb,pci,X)
     474             : 
     475             : static str
     476         138 : IOprintf(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     477             : {
     478         138 :         str *fmt = getArgReference_str(stk, pci, 1);
     479         138 :         str fmt2 = NULL;
     480         138 :         str msg = MAL_SUCCEED;
     481             : 
     482         138 :         (void) cntxt;
     483         138 :         (void) mb;
     484         138 :         switch (pci->argc) {
     485          30 :         case 2:
     486          30 :                 msg = IOprintf_(&fmt2, *fmt);
     487          30 :                 break;
     488         103 :         case 3:
     489         103 :                 msg = IOprintf_(&fmt2, *fmt, G(2));
     490         103 :                 break;
     491           4 :         case 4:
     492           4 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3));
     493           4 :                 break;
     494           0 :         case 5:
     495           0 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3), G(4));
     496           0 :                 break;
     497           1 :         case 6:
     498           1 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3), G(4), G(5));
     499           1 :                 break;
     500           0 :         case 7:
     501           0 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3), G(4), G(5), G(6));
     502           0 :                 break;
     503           0 :         case 8:
     504           0 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3), G(4), G(5), G(6), G(7));
     505           0 :                 break;
     506           0 :         case 9:
     507           0 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3), G(4), G(5), G(6), G(7), G(8));
     508           0 :                 break;
     509           0 :         case 10:
     510           0 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3), G(4), G(5), G(6), G(7), G(8),
     511           0 :                                                 G(9));
     512           0 :                 break;
     513           0 :         default:
     514           0 :                 throw(MAL, "io.printf", "Too many arguments to io.printf");
     515             :         }
     516         138 :         if (msg == MAL_SUCCEED) {
     517         137 :                 mnstr_printf(cntxt->fdout, "%s", fmt2);
     518         137 :                 GDKfree(fmt2);
     519             :         }
     520             :         return msg;
     521             : }
     522             : 
     523             : static str
     524           0 : IOprintfStream(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     525             : {
     526           0 :         str *fmt = getArgReference_str(stk, pci, 2);
     527           0 :         str fmt2 = NULL;
     528           0 :         stream *f = (stream *) getArgReference(stk, pci, 1);
     529           0 :         str msg = MAL_SUCCEED;
     530             : 
     531           0 :         (void) cntxt;
     532           0 :         (void) mb;
     533           0 :         switch (pci->argc) {
     534           0 :         case 3:
     535           0 :                 msg = IOprintf_(&fmt2, *fmt);
     536           0 :                 break;
     537           0 :         case 4:
     538           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3));
     539           0 :                 break;
     540           0 :         case 5:
     541           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4));
     542           0 :                 break;
     543           0 :         case 6:
     544           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4), G(5));
     545           0 :                 break;
     546           0 :         case 7:
     547           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4), G(5), G(6));
     548           0 :                 break;
     549           0 :         case 8:
     550           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4), G(5), G(6), G(7));
     551           0 :                 break;
     552           0 :         case 9:
     553           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4), G(5), G(6), G(7), G(8));
     554           0 :                 break;
     555           0 :         case 10:
     556           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4), G(5), G(6), G(7), G(8), G(9));
     557           0 :                 break;
     558           0 :         case 11:
     559           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4), G(5), G(6), G(7), G(8), G(9),
     560           0 :                                                 G(10));
     561           0 :                 break;
     562           0 :         default:
     563           0 :                 throw(MAL, "io.printf", "Too many arguments to io.printf");
     564             :         }
     565           0 :         if (msg == MAL_SUCCEED) {
     566           0 :                 mnstr_printf(f, "%s", fmt2);
     567           0 :                 GDKfree(fmt2);
     568             :         }
     569             :         return msg;
     570             : }
     571             : 
     572             : /*
     573             :  * The table printing routine implementations.
     574             :  * They merely differ in destination and order prerequisite
     575             :  */
     576             : static str
     577          53 : IOtable(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     578             : {
     579          53 :         BAT *piv[MAXPARAMS];
     580          53 :         int i;
     581          53 :         int tpe;
     582          53 :         ptr val;
     583             : 
     584          53 :         (void) cntxt;
     585          53 :         if (pci->retc != 1 || pci->argc < 2 || pci->argc >= MAXPARAMS)
     586           0 :                 throw(MAL, "io.table",
     587             :                           "INTERNAL ERROR" " assertion error  retc %d  argc %d", pci->retc,
     588             :                           pci->argc);
     589             : 
     590          53 :         memset(piv, 0, sizeof(BAT *) * MAXPARAMS);
     591         177 :         for (i = 1; i < pci->argc; i++) {
     592         124 :                 tpe = getArgType(mb, pci, i);
     593         124 :                 val = getArgReference(stk, pci, i);
     594         124 :                 if (!isaBatType(tpe)) {
     595           0 :                         while (--i >= 1)
     596           0 :                                 BBPreclaim(piv[i]);
     597           0 :                         throw(MAL, "io.table", ILLEGAL_ARGUMENT " BAT expected");
     598             :                 }
     599         124 :                 if ((piv[i] = BATdescriptor(*(bat *) val)) == NULL) {
     600           0 :                         while (--i >= 1)
     601           0 :                                 BBPunfix(piv[i]->batCacheid);
     602           0 :                         throw(MAL, "io.table", ILLEGAL_ARGUMENT " null BAT encountered");
     603             :                 }
     604             :         }
     605             :         /* add materialized void column */
     606          53 :         piv[0] = BATdense(piv[1]->hseqbase, 0, BATcount(piv[1]));
     607          53 :         if (piv[0] == NULL) {
     608           0 :                 for (i = 1; i < pci->argc; i++)
     609           0 :                         BBPunfix(piv[i]->batCacheid);
     610           0 :                 throw(MAL, "io.table", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     611             :         }
     612          53 :         BATprintcolumns(cntxt->fdout, pci->argc, piv);
     613         283 :         for (i = 0; i < pci->argc; i++)
     614         177 :                 BBPunfix(piv[i]->batCacheid);
     615             :         return MAL_SUCCEED;
     616             : }
     617             : 
     618             : #include "mel.h"
     619             : mel_func mal_io_init_funcs[] = {
     620             :  pattern("io", "stdin", io_stdin, false, "return the input stream to the database client", args(1,1, arg("",bstream))),
     621             :  pattern("io", "stdout", io_stdout, false, "return the output stream for the database client", args(1,1, arg("",streams))),
     622             :  pattern("io", "print", IOprint_val, false, "Print a MAL value tuple .", args(1,3, arg("",void),argany("val",1),varargany("lst",0))),
     623             :  pattern("io", "print", IOtable, false, "BATs are printed with '#' for legend \nlines, and the BUNs on separate lines \nbetween brackets, containing each to \ncomma separated values (head and tail). \nIf multiple BATs are passed for printing, \nprint() performs an implicit natural \njoin on the void head, producing a multi attribute table.", args(1,2, arg("",void),batvarargany("b1",0))),
     624             :  pattern("io", "print", IOprint_val, false, "Print a MAL value.", args(1,2, arg("",void),argany("val",1))),
     625             :  pattern("io", "print", IOprint_val, false, "Print a MAL value column .", args(1,2, arg("",void),batargany("val",1))),
     626             :  pattern("io", "printf", IOprintf, false, "Select default format ", args(1,3, arg("",void),arg("fmt",str),varargany("val",0))),
     627             :  pattern("io", "printf", IOprintf, false, "Select default format ", args(1,2, arg("",void),arg("fmt",str))),
     628             :  pattern("io", "printf", IOprintfStream, false, "Select default format ", args(1,4, arg("",void),arg("filep",streams),arg("fmt",str),varargany("val",0))),
     629             :  pattern("io", "printf", IOprintfStream, false, "Select default format ", args(1,3, arg("",void),arg("filep",streams),arg("fmt",str))),
     630             :  { .imp=NULL }
     631             : };
     632             : #include "mal_import.h"
     633             : #ifdef _MSC_VER
     634             : #undef read
     635             : #pragma section(".CRT$XCU",read)
     636             : #endif
     637         323 : LIB_STARTUP_FUNC(init_mal_io_mal)
     638         323 : { mal_module("mal_io", NULL, mal_io_init_funcs); }

Generated by: LCOV version 1.14