LCOV - code coverage report
Current view: top level - monetdb5/modules/mal - mal_io.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 216 406 53.2 %
Date: 2021-10-13 02:24:04 Functions: 8 12 66.7 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * author N.J. Nes, M.L. Kersten
      11             :  * 01/07/1996, 31/01/2002
      12             :  *
      13             :  * Input/Output module
      14             :  * The IO module provides simple @sc{ascii-io} rendering options.
      15             :  * It is modeled after the tuple formats, but does not
      16             :  * attempt to outline the results. Instead, it is geared at speed,
      17             :  * which also means that some functionality regarding the built-in
      18             :  * types is duplicated from the atoms definitions.
      19             :  *
      20             :  * A functional limited form of formatted printf is also provided.
      21             :  * It accepts at most one variable.
      22             :  * A more complete approach is the tablet module.
      23             :  *
      24             :  * The commands to load and save a BAT from/to an ASCII dump
      25             :  * are efficient, but work only for binary tables.
      26             :  */
      27             : 
      28             : /*
      29             :  * Printing
      30             :  * The print commands are implemented as single instruction rules,
      31             :  * because they need access to the calling context.
      32             :  * At a later stage we can look into the issues related to
      33             :  * parsing the format string as part of the initialization phase.
      34             :  * The old method in V4 essentially causes a lot of overhead
      35             :  * because you have to prepare for the worst (e.g. mismatch format
      36             :  * identifier and argument value)
      37             :  * Beware, the types of the objects to be printed should be
      38             :  * obtained from the stack, because the symbol table may actually
      39             :  * allow for any type to be assigned.
      40             :  */
      41             : #include "monetdb_config.h"
      42             : #include "mal.h"
      43             : #include "mal_instruction.h"
      44             : #include "mal_interpreter.h"
      45             : #include "mutils.h"
      46             : #include "mal_exception.h"
      47             : 
      48             : #define MAXFORMAT 64*1024
      49             : 
      50             : static str
      51           0 : io_stdin(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
      52             : {
      53           0 :         bstream **ret= (bstream**) getArgReference(stk,pci,0);
      54             :         (void) mb;
      55           0 :         if( cntxt->fdin == NULL)
      56           0 :                 throw(MAL, "io.print", SQLSTATE(HY002) "Input channel missing");
      57           0 :         *ret = cntxt->fdin;
      58           0 :         return MAL_SUCCEED;
      59             : }
      60             : 
      61             : static str
      62           0 : io_stdout(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
      63             : {
      64           0 :         stream **ret= (stream**) getArgReference(stk,pci,0);
      65             :         (void) mb;
      66           0 :         if( cntxt->fdout == NULL)
      67           0 :                 throw(MAL, "io.print", SQLSTATE(HY002) "Output channel missing");
      68           0 :         *ret = cntxt->fdout;
      69           0 :         return MAL_SUCCEED;
      70             : }
      71             : 
      72             : static str
      73        1410 : IOprintBoth(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int indx, str hd, str tl, int nobat)
      74             : {
      75        1410 :         int tpe = getArgType(mb, pci, indx);
      76        1410 :         ptr val = getArgReference(stk, pci, indx);
      77        1410 :         stream *fp = cntxt->fdout;
      78             : 
      79             :         (void) mb;
      80        1410 :         if( cntxt->fdout == NULL)
      81           0 :                 throw(MAL, "io.print", SQLSTATE(HY002) "Output channel missing");
      82             : 
      83        1410 :         if (tpe == TYPE_any)
      84           1 :                 tpe = stk->stk[pci->argv[indx]].vtype;
      85        1410 :         if (val == NULL || tpe == TYPE_void) {
      86           2 :                 if (hd)
      87           2 :                         mnstr_printf(fp, "%s", hd);
      88           2 :                 mnstr_printf(fp, "nil");
      89           2 :                 if (tl)
      90           2 :                         mnstr_printf(fp, "%s", tl);
      91           2 :                 return MAL_SUCCEED;
      92             :         }
      93        1408 :         if (isaBatType(tpe) ) {
      94             :                 BAT *b;
      95             : 
      96         652 :                 if (is_bat_nil(*(bat *) val)) {
      97           2 :                         if (hd)
      98           2 :                                 mnstr_printf(fp, "%s", hd);
      99           2 :                         mnstr_printf(fp,"nil");
     100           2 :                         if (tl)
     101           2 :                                 mnstr_printf(fp, "%s", tl);
     102           2 :                         return MAL_SUCCEED;
     103             :                 }
     104         650 :                 b = BATdescriptor(*(bat *) val);
     105         650 :                 if (b == NULL) {
     106           0 :                         throw(MAL, "io.print", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     107             :                 }
     108         650 :                 if (nobat) {
     109           0 :                         if (hd)
     110           0 :                                 mnstr_printf(fp, "%s", hd);
     111           0 :                         mnstr_printf(fp, "<%s>", BBP_logical(b->batCacheid));
     112           0 :                         if (tl)
     113           0 :                                 mnstr_printf(fp, "%s", tl);
     114             :                 } else {
     115         650 :                         BATprint(cntxt->fdout, b);
     116             :                 }
     117         650 :                 BBPunfix(b->batCacheid);
     118         650 :                 return MAL_SUCCEED;
     119             :         }
     120         756 :         if (hd)
     121         756 :                 mnstr_printf(fp, "%s", hd);
     122             : 
     123         756 :         if (ATOMvarsized(tpe))
     124         453 :                 ATOMprint(tpe, *(str *) val, fp);
     125             :         else
     126         303 :                 ATOMprint(tpe, val, fp);
     127             : 
     128         756 :         if (tl)
     129         755 :                 mnstr_printf(fp, "%s", tl);
     130             :         return MAL_SUCCEED;
     131             : }
     132             : 
     133             : static str
     134        1409 : IOprint_val(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     135             : {
     136             :         int i;
     137             :         str msg;
     138             : 
     139             :         (void) cntxt;
     140        1409 :         if (p->argc == 2)
     141        1408 :                 msg = IOprintBoth(cntxt, mb, stk, p, 1, "[ ", " ]\n", 0);
     142             :         else {
     143           1 :                 msg = IOprintBoth(cntxt, mb, stk, p, 1, "[ ", 0, 1);
     144           1 :                 if (msg)
     145             :                         return msg;
     146           1 :                 for (i = 2; i < p->argc - 1; i++)
     147           0 :                         if ((msg = IOprintBoth(cntxt,mb, stk, p, i, ", ", 0, 1)) != NULL)
     148           0 :                                 return msg;
     149           1 :                 msg = IOprintBoth(cntxt,mb, stk, p, i, ", ", "]\n", 1);
     150             :         }
     151             :         return msg;
     152             : 
     153             : }
     154             : 
     155             : /*
     156             :  * The IOprintf_() gets a format str, and a sequence of (ptr,int) parameters
     157             :  * containing values and their type numbers. The printf() proved to be a
     158             :  * great risk; people formatting badly their "%s" format strings were crashing
     159             :  * the kernel. This function will prevent you from doing so.
     160             :  *
     161             :  * New implementation that repeatedly invokes sprintf => hacking the va_alist
     162             :  * for using vfsprintf proved to be too compiler-dependent (OLD approach).
     163             :  */
     164             : #define writemem(X1)                                                                                                    \
     165             :         do {                                                                                                                            \
     166             :                 if (dst+X1 > buf+size) {                                                                             \
     167             :                         ptrdiff_t offset = dst - buf;                                                           \
     168             :                         char *tmp;                                                                                                      \
     169             :                         do {                                                                                                            \
     170             :                                 size *= 2;                                                                                              \
     171             :                         } while (dst+X1 > buf+size);                                                         \
     172             :                         tmp = GDKrealloc(buf, size);                                                            \
     173             :                         if (tmp == NULL) {                                                                                      \
     174             :                                 va_end(ap);                                                                                             \
     175             :                                 GDKfree(buf);                                                                                   \
     176             :                                 GDKfree(add);                                                                                   \
     177             :                                 throw(MAL, "io.printf", SQLSTATE(HY013) MAL_MALLOC_FAIL); \
     178             :                         }                                                                                                                       \
     179             :                         buf = tmp;                                                                                                      \
     180             :                         dst = buf + offset;                                                                                     \
     181             :                 }                                                                                                                               \
     182             :         } while (0)
     183             : 
     184             : #define m5sprintf(X1)\
     185             :         if (width > adds) {\
     186             :                 str newadd;\
     187             :                 newadd = GDKrealloc(add, width + 10);\
     188             :                 if (newadd != NULL) {\
     189             :                         adds = width + 10;\
     190             :                         add = newadd;\
     191             :                 }\
     192             :         }\
     193             :         n = snprintf(add, adds, meta, X1);\
     194             :         while (n < 0 || (size_t) n >= adds) {\
     195             :                 size_t newadds;\
     196             :                 str newadd;\
     197             : \
     198             :                 if (n >= 0)     /* glibc 2.1 */\
     199             :                         newadds = n + 1;   /* precisely what is needed */\
     200             :                 else            /* glibc 2.0 */\
     201             :                         newadds = n * 2;     /* twice the old size */\
     202             : \
     203             :                 newadd = GDKrealloc(add, newadds);\
     204             :                 if (newadd == NULL)\
     205             :                         break;\
     206             : \
     207             :                 adds = newadds;\
     208             :                 add = newadd;\
     209             :                 n = snprintf(add, adds, meta, X1);\
     210             :         }
     211             : 
     212             : 
     213             : static char toofew_error[80] = OPERATION_FAILED " At least %d parameter(s) expected.\n";
     214             : static char format_error[80] = OPERATION_FAILED " Error in format before param %d.\n";
     215             : static char type_error[80] = OPERATION_FAILED " Illegal type in param %d.\n";
     216             : 
     217             : #define return_error(x)                                                 \
     218             :         do {                                                                            \
     219             :                 GDKfree(buf);                                                   \
     220             :                 GDKfree(add);                                                   \
     221             :                 throw(MAL,"io.printf", x,argc);                       \
     222             :         } while (0)
     223             : 
     224             : static char niltext[4] = "nil";
     225             : 
     226             : static str
     227         162 : IOprintf_(str *res, str format, ...)
     228             : {
     229             :         va_list ap;
     230             :         int n;
     231             : 
     232             :         int prec = 0, dotseen = 0, escaped = 0, type, size, argc = 1;
     233             :         size_t adds = 100, width = 0;
     234             :         char *add, *dst, *buf, *cur, *paramseen = NULL;
     235             :         char *p;
     236             : 
     237         162 :         if (format == NULL) {
     238           0 :                 throw(MAL,"io.printf", ILLEGAL_ARGUMENT " NULL pointer passed as format.\n");
     239         162 :         } else if (strchr(format, '%') == NULL) {
     240          43 :                 *res = GDKstrdup(format);
     241          43 :                 if (*res == NULL)
     242           0 :                         throw(MAL,"io.printf", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     243             :                 return MAL_SUCCEED;
     244             :         }
     245         119 :         buf = dst = (str) GDKmalloc(size = 80);
     246         119 :         if ( buf == NULL)
     247           0 :                 throw(MAL,"io.printf", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     248         119 :         *res = NULL;
     249             : 
     250         119 :         add = GDKmalloc(adds);
     251         119 :         if (add == NULL) {
     252           0 :                 GDKfree(buf);
     253           0 :                 throw(MAL,"io.printf", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     254             :         }
     255             : 
     256         119 :         va_start(ap,format);
     257        1480 :         for (cur = format; *cur; cur++) {
     258        1362 :                 if (paramseen) {
     259             :                         char meta[100];
     260             :                         ptrdiff_t extra = 0;
     261             :                         ptrdiff_t len;
     262             : 
     263         141 :                         if (GDKisdigit(*cur)) {
     264          10 :                                 if (dotseen) {
     265           2 :                                         prec = 10 * prec + (*cur - '0');
     266             :                                 } else {
     267           8 :                                         width = 10 * width + (*cur - '0');
     268             :                                 }
     269          15 :                                 continue;
     270         131 :                         } else if (dotseen == 0 && *cur == '.') {
     271             :                                 dotseen = 1;
     272           2 :                                 continue;
     273         129 :                         } else if (cur == paramseen + 1 && (*cur == '+' || *cur == '-' || *cur == ' ')) {
     274           3 :                                 continue;
     275         126 :                         } else if (*cur == 'l') {
     276           0 :                                 cur++;
     277           0 :                                 if (*cur == 'l') {
     278           0 :                                         cur++;
     279             :                                         /* start of ll */
     280           0 :                                         extra = (cur - paramseen) - 2;
     281             :                                 }
     282             :                         }
     283         126 :                         if ((p = va_arg(ap, char *)) == NULL) {
     284           1 :                                 va_end(ap);
     285           1 :                                 return_error(toofew_error);
     286             :                         }
     287         125 :                         type = va_arg(ap, int);
     288         125 :                         type = ATOMbasetype(type);
     289             : 
     290         125 :                         len = 1 + (cur - paramseen);
     291         125 :                         memcpy(meta, paramseen, len);
     292         125 :                         meta[len] = 0;
     293         125 :                         if (ATOMcmp(type, ATOMnilptr(type), p) == 0) {
     294             :                                 /* value is nil; attempt to print formatted 'nil'
     295             :                                    without generating %ls etc. */
     296             :                                 char *csrc, *ctrg = meta;
     297             : 
     298          39 :                                 for (csrc = paramseen; csrc < cur; csrc++) {
     299          23 :                                         if (*csrc == '.')
     300             :                                                 break;
     301          22 :                                         if (GDKisdigit(*csrc) || *csrc == '-')
     302           4 :                                                 *(++ctrg) = *csrc;
     303             :                                 }
     304          17 :                                 *(++ctrg) = 's';
     305          17 :                                 *(++ctrg) = 0;
     306          17 :                                 m5sprintf(niltext);
     307         108 :                         } else if (strchr("cdiouxX", *cur) && !extra) {
     308             :                                 int ival;
     309             : 
     310          82 :                                 if (dotseen) {
     311           0 :                                         va_end(ap);
     312           0 :                                         return_error(format_error);
     313          82 :                                 } else if (type == TYPE_bte) {
     314           3 :                                         ival = (int) *(bte *) p;
     315          79 :                                 } else if (type == TYPE_sht) {
     316           0 :                                         ival = (int) *(sht *) p;
     317          79 :                                 } else if (type == TYPE_flt) {
     318           0 :                                         ival = (int) *(flt *) p;
     319          79 :                                 } else if (type == TYPE_lng) {
     320          23 :                                         goto largetypes;
     321             : #ifdef HAVE_HGE
     322          56 :                                 } else if (type == TYPE_hge) {
     323             :                                         /* Does this happen?
     324             :                                          * If so, what do we have TODO ? */
     325           0 :                                         va_end(ap);
     326           0 :                                         return_error(type_error);
     327             : #endif
     328          56 :                                 } else if (type == TYPE_int) {
     329          56 :                                         ival = *(int *) p;
     330             :                                 } else {
     331           0 :                                         va_end(ap);
     332           0 :                                         return_error(type_error);
     333             :                                 }
     334          59 :                                 m5sprintf(ival);
     335          26 :                         } else if (strchr("diouxX", *cur)) {
     336             : #ifdef NATIVE_WIN32
     337             :                                 ptrdiff_t i;
     338             : #endif
     339             :                                 lng lval;
     340             : 
     341           0 :                                 if (dotseen) {
     342           0 :                                         va_end(ap);
     343           0 :                                         return_error(format_error);
     344             :                                 }
     345           0 :                         largetypes:
     346          23 :                                 if (type == TYPE_bte) {
     347           0 :                                         lval = (lng) *(bte *) p;
     348          23 :                                 } else if (type == TYPE_sht) {
     349           0 :                                         lval = (lng) *(sht *) p;
     350          23 :                                 } else if (type == TYPE_int) {
     351           0 :                                         lval = (lng) *(int *) p;
     352          23 :                                 } else if (type == TYPE_flt) {
     353           0 :                                         lval = (lng) *(flt *) p;
     354          23 :                                 } else if (type == TYPE_dbl) {
     355           0 :                                         lval = (lng) *(dbl *) p;
     356          23 :                                 } else if (type == TYPE_lng) {
     357          23 :                                         lval = *(lng *) p;
     358             : #ifdef HAVE_HGE
     359           0 :                                 } else if (type == TYPE_hge) {
     360             :                                         /* Does this happen?
     361             :                                          * If so, what do we have TODO ? */
     362           0 :                                         va_end(ap);
     363           0 :                                         return_error(type_error);
     364             : #endif
     365             :                                 } else {
     366           0 :                                         va_end(ap);
     367           0 :                                         return_error(type_error);
     368             :                                 }
     369          23 :                                 if (!extra) {
     370          23 :                                         meta[len + 2] = meta[len];
     371          23 :                                         meta[len + 1] = meta[len - 1];
     372          23 :                                         meta[len] = 'l';
     373          23 :                                         meta[len - 1] = 'l';
     374             :                                         len += 2;
     375             :                                         extra = len - 3;
     376             :                                 }
     377             : #ifdef NATIVE_WIN32
     378             :                                 for (i = len; i >= (extra + 2); i--) {
     379             :                                         meta[i + 1] = meta[i];
     380             :                                 }
     381             :                                 meta[extra] = 'I';
     382             :                                 meta[extra + 1] = '6';
     383             :                                 meta[extra + 2] = '4';
     384             : #endif
     385          23 :                                 m5sprintf(lval);
     386          26 :                         } else if (strchr("feEgG", *cur)) {
     387             :                                 dbl dval;
     388             : 
     389           2 :                                 if (type == TYPE_flt) {
     390           2 :                                         dval = (dbl) *(flt *) p;
     391           0 :                                 } else if (type == TYPE_dbl) {
     392           0 :                                         dval = *(dbl *) p;
     393             :                                 } else {
     394           0 :                                         va_end(ap);
     395           0 :                                         return_error(type_error);
     396             :                                 }
     397           2 :                                 width += (1 + prec);
     398           2 :                                 m5sprintf(dval);
     399          24 :                         } else if (*cur == 's') {
     400             :                                 size_t length;
     401             : 
     402          24 :                                 if (extra) {
     403           0 :                                         va_end(ap);
     404           0 :                                         return_error(format_error);
     405          24 :                                 } else if (type != TYPE_str) {
     406           0 :                                         va_end(ap);
     407           0 :                                         return_error(type_error);
     408             :                                 }
     409          24 :                                 length = strLen(p);
     410          24 :                                 width++;
     411          24 :                                 prec++; /* account for '\0' */
     412          24 :                                 if (dotseen && (size_t) prec < length)
     413             :                                         length = (size_t) prec;
     414             :                                 if (length > width)
     415             :                                         width = length;
     416          25 :                                 m5sprintf(p);
     417             :                         } else {
     418           0 :                                 va_end(ap);
     419           0 :                                 return_error(format_error);
     420             :                         }
     421         125 :                         width = strlen(add);
     422         125 :                         writemem(width);
     423         125 :                         memcpy(dst, add, width);
     424         125 :                         dst += width;
     425             :                         paramseen = NULL;
     426         125 :                         argc++;
     427        1221 :                 } else if (!escaped) {
     428        1221 :                         if (*cur == '\\' || (*cur == '%' && cur[1] == '%')) {
     429             :                                 escaped = 1;
     430        1221 :                         } else if (*cur == '%') {
     431             :                                 paramseen = cur;
     432             :                                 dotseen = prec = 0;
     433             :                                 width = 0;
     434             :                         } else {
     435        1095 :                                 writemem(1);
     436        1095 :                                 *dst++ = *cur;
     437             :                         }
     438             :                 } else {
     439             :                         escaped = 0;
     440           0 :                         writemem(1);
     441           0 :                         *dst++ = *cur;
     442             :                 }
     443             :         }
     444             : 
     445             : /*
     446             :         if ( va_arg(ap, char *) != NULL){
     447             :                 GDKfree(buf);
     448             :                 throw(MAL,"io.printf", "params %d and beyond ignored %s.\n",argc);
     449             :         }
     450             : */
     451             : 
     452         118 :         writemem(1);
     453         118 :         va_end(ap);
     454         118 :         *dst = 0;
     455         118 :         *res = buf;
     456         118 :         GDKfree(add);
     457         118 :         return MAL_SUCCEED;
     458             : }
     459             : 
     460             : #define getArgValue(s,p,k) VALptr(&(s)->stk[(p)->argv[k]])
     461             : 
     462             : #define G(X) getArgValue(stk,pci,X), getArgType(mb,pci,X)
     463             : 
     464             : static str
     465         162 : IOprintf(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     466             : {
     467         162 :         str *fmt = getArgReference_str(stk,pci,1);
     468         162 :         str fmt2 = NULL;
     469             :         str msg= MAL_SUCCEED;
     470             : 
     471             :         (void) cntxt;
     472             :         (void) mb;
     473         162 :         switch( pci->argc){
     474          43 :         case 2: msg= IOprintf_(&fmt2,*fmt);
     475          43 :                         break;
     476         114 :         case 3: msg= IOprintf_(&fmt2,*fmt,G(2));
     477         114 :                 break;
     478           4 :         case 4: msg= IOprintf_(&fmt2,*fmt,G(2),G(3));
     479           4 :                 break;
     480           0 :         case 5: msg= IOprintf_(&fmt2,*fmt,G(2),G(3),G(4));
     481           0 :                 break;
     482           1 :         case 6: msg= IOprintf_(&fmt2,*fmt,G(2),G(3),G(4),G(5));
     483           1 :                 break;
     484           0 :         case 7: msg= IOprintf_(&fmt2,*fmt,G(2),G(3),G(4),G(5),G(6));
     485           0 :                 break;
     486           0 :         case 8: msg= IOprintf_(&fmt2,*fmt,G(2),G(3),G(4),G(5),G(6),G(7));
     487           0 :                 break;
     488           0 :         case 9: msg= IOprintf_(&fmt2,*fmt,G(2),G(3),G(4),G(5),G(6),G(7),G(8));
     489           0 :                 break;
     490           0 :         case 10: msg= IOprintf_(&fmt2,*fmt,G(2),G(3),G(4),G(5),G(6),G(7),G(8),G(9));
     491           0 :                 break;
     492           0 :         default:
     493           0 :                 throw(MAL, "io.printf", "Too many arguments to io.printf");
     494             :         }
     495         162 :         if (msg== MAL_SUCCEED) {
     496         161 :                 mnstr_printf(cntxt->fdout,"%s",fmt2);
     497         161 :                 GDKfree(fmt2);
     498             :         }
     499             :         return msg;
     500             : }
     501             : static str
     502           0 : IOprintfStream(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci){
     503           0 :         str *fmt = getArgReference_str(stk,pci,2);
     504           0 :         str fmt2 = NULL;
     505           0 :         stream *f= (stream *) getArgReference(stk,pci,1);
     506             :         str msg= MAL_SUCCEED;
     507             : 
     508             :         (void) cntxt;
     509             :         (void) mb;
     510           0 :         switch( pci->argc){
     511           0 :         case 3: msg= IOprintf_(&fmt2,*fmt);
     512           0 :                 break;
     513           0 :         case 4: msg= IOprintf_(&fmt2,*fmt,G(3));
     514           0 :                 break;
     515           0 :         case 5: msg= IOprintf_(&fmt2,*fmt,G(3),G(4));
     516           0 :                 break;
     517           0 :         case 6: msg= IOprintf_(&fmt2,*fmt,G(3),G(4),G(5));
     518           0 :                 break;
     519           0 :         case 7: msg= IOprintf_(&fmt2,*fmt,G(3),G(4),G(5),G(6));
     520           0 :                 break;
     521           0 :         case 8: msg= IOprintf_(&fmt2,*fmt,G(3),G(4),G(5),G(6),G(7));
     522           0 :                 break;
     523           0 :         case 9: msg= IOprintf_(&fmt2,*fmt,G(3),G(4),G(5),G(6),G(7),G(8));
     524           0 :                 break;
     525           0 :         case 10: msg= IOprintf_(&fmt2,*fmt,G(3),G(4),G(5),G(6),G(7),G(8),G(9));
     526           0 :                 break;
     527           0 :         case 11: msg= IOprintf_(&fmt2,*fmt,G(3),G(4),G(5),G(6),G(7),G(8),G(9),G(10));
     528           0 :                 break;
     529           0 :         default:
     530           0 :                 throw(MAL, "io.printf", "Too many arguments to io.printf");
     531             :         }
     532           0 :         if (msg== MAL_SUCCEED){
     533           0 :                 mnstr_printf(f,"%s",fmt2);
     534           0 :                 GDKfree(fmt2);
     535             :         }
     536             :         return msg;
     537             : }
     538             : 
     539             : /*
     540             :  * The table printing routine implementations.
     541             :  * They merely differ in destination and order prerequisite
     542             :  */
     543             : static str
     544          55 : IOtable(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     545             : {
     546             :         BAT *piv[MAXPARAMS];
     547             :         int i;
     548             :         int tpe;
     549             :         ptr val;
     550             : 
     551             :         (void) cntxt;
     552          55 :         if ( pci->retc != 1 || pci->argc < 2 || pci->argc >= MAXPARAMS)
     553           0 :                 throw(MAL, "io.table", "INTERNAL ERROR" " assertion error  retc %d  argc %d", pci->retc, pci->argc);
     554             : 
     555          55 :         memset(piv, 0, sizeof(BAT*) * MAXPARAMS);
     556         183 :         for (i = 1; i < pci->argc; i++) {
     557         128 :                 tpe = getArgType(mb, pci, i);
     558         128 :                 val = getArgReference(stk, pci, i);
     559         128 :                 if (!isaBatType(tpe)) {
     560           0 :                         while (--i >= 1)
     561           0 :                                 if (piv[i] != NULL)
     562           0 :                                         BBPunfix(piv[i]->batCacheid);
     563           0 :                         throw(MAL, "io.table", ILLEGAL_ARGUMENT " BAT expected");
     564             :                 }
     565         128 :                 if ((piv[i] = BATdescriptor(*(bat *) val)) == NULL) {
     566           0 :                         while (--i >= 1)
     567           0 :                                 BBPunfix(piv[i]->batCacheid);
     568           0 :                         throw(MAL, "io.table", ILLEGAL_ARGUMENT " null BAT encountered");
     569             :                 }
     570             :         }
     571             :         /* add materialized void column */
     572          55 :         piv[0] = BATdense(piv[1]->hseqbase, 0, BATcount(piv[1]));
     573          55 :         if (piv[0] == NULL) {
     574           0 :                 for (i = 1; i < pci->argc; i++)
     575           0 :                         BBPunfix(piv[i]->batCacheid);
     576           0 :                 throw(MAL, "io.table", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     577             :         }
     578          55 :         BATprintcolumns(cntxt->fdout, pci->argc, piv);
     579         238 :         for (i = 0; i < pci->argc; i++)
     580         183 :                 BBPunfix(piv[i]->batCacheid);
     581             :         return MAL_SUCCEED;
     582             : }
     583             : 
     584             : 
     585             : /*
     586             :  * Bulk export/loading
     587             :  * To simplify conversion between versions and to interface with other
     588             :  * applications, we use a simple import/export operation.
     589             :  *
     590             :  * The conversion routine assumes space in the buffer for storing the result.
     591             :  */
     592             : /*
     593             :  * A BAT can be saved in Monet format using the export command.
     594             :  * It is of particular use in preparing an ASCII version for migration.
     595             :  * The exported file is saved in the context of the directory
     596             :  * where the server was started unless an absolute file name was
     597             :  * presented.
     598             :  */
     599             : 
     600             : static str
     601           1 : IOexport(void *ret, bat *bid, str *fnme)
     602             : {
     603             :         BAT *b;
     604             :         stream *s;
     605             : 
     606             :         (void) ret;
     607           1 :         if ((b = BATdescriptor(*bid)) == NULL)
     608           0 :                 throw(MAL, "io.export", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     609             : 
     610           1 :         s = open_wastream(*fnme);
     611           1 :         if (s == NULL ){
     612           0 :                 BBPunfix(b->batCacheid);
     613           0 :                 throw(MAL, "io.export", "%s", mnstr_peek_error(NULL));
     614             :         }
     615           1 :         if (mnstr_errnr(s)) {
     616           0 :                 mnstr_close(s);
     617           0 :                 BBPunfix(b->batCacheid);
     618           0 :                 throw(MAL, "io.export", "%s", mnstr_peek_error(NULL));
     619             :         }
     620           1 :     BATprintcolumns(s, 1, &b);
     621           1 :         close_stream(s);
     622           1 :         BBPunfix(b->batCacheid);
     623           1 :         return MAL_SUCCEED;
     624             : }
     625             : 
     626             : /*
     627             :  * The import command reads a single BAT from an ASCII file produced by export.
     628             :  */
     629             : static str
     630           1 : IOimport(void *ret, bat *bid, str *fnme)
     631             : {
     632             :         BAT *b;
     633             :         ssize_t (*tconvert) (const char *, size_t *, ptr *, bool);
     634             :         ssize_t n;
     635             :         size_t bufsize = 2048;  /* NIELS:tmp change used to be 1024 */
     636             :         char *base, *cur, *end;
     637             :         char *buf;
     638           1 :         ptr t = 0;
     639           1 :         size_t lt = 0;
     640           1 :         FILE *fp = MT_fopen(*fnme, "r");
     641             :         char msg[BUFSIZ];
     642             : 
     643             :         (void) ret;
     644           1 :         if ((b = BATdescriptor(*bid)) == NULL) {
     645           0 :                 if (fp)
     646           0 :                         fclose(fp);
     647           0 :                 throw(MAL, "io.import", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     648             :         }
     649             : 
     650           1 :         tconvert = BATatoms[BATttype(b)].atomFromStr;
     651             :         /*
     652             :          * Open the file. Memory map it to minimize buffering problems.
     653             :          */
     654           1 :         if (fp == NULL) {
     655           0 :                 BBPunfix(b->batCacheid);
     656           0 :                 throw(MAL, "io.import", RUNTIME_FILE_NOT_FOUND ":%s", *fnme);
     657             :         } else {
     658             :                 int fn;
     659             :                 struct stat st;
     660             : 
     661           1 :                 buf = (char *) GDKmalloc(bufsize);
     662           1 :                 if ( buf == NULL) {
     663           0 :                         BBPunfix(b->batCacheid);
     664           0 :                         fclose(fp);
     665           0 :                         throw(MAL,"io.import", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     666             :                 }
     667             : 
     668           1 :                 if ((fn = fileno(fp)) <= 0) {
     669           0 :                         BBPunfix(b->batCacheid);
     670           0 :                         fclose(fp);
     671           0 :                         GDKfree(buf);
     672           0 :                         throw(MAL, "io.import", OPERATION_FAILED ": fileno()");
     673             :                 }
     674           1 :                 if (fstat(fn, &st) != 0) {
     675           0 :                         BBPunfix(b->batCacheid);
     676           0 :                         fclose(fp);
     677           0 :                         GDKfree(buf);
     678           0 :                         throw(MAL, "io.import", OPERATION_FAILED ": fstat()");
     679             :                 }
     680             : 
     681           1 :                 (void) fclose(fp);
     682           1 :                 if (st.st_size <= 0) {
     683           0 :                         BBPunfix(b->batCacheid);
     684           0 :                         GDKfree(buf);
     685           0 :                         throw(MAL, "io.import", OPERATION_FAILED ": empty file");
     686             :                 }
     687             : #if SIZEOF_SIZE_T == SIZEOF_INT
     688             :                 if (st.st_size > 0x7FFFFFFF) {
     689             :                         BBPunfix(b->batCacheid);
     690             :                         GDKfree(buf);
     691             :                         throw(MAL, "io.import", OPERATION_FAILED ": file too large");
     692             :                 }
     693             : #endif
     694           1 :                 base = cur = (char *) GDKmmap(*fnme, MMAP_SEQUENTIAL, (size_t) st.st_size);
     695           1 :                 if (cur == NULL) {
     696           0 :                         BBPunfix(b->batCacheid);
     697           0 :                         GDKfree(buf);
     698           0 :                         throw(MAL, "io.import", OPERATION_FAILED "GDKmmap()");
     699             :                 }
     700           1 :                 end = cur + st.st_size;
     701             : 
     702             :         }
     703             :         /* Parse a line. Copy it into a buffer. Concat broken lines with a slash.  */
     704           7 :         while (cur < end) {
     705             :                 str dst = buf, src = cur, p;
     706             :                 size_t l;
     707             : 
     708             :                 /* like p = strchr(cur, '\n') but with extra bounds check */
     709         115 :                 for (p = cur; p < end && *p != '\n'; p++)
     710             :                         ;
     711           6 :                 l = p - cur;
     712             : 
     713           6 :                 if (p < end) {
     714           6 :                         while (src[l - 1] == '\\') {
     715           0 :                                 if (buf+bufsize < dst+l) {
     716           0 :                                         size_t len = dst - buf;
     717           0 :                                         size_t inc = (size_t) ((dst+l) - buf);
     718           0 :                                         char *tmp = GDKrealloc(buf, bufsize = MAX(inc,bufsize)*2);
     719           0 :                                         if (tmp == NULL) {
     720           0 :                                                 BBPunfix(b->batCacheid);
     721           0 :                                                 GDKfree(buf);
     722           0 :                                                 GDKfree(t);
     723           0 :                                                 GDKmunmap(base, end - base);
     724           0 :                                                 throw(MAL, "io.import", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     725             :                                         }
     726             :                                         buf = tmp;
     727           0 :                                         dst = buf + len;
     728             :                                 }
     729           0 :                                 memcpy(dst, src, l-1);
     730           0 :                                 dst += l - 1;
     731           0 :                                 src += l + 1;
     732           0 :                                 for (p = src; p < end && *p != '\n'; p++)
     733             :                                         ;
     734           0 :                                 if (p == end)
     735             :                                         break;
     736           0 :                                 l = p - src;
     737             :                         }
     738             :                 }
     739             : 
     740           6 :                 if (buf+bufsize < dst+l) {
     741           0 :                         size_t len = dst - buf;
     742           0 :                         size_t inc = (size_t) ((dst+l) - buf);
     743           0 :                         char *tmp = GDKrealloc(buf, bufsize = MAX(inc,bufsize)*2);
     744           0 :                         if (tmp == NULL) {
     745           0 :                                 BBPunfix(b->batCacheid);
     746           0 :                                 GDKfree(buf);
     747           0 :                                 GDKfree(t);
     748           0 :                                 GDKmunmap(base, end - base);
     749           0 :                                 throw(MAL, "io.import", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     750             :                         }
     751             :                         buf = tmp;
     752           0 :                         dst = buf + len;
     753             :                 }
     754           6 :                 memcpy(dst, src, l);
     755           6 :                 dst[l] = 0;
     756           6 :                 cur = p + 1;
     757             :                 /* Parse the line, and insert a BUN.  */
     758           6 :                 for (p = buf; *p && GDKisspace(*p); p++)
     759             :                         ;
     760           6 :                 if (*p == '#')
     761           4 :                         continue;
     762             : 
     763           2 :                 for (;*p && *p != '['; p++)
     764             :                         ;
     765           2 :                 if (*p)
     766           4 :                         for (p++; *p && GDKisspace(*p); p++)
     767             :                                 ;
     768           2 :                 if (*p == 0) {
     769           0 :                         BBPunfix(b->batCacheid);
     770           0 :                         snprintf(msg,sizeof(msg),"error in input %s",buf);
     771           0 :                         GDKfree(buf);
     772           0 :                         GDKmunmap(base, end - base);
     773           0 :                         GDKfree(t);
     774           0 :                         throw(MAL, "io.import", "%s", msg);
     775             :                 }
     776           2 :                 n = tconvert(p, &lt, (ptr*)&t, true);
     777           2 :                 if (n < 0) {
     778           0 :                         BBPunfix(b->batCacheid);
     779           0 :                         snprintf(msg,sizeof(msg),"error in input %s",buf);
     780           0 :                         GDKfree(buf);
     781           0 :                         GDKmunmap(base, end - base);
     782           0 :                         GDKfree(t);
     783           0 :                         throw(MAL, "io.import", "%s", msg);
     784             :                 }
     785             :                 p += n;
     786           2 :                 if (BUNappend(b, t, false) != GDK_SUCCEED) {
     787           0 :                         BBPunfix(b->batCacheid);
     788           0 :                         GDKfree(buf);
     789           0 :                         GDKfree(t);
     790           0 :                         GDKmunmap(base, end - base);
     791           0 :                         throw(MAL, "io.import", "insert failed");
     792             :                 }
     793             : 
     794             : #if 0                                                   /* why do this? any measured effects? */
     795             : /*
     796             :  * Unmap already parsed memory, to keep the memory usage low.
     797             :  */
     798             : #ifndef WIN32
     799             : #define MAXBUF 40*MT_pagesize()
     800             :                 if ((unsigned) (cur - base) > MAXBUF) {
     801             :                         GDKmunmap(base, MAXBUF);
     802             :                         base += MAXBUF;
     803             :                 }
     804             : #endif
     805             : #endif
     806             :         }
     807             :         /* Cleanup and exit. Return the filled BAT.  */
     808           1 :         if (t)
     809           1 :                 GDKfree(t);
     810           1 :         GDKfree(buf);
     811           1 :         GDKmunmap(base, end - base);
     812           1 :         BBPunfix(b->batCacheid);
     813           1 :         return MAL_SUCCEED;
     814             : }
     815             : 
     816             : 
     817             : 
     818             : static str
     819           0 : IOsetmallocsuccesscount(void *res, lng *count) {
     820             :         (void) res;
     821           0 :         GDKsetmallocsuccesscount(*count);
     822           0 :         return MAL_SUCCEED;
     823             : }
     824             : 
     825             : #include "mel.h"
     826             : mel_func mal_io_init_funcs[] = {
     827             :  pattern("io", "stdin", io_stdin, false, "return the input stream to the database client", args(1,1, arg("",bstream))),
     828             :  pattern("io", "stdout", io_stdout, false, "return the output stream for the database client", args(1,1, arg("",streams))),
     829             :  pattern("io", "print", IOprint_val, false, "Print a MAL value tuple .", args(1,3, arg("",void),argany("val",1),varargany("lst",0))),
     830             :  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))),
     831             :  pattern("io", "print", IOprint_val, false, "Print a MAL value.", args(1,2, arg("",void),argany("val",1))),
     832             :  pattern("io", "print", IOprint_val, false, "Print a MAL value column .", args(1,2, arg("",void),batargany("val",1))),
     833             :  pattern("io", "printf", IOprintf, false, "Select default format ", args(1,3, arg("",void),arg("fmt",str),varargany("val",0))),
     834             :  pattern("io", "printf", IOprintf, false, "Select default format ", args(1,2, arg("",void),arg("fmt",str))),
     835             :  pattern("io", "printf", IOprintfStream, false, "Select default format ", args(1,4, arg("",void),arg("filep",streams),arg("fmt",str),varargany("val",0))),
     836             :  pattern("io", "printf", IOprintfStream, false, "Select default format ", args(1,3, arg("",void),arg("filep",streams),arg("fmt",str))),
     837             :  command("io", "export", IOexport, false, "Export a BAT as ASCII to a file. If the 'filepath' is not absolute, it\nis put into the $DBPATH directory. Success of failure is indicated.", args(0,2, batargany("b",2),arg("filepath",str))),
     838             :  command("io", "import", IOimport, false, "Import a BAT from an ASCII dump. The tuples are appended to the\nfirst argument. Its signature must match the dump,\nelse parsing errors will occur as an exception.", args(0,2, batargany("b",2),arg("filepath",str))),
     839             :  command("io", "setmallocsuccesscount", IOsetmallocsuccesscount, false, "Set number of mallocs that are allowed to succeed.", args(1,2, arg("",void),arg("count",lng))),
     840             :  { .imp=NULL }
     841             : };
     842             : #include "mal_import.h"
     843             : #ifdef _MSC_VER
     844             : #undef read
     845             : #pragma section(".CRT$XCU",read)
     846             : #endif
     847         259 : LIB_STARTUP_FUNC(init_mal_io_mal)
     848         259 : { mal_module("mal_io", NULL, mal_io_init_funcs); }

Generated by: LCOV version 1.14