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