LCOV - code coverage report
Current view: top level - monetdb5/modules/mal - mal_io.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 193 334 57.8 %
Date: 2024-04-25 20:03:45 Functions: 6 10 60.0 %

          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         139 : IOprintf_(str *res, str format, ...)
     236             : {
     237         139 :         va_list ap;
     238         139 :         int n;
     239             : 
     240         139 :         int prec = 0, dotseen = 0, escaped = 0, type, size, argc = 1;
     241         139 :         size_t adds = 100, width = 0;
     242         139 :         char *add, *dst, *buf, *cur, *paramseen = NULL;
     243         139 :         char *p;
     244             : 
     245         139 :         if (format == NULL) {
     246           0 :                 throw(MAL, "io.printf",
     247             :                           ILLEGAL_ARGUMENT " NULL pointer passed as format.\n");
     248         139 :         } else if (strchr(format, '%') == NULL) {
     249          31 :                 *res = GDKstrdup(format);
     250          31 :                 if (*res == NULL)
     251           0 :                         throw(MAL, "io.printf", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     252             :                 return MAL_SUCCEED;
     253             :         }
     254         108 :         buf = dst = (str) GDKmalloc(size = 80);
     255         108 :         if (buf == NULL)
     256           0 :                 throw(MAL, "io.printf", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     257         108 :         *res = NULL;
     258             : 
     259         108 :         add = GDKmalloc(adds);
     260         108 :         if (add == NULL) {
     261           0 :                 GDKfree(buf);
     262           0 :                 throw(MAL, "io.printf", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     263             :         }
     264             : 
     265         108 :         va_start(ap, format);
     266        1383 :         for (cur = format; *cur; cur++) {
     267        1276 :                 if (paramseen) {
     268         130 :                         char meta[100];
     269         130 :                         ptrdiff_t extra = 0;
     270         130 :                         ptrdiff_t len;
     271             : 
     272         130 :                         if (GDKisdigit(*cur)) {
     273          10 :                                 if (dotseen) {
     274           2 :                                         prec = 10 * prec + (*cur - '0');
     275             :                                 } else {
     276           8 :                                         width = 10 * width + (*cur - '0');
     277             :                                 }
     278          15 :                                 continue;
     279         120 :                         } else if (dotseen == 0 && *cur == '.') {
     280           2 :                                 dotseen = 1;
     281           2 :                                 continue;
     282         118 :                         } else if (cur == paramseen + 1
     283         110 :                                            && (*cur == '+' || *cur == '-' || *cur == ' ')) {
     284           3 :                                 continue;
     285         115 :                         } else if (*cur == 'l') {
     286           0 :                                 cur++;
     287           0 :                                 if (*cur == 'l') {
     288           0 :                                         cur++;
     289             :                                         /* start of ll */
     290           0 :                                         extra = (cur - paramseen) - 2;
     291             :                                 }
     292             :                         }
     293         115 :                         if ((p = va_arg(ap, char *)) == NULL) {
     294           1 :                                 va_end(ap);
     295           1 :                                 return_error(toofew_error);
     296             :                         }
     297         114 :                         type = va_arg(ap, int);
     298         114 :                         type = ATOMbasetype(type);
     299             : 
     300         114 :                         len = 1 + (cur - paramseen);
     301         114 :                         memcpy(meta, paramseen, len);
     302         114 :                         meta[len] = 0;
     303         114 :                         if (ATOMcmp(type, ATOMnilptr(type), p) == 0) {
     304             :                                 /* value is nil; attempt to print formatted 'nil'
     305             :                                    without generating %ls etc. */
     306             :                                 char *csrc, *ctrg = meta;
     307             : 
     308          39 :                                 for (csrc = paramseen; csrc < cur; csrc++) {
     309          23 :                                         if (*csrc == '.')
     310             :                                                 break;
     311          22 :                                         if (GDKisdigit(*csrc) || *csrc == '-')
     312           4 :                                                 *(++ctrg) = *csrc;
     313             :                                 }
     314          17 :                                 *(++ctrg) = 's';
     315          17 :                                 *(++ctrg) = 0;
     316          34 :                                 m5sprintf(niltext);
     317          97 :                         } else if (strchr("cdiouxX", *cur) && !extra) {
     318          78 :                                 int ival;
     319             : 
     320          78 :                                 if (dotseen) {
     321           0 :                                         va_end(ap);
     322           0 :                                         return_error(format_error);
     323          78 :                                 } else if (type == TYPE_bte) {
     324           3 :                                         ival = (int) *(bte *) p;
     325             :                                 } else if (type == TYPE_sht) {
     326           0 :                                         ival = (int) *(sht *) p;
     327             :                                 } else if (type == TYPE_flt) {
     328           0 :                                         ival = (int) *(flt *) p;
     329             :                                 } else if (type == TYPE_lng) {
     330          23 :                                         goto largetypes;
     331             : #ifdef HAVE_HGE
     332             :                                 } else if (type == TYPE_hge) {
     333             :                                         /* Does this happen?
     334             :                                          * If so, what do we have TODO ? */
     335           0 :                                         va_end(ap);
     336           0 :                                         return_error(type_error);
     337             : #endif
     338             :                                 } else if (type == TYPE_int) {
     339          52 :                                         ival = *(int *) p;
     340             :                                 } else {
     341           0 :                                         va_end(ap);
     342           0 :                                         return_error(type_error);
     343             :                                 }
     344         110 :                                 m5sprintf(ival);
     345          19 :                         } else if (strchr("diouxX", *cur)) {
     346             : #ifdef NATIVE_WIN32
     347             :                                 ptrdiff_t i;
     348             : #endif
     349           0 :                                 lng lval;
     350             : 
     351           0 :                                 if (dotseen) {
     352           0 :                                         va_end(ap);
     353           0 :                                         return_error(format_error);
     354             :                                 }
     355           0 :   largetypes:
     356          23 :                                 if (type == TYPE_bte) {
     357           0 :                                         lval = (lng) *(bte *) p;
     358          23 :                                 } else if (type == TYPE_sht) {
     359           0 :                                         lval = (lng) *(sht *) p;
     360             :                                 } else if (type == TYPE_int) {
     361           0 :                                         lval = (lng) *(int *) p;
     362             :                                 } else if (type == TYPE_flt) {
     363           0 :                                         lval = (lng) *(flt *) p;
     364             :                                 } else if (type == TYPE_dbl) {
     365           0 :                                         lval = (lng) *(dbl *) p;
     366             :                                 } else if (type == TYPE_lng) {
     367          23 :                                         lval = *(lng *) p;
     368             : #ifdef HAVE_HGE
     369           0 :                                 } else if (type == TYPE_hge) {
     370             :                                         /* Does this happen?
     371             :                                          * If so, what do we have TODO ? */
     372           0 :                                         va_end(ap);
     373           0 :                                         return_error(type_error);
     374             : #endif
     375             :                                 } else {
     376           0 :                                         va_end(ap);
     377           0 :                                         return_error(type_error);
     378             :                                 }
     379          23 :                                 if (!extra) {
     380          23 :                                         meta[len + 2] = meta[len];
     381          23 :                                         meta[len + 1] = meta[len - 1];
     382          23 :                                         meta[len] = 'l';
     383          23 :                                         meta[len - 1] = 'l';
     384          23 :                                         len += 2;
     385          23 :                                         extra = len - 3;
     386             :                                 }
     387             : #ifdef NATIVE_WIN32
     388             :                                 for (i = len; i >= (extra + 2); i--) {
     389             :                                         meta[i + 1] = meta[i];
     390             :                                 }
     391             :                                 meta[extra] = 'I';
     392             :                                 meta[extra + 1] = '6';
     393             :                                 meta[extra + 2] = '4';
     394             : #endif
     395          46 :                                 m5sprintf(lval);
     396          19 :                         } else if (strchr("feEgG", *cur)) {
     397           2 :                                 dbl dval;
     398             : 
     399           2 :                                 if (type == TYPE_flt) {
     400           2 :                                         dval = (dbl) *(flt *) p;
     401           0 :                                 } else if (type == TYPE_dbl) {
     402           0 :                                         dval = *(dbl *) p;
     403             :                                 } else {
     404           0 :                                         va_end(ap);
     405           0 :                                         return_error(type_error);
     406             :                                 }
     407           2 :                                 width += (1 + prec);
     408           4 :                                 m5sprintf(dval);
     409          17 :                         } else if (*cur == 's') {
     410          17 :                                 size_t length;
     411             : 
     412          17 :                                 if (extra) {
     413           0 :                                         va_end(ap);
     414           0 :                                         return_error(format_error);
     415          17 :                                 } else if (type != TYPE_str) {
     416           0 :                                         va_end(ap);
     417           0 :                                         return_error(type_error);
     418             :                                 }
     419          17 :                                 length = strLen(p);
     420          17 :                                 width++;
     421          17 :                                 prec++;                 /* account for '\0' */
     422          17 :                                 if (dotseen && (size_t) prec < length)
     423          17 :                                         length = (size_t) prec;
     424          17 :                                 if (length > width)
     425             :                                         width = length;
     426          34 :                                 m5sprintf(p);
     427             :                         } else {
     428           0 :                                 va_end(ap);
     429           0 :                                 return_error(format_error);
     430             :                         }
     431         114 :                         width = strlen(add);
     432         114 :                         writemem(width);
     433         114 :                         memcpy(dst, add, width);
     434         114 :                         dst += width;
     435         114 :                         paramseen = NULL;
     436         114 :                         argc++;
     437        1146 :                 } else if (!escaped) {
     438        1146 :                         if (*cur == '\\' || (*cur == '%' && cur[1] == '%')) {
     439             :                                 escaped = 1;
     440        1146 :                         } else if (*cur == '%') {
     441             :                                 paramseen = cur;
     442             :                                 dotseen = prec = 0;
     443             :                                 width = 0;
     444             :                         } else {
     445        1031 :                                 writemem(1);
     446        1031 :                                 *dst++ = *cur;
     447             :                         }
     448             :                 } else {
     449           0 :                         escaped = 0;
     450           0 :                         writemem(1);
     451           0 :                         *dst++ = *cur;
     452             :                 }
     453             :         }
     454             : 
     455             : /*
     456             :         if ( va_arg(ap, char *) != NULL){
     457             :                 GDKfree(buf);
     458             :                 throw(MAL,"io.printf", "params %d and beyond ignored %s.\n",argc);
     459             :         }
     460             : */
     461             : 
     462         107 :         writemem(1);
     463         107 :         va_end(ap);
     464         107 :         *dst = 0;
     465         107 :         *res = buf;
     466         107 :         GDKfree(add);
     467         107 :         return MAL_SUCCEED;
     468             : }
     469             : 
     470             : #define getArgValue(s,p,k) VALptr(&(s)->stk[(p)->argv[k]])
     471             : 
     472             : #define G(X) getArgValue(stk,pci,X), getArgType(mb,pci,X)
     473             : 
     474             : static str
     475         139 : IOprintf(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     476             : {
     477         139 :         str *fmt = getArgReference_str(stk, pci, 1);
     478         139 :         str fmt2 = NULL;
     479         139 :         str msg = MAL_SUCCEED;
     480             : 
     481         139 :         (void) cntxt;
     482         139 :         (void) mb;
     483         139 :         switch (pci->argc) {
     484          31 :         case 2:
     485          31 :                 msg = IOprintf_(&fmt2, *fmt);
     486          31 :                 break;
     487         103 :         case 3:
     488         103 :                 msg = IOprintf_(&fmt2, *fmt, G(2));
     489         103 :                 break;
     490           4 :         case 4:
     491           4 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3));
     492           4 :                 break;
     493           0 :         case 5:
     494           0 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3), G(4));
     495           0 :                 break;
     496           1 :         case 6:
     497           1 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3), G(4), G(5));
     498           1 :                 break;
     499           0 :         case 7:
     500           0 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3), G(4), G(5), G(6));
     501           0 :                 break;
     502           0 :         case 8:
     503           0 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3), G(4), G(5), G(6), G(7));
     504           0 :                 break;
     505           0 :         case 9:
     506           0 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3), G(4), G(5), G(6), G(7), G(8));
     507           0 :                 break;
     508           0 :         case 10:
     509           0 :                 msg = IOprintf_(&fmt2, *fmt, G(2), G(3), G(4), G(5), G(6), G(7), G(8),
     510           0 :                                                 G(9));
     511           0 :                 break;
     512           0 :         default:
     513           0 :                 throw(MAL, "io.printf", "Too many arguments to io.printf");
     514             :         }
     515         139 :         if (msg == MAL_SUCCEED) {
     516         138 :                 mnstr_printf(cntxt->fdout, "%s", fmt2);
     517         138 :                 GDKfree(fmt2);
     518             :         }
     519             :         return msg;
     520             : }
     521             : 
     522             : static str
     523           0 : IOprintfStream(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     524             : {
     525           0 :         str *fmt = getArgReference_str(stk, pci, 2);
     526           0 :         str fmt2 = NULL;
     527           0 :         stream *f = (stream *) getArgReference(stk, pci, 1);
     528           0 :         str msg = MAL_SUCCEED;
     529             : 
     530           0 :         (void) cntxt;
     531           0 :         (void) mb;
     532           0 :         switch (pci->argc) {
     533           0 :         case 3:
     534           0 :                 msg = IOprintf_(&fmt2, *fmt);
     535           0 :                 break;
     536           0 :         case 4:
     537           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3));
     538           0 :                 break;
     539           0 :         case 5:
     540           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4));
     541           0 :                 break;
     542           0 :         case 6:
     543           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4), G(5));
     544           0 :                 break;
     545           0 :         case 7:
     546           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4), G(5), G(6));
     547           0 :                 break;
     548           0 :         case 8:
     549           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4), G(5), G(6), G(7));
     550           0 :                 break;
     551           0 :         case 9:
     552           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4), G(5), G(6), G(7), G(8));
     553           0 :                 break;
     554           0 :         case 10:
     555           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4), G(5), G(6), G(7), G(8), G(9));
     556           0 :                 break;
     557           0 :         case 11:
     558           0 :                 msg = IOprintf_(&fmt2, *fmt, G(3), G(4), G(5), G(6), G(7), G(8), G(9),
     559           0 :                                                 G(10));
     560           0 :                 break;
     561           0 :         default:
     562           0 :                 throw(MAL, "io.printf", "Too many arguments to io.printf");
     563             :         }
     564           0 :         if (msg == MAL_SUCCEED) {
     565           0 :                 mnstr_printf(f, "%s", fmt2);
     566           0 :                 GDKfree(fmt2);
     567             :         }
     568             :         return msg;
     569             : }
     570             : 
     571             : /*
     572             :  * The table printing routine implementations.
     573             :  * They merely differ in destination and order prerequisite
     574             :  */
     575             : static str
     576          53 : IOtable(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     577             : {
     578          53 :         BAT *piv[MAXPARAMS];
     579          53 :         int i;
     580          53 :         int tpe;
     581          53 :         ptr val;
     582             : 
     583          53 :         (void) cntxt;
     584          53 :         if (pci->retc != 1 || pci->argc < 2 || pci->argc >= MAXPARAMS)
     585           0 :                 throw(MAL, "io.table",
     586             :                           "INTERNAL ERROR" " assertion error  retc %d  argc %d", pci->retc,
     587             :                           pci->argc);
     588             : 
     589          53 :         memset(piv, 0, sizeof(BAT *) * MAXPARAMS);
     590         177 :         for (i = 1; i < pci->argc; i++) {
     591         124 :                 tpe = getArgType(mb, pci, i);
     592         124 :                 val = getArgReference(stk, pci, i);
     593         124 :                 if (!isaBatType(tpe)) {
     594           0 :                         while (--i >= 1)
     595           0 :                                 BBPreclaim(piv[i]);
     596           0 :                         throw(MAL, "io.table", ILLEGAL_ARGUMENT " BAT expected");
     597             :                 }
     598         124 :                 if ((piv[i] = BATdescriptor(*(bat *) val)) == NULL) {
     599           0 :                         while (--i >= 1)
     600           0 :                                 BBPunfix(piv[i]->batCacheid);
     601           0 :                         throw(MAL, "io.table", ILLEGAL_ARGUMENT " null BAT encountered");
     602             :                 }
     603             :         }
     604             :         /* add materialized void column */
     605          53 :         piv[0] = BATdense(piv[1]->hseqbase, 0, BATcount(piv[1]));
     606          53 :         if (piv[0] == NULL) {
     607           0 :                 for (i = 1; i < pci->argc; i++)
     608           0 :                         BBPunfix(piv[i]->batCacheid);
     609           0 :                 throw(MAL, "io.table", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     610             :         }
     611          53 :         BATprintcolumns(cntxt->fdout, pci->argc, piv);
     612         283 :         for (i = 0; i < pci->argc; i++)
     613         177 :                 BBPunfix(piv[i]->batCacheid);
     614             :         return MAL_SUCCEED;
     615             : }
     616             : 
     617             : static str
     618           0 : IOsetmallocsuccesscount(void *res, lng *count)
     619             : {
     620           0 :         (void) res;
     621           0 :         GDKsetmallocsuccesscount(*count);
     622           0 :         return MAL_SUCCEED;
     623             : }
     624             : 
     625             : #include "mel.h"
     626             : mel_func mal_io_init_funcs[] = {
     627             :  pattern("io", "stdin", io_stdin, false, "return the input stream to the database client", args(1,1, arg("",bstream))),
     628             :  pattern("io", "stdout", io_stdout, false, "return the output stream for the database client", args(1,1, arg("",streams))),
     629             :  pattern("io", "print", IOprint_val, false, "Print a MAL value tuple .", args(1,3, arg("",void),argany("val",1),varargany("lst",0))),
     630             :  pattern("io", "print", IOtable, false, "BATs are printed with '#' for legend \nlines, and the BUNs on seperate 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))),
     631             :  pattern("io", "print", IOprint_val, false, "Print a MAL value.", args(1,2, arg("",void),argany("val",1))),
     632             :  pattern("io", "print", IOprint_val, false, "Print a MAL value column .", args(1,2, arg("",void),batargany("val",1))),
     633             :  pattern("io", "printf", IOprintf, false, "Select default format ", args(1,3, arg("",void),arg("fmt",str),varargany("val",0))),
     634             :  pattern("io", "printf", IOprintf, false, "Select default format ", args(1,2, arg("",void),arg("fmt",str))),
     635             :  pattern("io", "printf", IOprintfStream, false, "Select default format ", args(1,4, arg("",void),arg("filep",streams),arg("fmt",str),varargany("val",0))),
     636             :  pattern("io", "printf", IOprintfStream, false, "Select default format ", args(1,3, arg("",void),arg("filep",streams),arg("fmt",str))),
     637             :  command("io", "setmallocsuccesscount", IOsetmallocsuccesscount, false, "Set number of mallocs that are allowed to succeed.", args(1,2, arg("",void),arg("count",lng))),
     638             :  { .imp=NULL }
     639             : };
     640             : #include "mal_import.h"
     641             : #ifdef _MSC_VER
     642             : #undef read
     643             : #pragma section(".CRT$XCU",read)
     644             : #endif
     645         329 : LIB_STARTUP_FUNC(init_mal_io_mal)
     646         329 : { mal_module("mal_io", NULL, mal_io_init_funcs); }

Generated by: LCOV version 1.14