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 - 2019 MonetDB B.V. |
7 | */ |
8 | |
9 | /* |
10 | * (author) M. Kersten 2015 |
11 | */ |
12 | |
13 | #include "monetdb_config.h" |
14 | #include "mal_instruction.h" |
15 | #include "mal_function.h" /* for getPC() */ |
16 | #include "mal_utils.h" |
17 | #include "mal_exception.h" |
18 | #include "mal_listing.h" |
19 | |
20 | /* |
21 | * Since MAL programs can be created on the fly by linked-in query |
22 | * compilers, or transformed by optimizers, it becomes |
23 | * mandatory to be able to produce textual correct MAL programs |
24 | * from its internal representation for several purposes. |
25 | * |
26 | * Whenever there is an overriding property it is applied. |
27 | * |
28 | * The hiddenInstruction operator assumes a sufficiently large block |
29 | * to leave information on the signature behind. |
30 | * |
31 | * The protection against overflow is not tight. |
32 | */ |
33 | #define advance(X,B,L) while(*(X) && B+L>X)(X)++; |
34 | |
35 | /* Copy string in src to *dstp which has *lenp space available and |
36 | * terminate with a NULL byte. *dstp and *lenp are adjusted for the |
37 | * used space. If there is not enough space to copy all of src, |
38 | * return false, otherwise return true. The resulting string is |
39 | * always NULL-terminated. */ |
40 | static inline bool |
41 | copystring(char **dstp, const char *src, size_t *lenp) |
42 | { |
43 | size_t len = *lenp; |
44 | char *dst = *dstp; |
45 | |
46 | if (src == NULL) |
47 | return true; |
48 | if (len > 0) { |
49 | while (*src && len > 1) { |
50 | *dst++ = *src++; |
51 | len--; |
52 | } |
53 | *dst = 0; |
54 | *dstp = dst; |
55 | *lenp = len; |
56 | } |
57 | return *src == 0; |
58 | } |
59 | |
60 | static str |
61 | renderTerm(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int idx, int flg) |
62 | { |
63 | char *buf =0; |
64 | char *nme =0; |
65 | int nameused = 0; |
66 | size_t len = 0, maxlen = BUFSIZ; |
67 | ValRecord *val = 0; |
68 | char *cv =0; |
69 | str tpe; |
70 | int showtype = 0, closequote=0; |
71 | int varid = getArg(p,idx); |
72 | |
73 | buf = GDKzalloc(maxlen); |
74 | if( buf == NULL) { |
75 | addMalException(mb, "renderTerm:Failed to allocate" ); |
76 | return NULL; |
77 | } |
78 | // show the name when required or is used |
79 | if ((flg & LIST_MAL_NAME) && !isVarConstant(mb,varid) && !isVarTypedef(mb,varid)) { |
80 | nme = getVarName(mb,varid); |
81 | len +=snprintf(buf, maxlen, "%s" , nme); |
82 | nameused =1; |
83 | } |
84 | // show the value when required or being a constant |
85 | if( ((flg & LIST_MAL_VALUE) && stk != 0) || isVarConstant(mb,varid) ){ |
86 | if (nameused){ |
87 | strcat(buf + len,"=" ); |
88 | len++; |
89 | } |
90 | |
91 | // locate value record |
92 | if (isVarConstant(mb,varid)){ |
93 | val = &getVarConstant(mb, varid); |
94 | showtype= getVarType(mb,varid) != TYPE_str && getVarType(mb,varid) != TYPE_bit; |
95 | } else if( stk) |
96 | val = &stk->stk[varid]; |
97 | |
98 | if ((cv = VALformat(val)) == NULL) { |
99 | addMalException(mb, "renderTerm:Failed to allocate" ); |
100 | GDKfree(buf); |
101 | return NULL; |
102 | } |
103 | if (len + strlen(cv) >= maxlen) { |
104 | char *nbuf= GDKrealloc(buf, maxlen =len + strlen(cv) + BUFSIZ); |
105 | |
106 | if( nbuf == 0){ |
107 | GDKfree(buf); |
108 | GDKfree(cv); |
109 | addMalException(mb,"renderTerm:Failed to allocate" ); |
110 | return NULL; |
111 | } |
112 | buf = nbuf; |
113 | } |
114 | |
115 | if( strcmp(cv,"nil" ) == 0){ |
116 | strcat(buf+len,cv); |
117 | len += strlen(buf+len); |
118 | GDKfree(cv); |
119 | showtype = showtype || getBatType(getVarType(mb,varid)) > TYPE_str || |
120 | ((isVarUDFtype(mb,varid) || isVarTypedef(mb,varid)) && isVarConstant(mb,varid)) || isaBatType(getVarType(mb,varid)); |
121 | } else{ |
122 | if ( !isaBatType(getVarType(mb,varid)) && getBatType(getVarType(mb,varid)) > TYPE_str ){ |
123 | closequote = 1; |
124 | strcat(buf+len,"\"" ); |
125 | len++; |
126 | } |
127 | strcat(buf+len,cv); |
128 | len += strlen(buf+len); |
129 | GDKfree(cv); |
130 | |
131 | if( closequote ){ |
132 | strcat(buf+len,"\"" ); |
133 | len++; |
134 | } |
135 | showtype = showtype || closequote > TYPE_str || ((isVarUDFtype(mb,varid) || isVarTypedef(mb,varid) || (flg & (LIST_MAL_REMOTE | LIST_MAL_TYPE))) && isVarConstant(mb,varid)) || |
136 | (isaBatType(getVarType(mb,varid)) && idx < p->retc); |
137 | |
138 | if (stk && isaBatType(getVarType(mb,varid)) && stk->stk[varid].val.bval ){ |
139 | BAT *d= BBPquickdesc(stk->stk[varid].val.bval, true); |
140 | if( d) |
141 | len += snprintf(buf+len,maxlen-len,"[" BUNFMT "]" , BATcount(d)); |
142 | } |
143 | } |
144 | } |
145 | |
146 | // show the type when required or frozen by the user |
147 | // special care should be taken with constants, they may have been casted |
148 | if ((flg & LIST_MAL_TYPE) || (isVarUDFtype(mb, varid) && idx < p->retc) || isVarTypedef(mb,varid) || showtype){ |
149 | strcat(buf + len,":" ); |
150 | len++; |
151 | tpe = getTypeName(getVarType(mb, varid)); |
152 | len += snprintf(buf+len,maxlen-len,"%s" ,tpe); |
153 | GDKfree(tpe); |
154 | } |
155 | |
156 | if( len >= maxlen) |
157 | addMalException(mb,"renderTerm:Value representation too large" ); |
158 | return buf; |
159 | } |
160 | |
161 | /* |
162 | It receives the space to store the definition |
163 | The MAL profiler dumps some performance data at the |
164 | beginning of each line. |
165 | */ |
166 | |
167 | str |
168 | fcnDefinition(MalBlkPtr mb, InstrPtr p, str t, int flg, str base, size_t len) |
169 | { |
170 | int i; |
171 | str arg, tpe; |
172 | |
173 | len -= t - base; |
174 | if (!flg && !copystring(&t, "#" , &len)) |
175 | return base; |
176 | if( mb->inlineProp && !copystring(&t, "inline " , &len)) |
177 | return base; |
178 | if( mb->unsafeProp && !copystring(&t, "unsafe " , &len)) |
179 | return base; |
180 | if( mb->sealedProp && !copystring(&t, "sealed " , &len)) |
181 | return base; |
182 | if (!copystring(&t, operatorName(p->token), &len) || |
183 | !copystring(&t, " " , &len) || |
184 | !copystring(&t, getModuleId(p) ? getModuleId(p) : "user" , &len) || |
185 | !copystring(&t, "." , &len) || |
186 | !copystring(&t, getFunctionId(p), &len) || |
187 | !copystring(&t, "(" , &len)) |
188 | return base; |
189 | |
190 | for (i = p->retc; i < p->argc; i++) { |
191 | arg = renderTerm(mb, 0, p, i, (LIST_MAL_NAME | LIST_MAL_TYPE | LIST_MAL_PROPS)); |
192 | if (arg && !copystring(&t, arg, &len)) { |
193 | GDKfree(arg); |
194 | return base; |
195 | } |
196 | GDKfree(arg); |
197 | if( i<p->argc-1 && !copystring(&t, ", " , &len)) |
198 | return base; |
199 | } |
200 | |
201 | advance(t,base,len); |
202 | if (p->varargs & VARARGS && !copystring(&t, "..." , &len)) |
203 | return base; |
204 | |
205 | if (p->retc == 1) { |
206 | if (!copystring(&t, "):" , &len)) |
207 | return base; |
208 | tpe = getTypeName(getVarType(mb, getArg(p,0))); |
209 | if (!copystring(&t, tpe, &len)) { |
210 | GDKfree(tpe); |
211 | return base; |
212 | } |
213 | GDKfree(tpe); |
214 | if (p->varargs & VARRETS && !copystring(&t, "..." , &len)) |
215 | return base; |
216 | } else { |
217 | if (!copystring(&t, ") (" , &len)) |
218 | return base; |
219 | for (i = 0; i < p->retc; i++) { |
220 | arg = renderTerm(mb, 0, p, i, (LIST_MAL_NAME | LIST_MAL_TYPE | LIST_MAL_PROPS)); |
221 | if (arg && !copystring(&t, arg, &len)) { |
222 | GDKfree(arg); |
223 | return base; |
224 | } |
225 | GDKfree(arg); |
226 | if( i<p->retc-1 && !copystring(&t, ", " , &len)) |
227 | return base; |
228 | } |
229 | if (p->varargs & VARRETS && !copystring(&t, "..." , &len)) |
230 | return base; |
231 | if (!copystring(&t, ")" , &len)) |
232 | return base; |
233 | } |
234 | |
235 | if (mb->binding[0]) { |
236 | if (!copystring(&t, " address " , &len) || |
237 | !copystring(&t, mb->binding, &len)) |
238 | return base; |
239 | } |
240 | (void) copystring(&t, ";" , &len); |
241 | return base; |
242 | } |
243 | |
244 | str |
245 | operatorName(int i) |
246 | { |
247 | switch (i) { |
248 | case ASSIGNsymbol: return ":=" ; |
249 | case BARRIERsymbol: return "barrier" ; |
250 | case REDOsymbol: return "redo" ; |
251 | case LEAVEsymbol: return "leave" ; |
252 | case EXITsymbol: return "exit" ; |
253 | case RETURNsymbol: return "return" ; |
254 | case YIELDsymbol: return "yield" ; |
255 | case CATCHsymbol: return "catch" ; |
256 | case RAISEsymbol: return "raise" ; |
257 | case ENDsymbol: return "end" ; |
258 | case FUNCTIONsymbol: return "function" ; |
259 | case FACTORYsymbol: return "factory" ; |
260 | case COMMANDsymbol: return "command" ; |
261 | case PATTERNsymbol: return "pattern" ; |
262 | } |
263 | return "Undefined" ; |
264 | } |
265 | |
266 | str |
267 | instruction2str(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg) |
268 | { |
269 | int i; |
270 | str base, t; |
271 | size_t len = 512 + (p->argc * 128); /* max realistic line length estimate */ |
272 | str arg; |
273 | |
274 | t = base = GDKmalloc(len); |
275 | if ( base == NULL) |
276 | return NULL; |
277 | if (!flg) { |
278 | *t++ = '#'; |
279 | len--; |
280 | if (p->typechk == TYPE_UNKNOWN) { |
281 | *t++ = '!'; /* error */ |
282 | len--; |
283 | } |
284 | } |
285 | *t = 0; |
286 | if (p->token == REMsymbol && !( getModuleId(p) && strcmp(getModuleId(p),"querylog" ) == 0 && getFunctionId(p) && strcmp(getFunctionId(p),"define" ) == 0)) { |
287 | /* do nothing */ |
288 | } else if (p->barrier) { |
289 | if (p->barrier == LEAVEsymbol || |
290 | p->barrier == REDOsymbol || |
291 | p->barrier == RETURNsymbol || |
292 | p->barrier == YIELDsymbol || |
293 | p->barrier == RAISEsymbol) { |
294 | if (!copystring(&t, " " , &len)) |
295 | return base; |
296 | } |
297 | arg = operatorName(p->barrier); |
298 | if (!copystring(&t, arg, &len) || |
299 | !copystring(&t, " " , &len)) |
300 | return base; |
301 | } else if( functionStart(p) && flg != LIST_MAL_CALL ){ |
302 | return fcnDefinition(mb, p, t, flg, base, len + (t - base)); |
303 | } else if (!functionExit(p) && flg!=LIST_MAL_CALL) { |
304 | // beautify with tabs |
305 | if (!copystring(&t, " " , &len)) |
306 | return base; |
307 | } |
308 | switch (p->token<0?-p->token:p->token) { |
309 | case FCNcall: |
310 | case FACcall: |
311 | case PATcall: |
312 | case CMDcall: |
313 | case ASSIGNsymbol : |
314 | // is any variable explicit or used |
315 | for (i = 0; i < p->retc; i++) |
316 | if ( !isTmpVar(mb,getArg(p,i)) || isVarUsed(mb, getArg(p, i)) || isVarUDFtype(mb,getArg(p,i))) |
317 | break; |
318 | |
319 | if (i == p->retc) |
320 | break; |
321 | |
322 | /* display multi-assignment list */ |
323 | if (p->retc > 1 && !copystring(&t, "(" , &len)) |
324 | return base; |
325 | |
326 | for (i = 0; i < p->retc; i++) { |
327 | arg= renderTerm(mb, stk, p, i, flg); |
328 | if (arg) { |
329 | if (!copystring(&t, arg, &len)) { |
330 | GDKfree(arg); |
331 | return base; |
332 | } |
333 | GDKfree(arg); |
334 | } |
335 | if (i < p->retc - 1 && !copystring(&t, ", " , &len)) |
336 | return base; |
337 | } |
338 | if (p->retc > 1 && !copystring(&t, ")" , &len)) |
339 | return base; |
340 | |
341 | if (p->argc > p->retc || getFunctionId(p)) { |
342 | if (!copystring(&t, " := " , &len)) |
343 | return base; |
344 | } |
345 | break; |
346 | case ENDsymbol: |
347 | if (!copystring(&t, "end " , &len) || |
348 | !copystring(&t, getModuleId(getInstrPtr(mb,0)), &len) || |
349 | !copystring(&t, "." , &len) || |
350 | !copystring(&t, getFunctionId(getInstrPtr(mb, 0)), &len)) |
351 | return base; |
352 | break; |
353 | case COMMANDsymbol: |
354 | case FUNCTIONsymbol: |
355 | case FACTORYsymbol: |
356 | case PATTERNsymbol: |
357 | if (flg & LIST_MAL_VALUE) { |
358 | if (!copystring(&t, operatorName(p->token), &len) || |
359 | !copystring(&t, " " , &len)) |
360 | return base; |
361 | } |
362 | return fcnDefinition(mb, p, t, flg, base, len + (t - base)); |
363 | case REMsymbol: |
364 | case NOOPsymbol: |
365 | if (!copystring(&t, "#" , &len)) |
366 | return base; |
367 | if (getVar(mb, getArg(p, 0))->value.val.sval && getVar(mb, getArg(p, 0))->value.len > 0 && |
368 | !copystring(&t, getVar(mb, getArg(p, 0))->value.val.sval, &len)) |
369 | return base; |
370 | if (!copystring(&t, " " , &len)) |
371 | return base; |
372 | break; |
373 | default: |
374 | i = snprintf(t, len, " unknown symbol ?%d? " , p->token); |
375 | if (i < 0 || (size_t) i >= len) |
376 | return base; |
377 | len -= (size_t) i; |
378 | t += i; |
379 | break; |
380 | } |
381 | |
382 | if (getModuleId(p)) { |
383 | if (!copystring(&t, getModuleId(p), &len) || |
384 | !copystring(&t, "." , &len)) |
385 | return base; |
386 | } |
387 | if (getFunctionId(p)) { |
388 | if (!copystring(&t, getFunctionId(p), &len) || |
389 | !copystring(&t, "(" , &len)) |
390 | return base; |
391 | } else if (p->argc > p->retc + 1) { |
392 | if (!copystring(&t, "(" , &len)) |
393 | return base; |
394 | } |
395 | for (i = p->retc; i < p->argc; i++) { |
396 | arg= renderTerm(mb, stk, p, i, flg); |
397 | if (arg) { |
398 | if (!copystring(&t, arg, &len)) { |
399 | GDKfree(arg); |
400 | return base; |
401 | } |
402 | GDKfree(arg); |
403 | } |
404 | |
405 | if (i < p->argc -1 && !copystring(&t, ", " , &len)) |
406 | return base; |
407 | } |
408 | if (getFunctionId(p) || p->argc > p->retc + 1) { |
409 | if (!copystring(&t, ")" , &len)) |
410 | return base; |
411 | } |
412 | if (p->token != REMsymbol){ |
413 | if (!copystring(&t, ";" , &len)) |
414 | return base; |
415 | } |
416 | return base; |
417 | } |
418 | |
419 | /* the MAL beautifier is meant to simplify correlation of MAL variables and |
420 | * the columns in the underlying database. |
421 | * If the status is set, then we consider the instruction DONE and the result variables |
422 | * should be shown as well. |
423 | */ |
424 | static str |
425 | shortRenderingTerm(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int idx) |
426 | { |
427 | str s, nme; |
428 | BAT *b; |
429 | ValRecord *val; |
430 | char *cv =0; |
431 | int varid = getArg(p,idx); |
432 | size_t len = BUFSIZ; |
433 | |
434 | s= GDKmalloc(len); |
435 | if( s == NULL) |
436 | return NULL; |
437 | *s = 0; |
438 | |
439 | if( isVarConstant(mb,varid) ){ |
440 | val =&getVarConstant(mb, varid); |
441 | if ((cv = VALformat(val)) == NULL) { |
442 | GDKfree(s); |
443 | return NULL; |
444 | } |
445 | if (strlen(cv) >= len) { |
446 | char *nbuf; |
447 | len = strlen(cv); |
448 | nbuf = GDKrealloc(s, len + 1); |
449 | if (nbuf == NULL) { |
450 | GDKfree(s); |
451 | GDKfree(cv); |
452 | return NULL; |
453 | } |
454 | s = nbuf; |
455 | } |
456 | snprintf(s,len + 1,"%s" ,cv); |
457 | } else { |
458 | val = &stk->stk[varid]; |
459 | if ((cv = VALformat(val)) == NULL) { |
460 | GDKfree(s); |
461 | return NULL; |
462 | } |
463 | nme = getVarName(mb, varid); |
464 | if ( isaBatType(getArgType(mb,p,idx))){ |
465 | b = BBPquickdesc(stk->stk[varid].val.bval, true); |
466 | snprintf(s,BUFSIZ,"%s[" BUNFMT"]" ,nme, b?BATcount(b):0); |
467 | } else |
468 | snprintf(s,BUFSIZ,"%s=%s " ,nme,cv); |
469 | } |
470 | GDKfree(cv); |
471 | return s; |
472 | } |
473 | |
474 | str |
475 | shortStmtRendering(MalBlkPtr mb, MalStkPtr stk, InstrPtr p) |
476 | { |
477 | int i; |
478 | str base, s, t, nme; |
479 | size_t len= (mb->stop < 1000? 1000: mb->stop) * 128 /* max realistic line length estimate */; |
480 | |
481 | base = s = GDKmalloc(len); |
482 | if ( s == NULL) |
483 | return s; |
484 | *s =0; |
485 | t=s; |
486 | if (p->token == REMsymbol && !( getModuleId(p) && strcmp(getModuleId(p),"querylog" ) == 0 && getFunctionId(p) && strcmp(getFunctionId(p),"define" ) == 0)) |
487 | return base; |
488 | if (p->barrier == LEAVEsymbol || |
489 | p->barrier == REDOsymbol || |
490 | p->barrier == RETURNsymbol || |
491 | p->barrier == YIELDsymbol || |
492 | p->barrier == EXITsymbol || |
493 | p->barrier == RAISEsymbol) { |
494 | snprintf(t,(len-(t-base)), "%s " , operatorName(p->barrier)); |
495 | advance(t,base,len); |
496 | } |
497 | if( p->token == FUNCTIONsymbol) { |
498 | snprintf(t,(len-(t-base)), "function %s." , getModuleId(p)); |
499 | advance(t,base,len); |
500 | } |
501 | if (p->token == ENDsymbol ){ |
502 | snprintf(t,(len-(t-base)), "end %s.%s" , getModuleId(getInstrPtr(mb,0)), getFunctionId(getInstrPtr(mb,0))); |
503 | return base; |
504 | } |
505 | // handle the result variables |
506 | for (i = 0; i < p->retc; i++) |
507 | if ( !isTmpVar(mb,getArg(p,i)) || isVarUsed(mb, getArg(p, i)) || isVarUDFtype(mb,getArg(p,i))) |
508 | break; |
509 | |
510 | if (i == p->retc) // no result arguments |
511 | goto short_end; |
512 | |
513 | /* display optional multi-assignment list */ |
514 | if( getArgType(mb,p,0) != TYPE_void){ |
515 | if (p->retc > 1 && t < base + len-1){ |
516 | *t++ = '('; |
517 | *t=0; |
518 | } |
519 | |
520 | for (i = 0; i < p->retc; i++) { |
521 | nme = shortRenderingTerm(mb, stk, p,i); |
522 | snprintf(t,(len-(t-base)), "%s%s" , (i?", " :"" ), nme); |
523 | GDKfree(nme); |
524 | advance(t,base,len); |
525 | } |
526 | if (p->retc > 1 && t< base+len) |
527 | *t++ = ')'; |
528 | if( t < base +len) *t++ = ':'; |
529 | if( t < base +len) *t++ = '='; |
530 | if( t < base +len) *t++ = ' '; |
531 | } |
532 | *t =0; |
533 | |
534 | short_end: |
535 | advance(t,base,len); |
536 | |
537 | // handle the instruction mapping |
538 | snprintf(t, (len-(t-base)),"%s" , (getFunctionId(p)?getFunctionId(p):"" )); |
539 | advance(t,base,len); |
540 | |
541 | // handle the arguments, constants should be shown including their non-default type |
542 | /* display optional multi-assignment list */ |
543 | if( t< base + len) *t++ = '('; |
544 | for (i = p->retc; i < p->argc; i++) { |
545 | nme = shortRenderingTerm(mb, stk, p,i); |
546 | snprintf(t,(len-(t-base)), "%s%s" , (i!= p->retc? ", " :" " ), nme); |
547 | GDKfree(nme); |
548 | advance(t,base,len); |
549 | if (i < p->retc - 1 && t < base+len){ |
550 | *t++ = ','; |
551 | *t++ = ' '; |
552 | } |
553 | } |
554 | if( t < base + len) *t++ = ' '; |
555 | if( t < base + len) *t++ = ')'; |
556 | *t=0; |
557 | |
558 | if (t >= s + len) |
559 | throw(MAL,"instruction2str:" ,"instruction too long" ); |
560 | return base; |
561 | } |
562 | |
563 | /* Remote execution of MAL calls for more type/property information to be exchanged */ |
564 | str |
565 | mal2str(MalBlkPtr mb, int first, int last) |
566 | { |
567 | str ps = NULL, *txt; |
568 | int i, j; |
569 | size_t *len, totlen = 0; |
570 | |
571 | txt = GDKmalloc(sizeof(str) * mb->stop); |
572 | len = GDKmalloc(sizeof(size_t) * mb->stop); |
573 | |
574 | if( txt == NULL || len == NULL){ |
575 | addMalException(mb,"mal2str: " MAL_MALLOC_FAIL); |
576 | GDKfree(txt); |
577 | GDKfree(len); |
578 | return NULL; |
579 | } |
580 | for (i = first; i < last; i++) { |
581 | if( i == 0) |
582 | txt[i] = instruction2str(mb, 0, getInstrPtr(mb, i), LIST_MAL_NAME | LIST_MAL_TYPE | LIST_MAL_PROPS); |
583 | else |
584 | txt[i] = instruction2str(mb, 0, getInstrPtr(mb, i), LIST_MAL_CALL | LIST_MAL_PROPS | LIST_MAL_REMOTE); |
585 | #ifdef _DEBUG_LISTING_ |
586 | fprintf(stderr,"%s\n" ,txt[i]); |
587 | #endif |
588 | |
589 | if ( txt[i]) |
590 | totlen += len[i] = strlen(txt[i]); |
591 | else { |
592 | addMalException(mb,"mal2str: " MAL_MALLOC_FAIL); |
593 | GDKfree(len); |
594 | for (j = first; j < i; j++) |
595 | GDKfree(txt[j]); |
596 | GDKfree(txt); |
597 | return NULL; |
598 | } |
599 | } |
600 | ps = GDKmalloc(totlen + mb->stop + 1); |
601 | if( ps == NULL){ |
602 | addMalException(mb,"mal2str: " MAL_MALLOC_FAIL); |
603 | GDKfree(len); |
604 | for (i = first; i < last; i++) |
605 | GDKfree(txt[i]); |
606 | GDKfree(txt); |
607 | return NULL; |
608 | } |
609 | |
610 | totlen = 0; |
611 | for (i = first; i < last; i++) { |
612 | if( txt[i]){ |
613 | strncpy(ps + totlen, txt[i], len[i]); |
614 | ps[totlen + len[i]] = '\n'; |
615 | ps[totlen + len[i] + 1] = 0; |
616 | totlen += len[i] + 1; |
617 | GDKfree(txt[i]); |
618 | } |
619 | } |
620 | GDKfree(len); |
621 | GDKfree(txt); |
622 | return ps; |
623 | } |
624 | |
625 | void |
626 | printInstruction(stream *fd, MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg) |
627 | { |
628 | str ps; |
629 | |
630 | if (fd == 0) |
631 | return; |
632 | ps = instruction2str(mb, stk, p, flg); |
633 | /* ps[strlen(ps)-1] = 0; remove '\n' */ |
634 | if ( ps ){ |
635 | mnstr_printf(fd, "%s%s" , (flg & LIST_MAL_MAPI ? "=" : "" ), ps); |
636 | GDKfree(ps); |
637 | } else { |
638 | mnstr_printf(fd,"#failed instruction2str()" ); |
639 | } |
640 | mnstr_printf(fd, "\n" ); |
641 | } |
642 | |
643 | void |
644 | fprintInstruction(FILE *fd, MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg) |
645 | { |
646 | str ps; |
647 | |
648 | if (fd == 0) |
649 | return; |
650 | ps = instruction2str(mb, stk, p, flg); |
651 | /* ps[strlen(ps)-1] = 0; remove '\n' */ |
652 | if ( ps ){ |
653 | fprintf(fd, "%s%s" , (flg & LIST_MAL_MAPI ? "=" : "" ), ps); |
654 | GDKfree(ps); |
655 | } else { |
656 | fprintf(fd,"#failed instruction2str()" ); |
657 | } |
658 | fprintf(fd, "\n" ); |
659 | } |
660 | |
661 | void |
662 | printSignature(stream *fd, Symbol s, int flg) |
663 | { |
664 | InstrPtr p; |
665 | str txt; |
666 | |
667 | if ( s->def == 0 ){ |
668 | mnstr_printf(fd, "missing definition of %s\n" , s->name); |
669 | return; |
670 | } |
671 | txt = GDKzalloc(MAXLISTING); /* some slack for large blocks */ |
672 | if( txt){ |
673 | p = getSignature(s); |
674 | (void) fcnDefinition(s->def, p, txt, flg, txt, MAXLISTING); |
675 | mnstr_printf(fd, "%s\n" , txt); |
676 | GDKfree(txt); |
677 | } else mnstr_printf(fd, "printSignature: " MAL_MALLOC_FAIL); |
678 | } |
679 | |
680 | void showMalBlkHistory(stream *out, MalBlkPtr mb) |
681 | { |
682 | MalBlkPtr m=mb; |
683 | InstrPtr p,sig; |
684 | int j=0; |
685 | str msg; |
686 | |
687 | sig = getInstrPtr(mb,0); |
688 | m= m->history; |
689 | while(m){ |
690 | p= getInstrPtr(m,m->stop-1); |
691 | if( p->token == REMsymbol){ |
692 | msg= instruction2str(m, 0, p, FALSE); |
693 | if (msg ) { |
694 | mnstr_printf(out,"%s.%s[%2d] %s\n" , |
695 | getModuleId(sig), getFunctionId(sig),j++,msg+3); |
696 | GDKfree(msg); |
697 | } else { |
698 | mnstr_printf(out,"#failed instruction2str()\n" ); |
699 | } |
700 | } |
701 | m= m->history; |
702 | } |
703 | } |
704 | |