LCOV - code coverage report
Current view: top level - monetdb5/modules/mal - mal_io.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 182 360 50.6 %
Date: 2021-01-13 20:07:21 Functions: 7 11 63.6 %

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

Generated by: LCOV version 1.14