2 * The Regina Rexx Interpreter
3 * Copyright (C) 1992-1994 Anders Christensen <anders@pvv.unit.no>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 typedef struct { /* tra_tsd: static variables of this module (thread-safe) */
32 int traceflag
; /* boolean: 1 indicates that trace output is NOT displayed */
34 int intercount
; /* number of times to execute trace without interaction */
35 int quiet
; /* boolean: run quietly in interaction trace */
37 char tracestr
[LINELENGTH
+1];
41 } tra_tsd_t
; /* thread-specific but only needed by this module. see
46 /* init_tracing initializes the module.
47 * Currently, we set up the thread specific data.
48 * The function returns 1 on success, 0 if memory is short.
50 int init_tracing( tsd_t
*TSD
)
54 if ( TSD
->tra_tsd
!= NULL
)
57 if ( ( TSD
->tra_tsd
= MallocTSD( sizeof( tra_tsd_t
) ) ) == NULL
)
59 tt
= (tra_tsd_t
*)TSD
->tra_tsd
;
60 memset( tt
, 0, sizeof( tra_tsd_t
) );
61 tt
->lasttracedline
= -1;
65 int pushcallstack( const tsd_t
*TSD
, treenode
*thisptr
)
69 if ( TSD
->systeminfo
->cstackcnt
>= TSD
->systeminfo
->cstackmax
)
71 assert( TSD
->systeminfo
->cstackcnt
== TSD
->systeminfo
->cstackmax
);
72 tmpptr
= (nodeptr
*)MallocTSD( ( TSD
->systeminfo
->cstackmax
* 2 + 10 ) *
74 if ( TSD
->systeminfo
->callstack
)
76 memcpy( tmpptr
, TSD
->systeminfo
->callstack
,
77 TSD
->systeminfo
->cstackcnt
* sizeof( nodeptr
) );
78 FreeTSD( TSD
->systeminfo
->callstack
);
80 TSD
->systeminfo
->callstack
= tmpptr
;
81 TSD
->systeminfo
->cstackmax
*= 2;
82 TSD
->systeminfo
->cstackmax
+= 10;
85 TSD
->systeminfo
->callstack
[TSD
->systeminfo
->cstackcnt
++] = thisptr
;
86 return TSD
->systeminfo
->cstackcnt
;
89 void popcallstack( const tsd_t
*TSD
, int value
)
93 assert( TSD
->systeminfo
->cstackcnt
>= value
);
94 TSD
->systeminfo
->cstackcnt
= value
;
97 --TSD
->systeminfo
->cstackcnt
;
99 assert( TSD
->systeminfo
->cstackcnt
>= 0 );
102 static void printout( tsd_t
*TSD
, const streng
*message
)
108 if ( TSD
->systeminfo
->hooks
& HOOK_MASK( HOOK_STDERR
) )
109 rc
= hookup_output( TSD
, HOOK_STDERR
, message
);
111 if ( rc
== HOOK_GO_ON
)
113 if ( get_options_flag( TSD
->currlevel
, EXT_STDOUT_FOR_STDERR
) )
115 if ( get_options_flag( TSD
->currlevel
, EXT_TRACE_HTML
) )
116 fwrite( "<FONT COLOR=#669933><PRE>", 25, 1, fp
);
117 fwrite( message
->value
, message
->len
, 1, fp
) ;
118 if ( get_options_flag( TSD
->currlevel
, EXT_TRACE_HTML
) )
119 fwrite( "</PRE></FONT>", 13, 1, fp
);
120 #if defined(DOS) || defined(OS2) || defined(WIN32)
122 * stdout is open in binary mode, so we need to add the
123 * extra CR to the end of the line.
125 fputc( REGINA_CR
, fp
);
127 fputc( REGINA_EOL
, fp
);
132 void traceerror( tsd_t
*TSD
, const treenode
*thisptr
, int RC
)
136 if ( ( TSD
->trace_stat
== 'N' ) || ( TSD
->trace_stat
== 'F' ) )
137 traceline( TSD
, thisptr
, 'C', 0 );
139 if ( TSD
->trace_stat
!= 'O' )
141 message
= Str_makeTSD( 20 + sizeof( int ) * 3 ) ;
142 message
->len
= sprintf( message
->value
, " +++ RC=%d +++", RC
);
144 printout( TSD
, message
);
145 Free_stringTSD( message
);
149 void tracecompound( tsd_t
*TSD
, const streng
*stem
, int length
,
150 const streng
*index
, char trch
)
156 tt
= (tra_tsd_t
*)TSD
->tra_tsd
;
157 if ( tt
->traceflag
|| ( TSD
->trace_stat
!= 'I' ) || tt
->quiet
)
160 indent
= TSD
->systeminfo
->cstackcnt
+ TSD
->systeminfo
->ctrlcounter
;
161 message
= Str_makeTSD( stem
->len
+ index
->len
+ 30 + indent
);
163 sprintf( tt
->tracestr
, " >%c> %%%ds \"%%.%ds.%%.%ds\"",
164 trch
, indent
, length
, index
->len
);
165 message
->len
= sprintf( message
->value
, tt
->tracestr
,
166 "", stem
->value
, index
->value
);
168 printout( TSD
, message
);
170 Free_stringTSD( message
);
173 void starttrace( const tsd_t
*TSD
)
177 tt
= (tra_tsd_t
*)TSD
->tra_tsd
;
182 static void tracemsg( tsd_t
*TSD
)
187 msg
= errortext( TSD
, 0, 3, 0, 0 );
188 message
= Str_makeTSD( 12 + Str_len( msg
) );
189 Str_catstrTSD( message
, " +++ " );
190 Str_catTSD( message
, msg
);
191 printout( TSD
, message
);
192 Free_stringTSD( message
);
195 int intertrace( tsd_t
*TSD
)
201 tt
= (tra_tsd_t
*)TSD
->tra_tsd
;
203 if ( tt
->intercount
)
206 if ( tt
->intercount
== 0 )
218 if ( tt
->notnow
== 1 )
223 else if ( tt
->notnow
== 2 )
231 for ( ; retvalue1
< 0; )
234 if ( TSD
->systeminfo
->hooks
& HOOK_MASK( HOOK_TRCIN
) )
235 rc
= hookup_input( TSD
, HOOK_TRCIN
, &str
);
237 if ( rc
== HOOK_GO_ON
)
238 str
= readkbdline( TSD
);
246 if ( ( Str_len( str
) == 1 ) && (str
->value
[0] == '=' ) )
253 dointerpret( TSD
, str
);
254 if ( !TSD
->systeminfo
->interactive
)
256 tt
->intercount
= tt
->quiet
= 0;
259 if ( tt
->intercount
)
273 void tracenumber( tsd_t
*TSD
, const num_descr
*num
, char type
)
276 streng
*message
,*tmpstr
;
281 tmpch
= TSD
->currlevel
->tracestat
;
282 if ( ( tmpch
!= 'I' ) && ( tmpch
!= 'R' ) )
285 tt
= (tra_tsd_t
*)TSD
->tra_tsd
;
286 if ( tt
->traceflag
|| tt
->quiet
)
289 memset( &nd
, 0, sizeof( num_descr
) );
290 descr_copy( TSD
, num
, &nd
);
291 tmpstr
= str_norm( TSD
, &nd
, NULL
);
292 indent
= TSD
->systeminfo
->cstackcnt
+ TSD
->systeminfo
->ctrlcounter
;
293 message
= Str_makeTSD( 30 + indent
+ tmpstr
->len
);
294 sprintf( tt
->tracestr
, " >%%c> %%%ds \"%%.%ds\"",
295 indent
, tmpstr
->len
);
296 message
->len
= sprintf( message
->value
, tt
->tracestr
,
297 type
, "", tmpstr
->value
);
298 printout( TSD
, message
);
299 if ( nd
.num
!= NULL
)
301 Free_stringTSD( message
);
302 Free_stringTSD( tmpstr
);
305 void tracebool( tsd_t
*TSD
, int value
, char type
)
312 tmpch
= TSD
->currlevel
->tracestat
;
313 if ( ( tmpch
!= 'I' ) && ( tmpch
!= 'R' ) )
316 tt
= (tra_tsd_t
*)TSD
->tra_tsd
;
317 if ( tt
->traceflag
|| tt
->quiet
)
320 indent
= TSD
->systeminfo
->cstackcnt
+ TSD
->systeminfo
->ctrlcounter
;
321 message
= Str_makeTSD( 35 + indent
);
322 sprintf( tt
->tracestr
, " >%%c> %%%ds \"%%d\"",
324 message
->len
= sprintf( message
->value
, tt
->tracestr
,
326 printout( TSD
, message
);
327 Free_stringTSD( message
);
330 void tracevalue( tsd_t
*TSD
, const streng
*str
, char type
)
338 * ANSI 8.3.17 requires placeholders in PARSE to be traced with TRACE R
340 tmpch
= TSD
->currlevel
->tracestat
;
341 if ( ( tmpch
!= 'I' ) && ( tmpch
!= 'R' ) )
344 tt
= (tra_tsd_t
*)TSD
->tra_tsd
;
345 if ( tt
->traceflag
|| tt
->quiet
)
348 indent
= TSD
->systeminfo
->cstackcnt
+ TSD
->systeminfo
->ctrlcounter
;
349 message
= Str_makeTSD( str
->len
+ 30 + indent
);
350 sprintf( tt
->tracestr
, " >%%c> %%%ds \"%%.%ds\"",
352 message
->len
= sprintf( message
->value
, tt
->tracestr
,
353 type
, "", str
->value
);
354 printout( TSD
, message
);
355 Free_stringTSD( message
);
358 void traceline( tsd_t
*TSD
, const treenode
*thisptr
, char tch
, int offset
)
365 tt
= (tra_tsd_t
*)TSD
->tra_tsd
;
366 if ( tt
->traceflag
|| tt
->quiet
)
369 if ( ( thisptr
->charnr
< 0 ) || ( thisptr
->lineno
< 0 ) )
377 break; /* Oh yes, break the IRA ;-) */
380 if ( thisptr
->type
== X_LABEL
)
385 if ( ( thisptr
->type
== X_COMMAND
)
386 || ( ( thisptr
->type
== X_ADDR_N
) && thisptr
->p
[0] ) )
394 srcstr
= getsourceline( TSD
, thisptr
->lineno
, thisptr
->charnr
,
395 &TSD
->systeminfo
->tree
);
397 indent
= TSD
->systeminfo
->cstackcnt
+ TSD
->systeminfo
->ctrlcounter
;
398 message
= Str_makeTSD( indent
+ 20 + srcstr
->len
+ offset
);
399 if ( thisptr
->lineno
== tt
->lasttracedline
)
401 sprintf( tt
->tracestr
, " *-* %%%ds%%.%ds",
402 indent
+ offset
, srcstr
->len
);
403 message
->len
= sprintf( message
->value
, tt
->tracestr
,
408 sprintf( tt
->tracestr
, "%%6d *-* %%%ds%%.%ds",
409 indent
+ offset
, srcstr
->len
);
410 message
->len
= sprintf( message
->value
, tt
->tracestr
,
411 thisptr
->lineno
, "", srcstr
->value
);
414 printout( TSD
, message
);
415 tt
->lasttracedline
= thisptr
->lineno
;
416 Free_stringTSD( message
);
417 Free_stringTSD( srcstr
);
420 void traceback( tsd_t
*TSD
)
426 int i
,j
,linesize
=128,indent
;
429 tt
= (tra_tsd_t
*)TSD
->tra_tsd
;
431 * Allocate enough space for one line and control stuff. Count below
432 * characters for the needed size. Beware of the computed format
435 indent
= TSD
->systeminfo
->cstackcnt
+ TSD
->systeminfo
->ctrlcounter
;
436 message
= Str_makeTSD( linesize
+ indent
* 3 + 20 );
437 if ( TSD
->currentnode
)
439 srcline
= getsourceline( TSD
,
440 TSD
->currentnode
->lineno
,
441 TSD
->currentnode
->charnr
,
442 &TSD
->systeminfo
->tree
);
443 if ( srcline
->len
> linesize
)
445 Free_stringTSD( message
);
446 linesize
= srcline
->len
;
447 message
= Str_makeTSD( linesize
+ indent
* 3 + 20 );
449 sprintf( tt
->tracefmt
, "%%6d +++ %%%ds%%.%ds",
450 indent
* 3, srcline
->len
);
451 message
->len
= sprintf( message
->value
, tt
->tracefmt
,
452 TSD
->currentnode
->lineno
, "",
454 printout( TSD
, message
);
455 Free_stringTSD( srcline
);
459 for ( ss
= TSD
->systeminfo
; ss
; ss
= ss
->previous
)
461 for ( i
= ss
->cstackcnt
- 1; i
>= 0; i
-- )
463 ptr
= ss
->callstack
[i
];
467 srcline
= getsourceline( TSD
,
471 if ( srcline
->len
> linesize
)
473 Free_stringTSD( message
);
474 linesize
= srcline
->len
;
475 message
= Str_makeTSD( linesize
+ indent
* 3 + 20 );
479 if ( ( j
> 12 ) && get_options_flag( TSD
->currlevel
, EXT_PRUNE_TRACE
) )
480 sprintf( tt
->tracefmt
, "%%6d +++ [...] %%%ds%%.%ds",
483 sprintf( tt
->tracefmt
, "%%6d +++ %%%ds%%.%ds",
484 j
* 3, srcline
->len
);
485 message
->len
= sprintf( message
->value
, tt
->tracefmt
,
488 printout( TSD
, message
);
489 Free_stringTSD( srcline
);
492 Free_stringTSD( message
);
495 void queue_trace_char( const tsd_t
*TSD
, char ch2
)
499 tt
= (tra_tsd_t
*)TSD
->tra_tsd
;
500 if ( tt
->bufptr0
< 32 )
501 tt
->buf0
[tt
->bufptr0
++] = ch2
;
503 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
,
504 "too many tracechars queued" );
507 void flush_trace_chars( tsd_t
*TSD
)
512 tt
= (tra_tsd_t
*)TSD
->tra_tsd
;
513 for ( cnt
= 0; cnt
< tt
->bufptr0
; cnt
++ )
514 set_trace_char( TSD
, tt
->buf0
[cnt
] );
519 void set_trace_char( tsd_t
*TSD
, char ch2
)
521 ch2
= (char) rx_toupper( ch2
);
525 TSD
->systeminfo
->interactive
= !TSD
->systeminfo
->interactive
;
526 TSD
->currlevel
->traceint
= (char) TSD
->systeminfo
->interactive
;
527 if ( TSD
->systeminfo
->interactive
)
540 TSD
->currlevel
->tracestat
= ch2
;
544 exiterror( ERR_INVALID_TRACE
, 1, "ACEFILNOR", ch2
);
548 TSD
->systeminfo
->interactive
= TSD
->currlevel
->traceint
= 0;
549 TSD
->trace_stat
= TSD
->currlevel
->tracestat
;
552 void set_trace( tsd_t
*TSD
, const streng
*setting
)
557 if ( myisnumber( TSD
, setting
) )
559 cptr
= streng_to_int( TSD
, setting
, &error
);
561 exiterror( ERR_INVALID_INTEGER
, 7, tmpstr_of( TSD
, setting
) );
564 * If the number is positive, interactive tracing continues
565 * for the supplied number of clauses, but no pausing is done.
566 * If the number is negative, no trace output is inhibited
567 * (as is the pauses) for the supplied number of clauses.
568 * If the number is zero, this is the same as TRACE OFF
570 tt
= (tra_tsd_t
*)TSD
->tra_tsd
;
573 TSD
->currlevel
->tracestat
= 'O';
574 TSD
->systeminfo
->interactive
= 0;
575 TSD
->currlevel
->traceint
= 0;
576 TSD
->trace_stat
= TSD
->currlevel
->tracestat
;
581 tt
->intercount
= cptr
+ 1;
586 tt
->intercount
= -cptr
+ 1;
591 for ( cptr
= 0; cptr
< Str_len( setting
); cptr
++ )
593 set_trace_char( TSD
, setting
->value
[cptr
] );
594 if ( rx_isalpha( setting
->value
[cptr
] ) )