comparison interps/c-intercal/src/yuk.c @ 996:859f9b4339e6

<Gregor> tar xf egobot.tar.xz
author HackBot
date Sun, 09 Dec 2012 19:30:08 +0000
parents
children
comparison
equal deleted inserted replaced
995:6883f5911eb7 996:859f9b4339e6
1 /****************************************************************************
2
3 NAME
4 yuk.c -- C-INTERCAL debugger and profiler code, linked into programs.
5
6 DESCRIPTION
7 File linked into programs as a debugger or profiler.
8
9 LICENSE TERMS
10 Copyright (C) 2006 Alex Smith
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
26 ****************************************************************************/
27 #include "config.h" /* AIS: Generated by autoconf */
28 #include <stdlib.h>
29 #include <stdio.h>
30 #ifdef HAVE_SYS_TIME_H
31 # include <sys/time.h>
32 # ifdef TIME_WITH_SYS_TIME
33 # include <time.h>
34 # endif
35 #else
36 # include <time.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
42 #include <setjmp.h>
43 #include <string.h>
44
45 #define YUKDEBUG 1
46
47 #include "yuk.h"
48 #include "ick_lose.h"
49 #include "sizes.h"
50 #include "abcess.h"
51 #include "uncommon.h"
52
53 #if YPTIMERTYPE == 4
54 #include <sys/times.h>
55 #endif
56
57 extern signed char onewatch[];
58 extern signed char twowatch[];
59 extern ick_type16 oneold[];
60 extern ick_type32 twoold[];
61
62 char** globalargv;
63 int globalargc;
64 int yuklines = 0;
65 int yukloop = 0;
66 int yukcommands = 0; /* these 5 lines because externs must be defined
67 somewhere */
68 /* Global variable storage types:
69 static: limited to the file
70 unadorned: defining an extern
71 extern: defined elsewhere (unless initialised) */
72
73 static char buf[21];
74
75 static sig_atomic_t singlestep = 1; /* if 0, run until a breakpoint */
76 static sig_atomic_t writelines = 1; /* whether to display executed lines onscreen */
77 static int breakpoints[80]; /* initialised to all 0s. Breakpoint locations */
78 static int nbreakpoints = 1; /* how many breakpoints we have */
79 static int monitors[80]; /* monitors give a message when program flow passes them */
80 static int nmonitors = 0;
81 static int untilnext = -1; /* NEXTING level to break the program at */
82 static int firstrun = 1; /* ick_first time an interactive command point is reached */
83 static int yukerrcmdg = -1; /* the aboff that indicates an error in the 'g' command */
84
85 static yptimer tickcount; /* yptimer of last run */
86 static int lastaboff = 0; /* last value of aboff */
87
88 static void handlesigint(int i)
89 { /* this is a signal handler, so can't do much */
90 singlestep = 1;
91 writelines = 1;
92 /*@-noeffect@*/ (void) i; /*@=noeffect@*/
93 }
94
95 #if YPTIMERTYPE==1 || YPTIMERTYPE==2
96 static yptimer yukgettimeofday()
97 {
98 static struct timeval tp;
99 yptimer temp;
100 /* gettimeofday is POSIX; config.sh has checked that it's
101 available, so turn off the unrecog warning */
102 /*@-unrecog@*/
103 gettimeofday(&tp,0);
104 /*@=unrecog@*/
105 temp=(yptimer)tp.tv_usec +
106 (yptimer)tp.tv_sec * (yptimer)1000000LU;
107 /* here we make use of unsigned wraparound. In the case
108 YPTIMERTYPE == 1, it seems quite likely that we're going
109 to wraparound, but because everything is cast to the
110 unsigned integral type yptimer, we get a value that will
111 wraparound in such a way that - will give us the correct
112 time interval. */
113 return temp;
114 }
115 #elif YPTIMERTYPE == 4
116 yptimer yuktimes()
117 {
118 static struct tms tp;
119 times(&tp);
120 return tp.tms_utime + tp.tms_stime;
121 }
122 #elif YPTIMERTYPE == 5
123 static yptimer yukclock_gettime()
124 {
125 static struct timespec ts;
126 yptimer temp;
127 /* We've checked that this function is available; -lrt will be linked in. */
128 /*@-unrecog@*/
129 #if defined(_POSIX_CPUTIME) && _POSIX_CPUTIME > 0
130 clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&ts);
131 #else
132 # if defined(_POSIX_THREAD_CPUTIME) && _POSIX_THREAD_CPUTIME > 0
133 clock_gettime(CLOCK_THREAD_CPUTIME_ID,&ts);
134 # else
135 # if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK > 0
136 clock_gettime(CLOCK_MONOTONIC,&ts);
137 # else
138 # ifndef CLOCK_REALTIME
139 # error clock_gettime is defined, but no clocks seem to be; try changing YPTIMERTYPE in src/yuk.h
140 # endif
141 clock_gettime(CLOCK_REALTIME,&ts);
142 # endif
143 # endif
144 #endif
145 /*@=unrecog@*/
146 temp=(yptimer)ts.tv_nsec +
147 (yptimer)ts.tv_sec * (yptimer)1000000000LU;
148 /* using wraparound as with gettimeofday */
149 return temp;
150 }
151 #endif /* YPTIMERTYPE */
152
153 void yukterm(void)
154 {
155 int i,lastline,thisline,inrow=0;
156 yptimer avgtime,avgtime2;
157 if(yukopts==2) (void) puts("Program ended without error.");
158 if(!(yukopts&1)) return;
159 /* Print profiling information */
160 (void) puts("Profiling information saved to \"yuk.out\".");
161 (void) freopen("yuk.out","w",stdout);
162 i=-1;
163 lastline=-1;
164 while(++i<yukcommands)
165 {
166 thisline=lineofaboff[i];
167 if(thisline==lastline) inrow++; else
168 {
169 inrow=1;
170 printf("%5d:\t%s\n",thisline,textlines[thisline]);
171 }
172 lastline=thisline;
173 avgtime=ypexecount[i]+ypabscount[i];
174 if(avgtime) avgtime=ypexectime[i]/avgtime;
175 avgtime2=0;
176 if(ypexecount[i]) avgtime2=ypexectime[i]/ypexecount[i];
177 /*@-formatcode@*/ /* Splint doesn't understand string interpolation */
178 printf("C%d: Time%4" YPTIMERTFORMAT ".%0" YPTIMERTFORMATD
179 ", Avg%2" YPTIMERTFORMAT ".%0" YPTIMERTFORMATD ", "
180 "Avg Exec%2" YPTIMERTFORMAT ".%0" YPTIMERTFORMATD
181 ", Exec%8" YPCOUNTERTFORMAT ", Abs%8" YPCOUNTERTFORMAT "\n",
182 inrow,ypexectime[i]/YPTIMERSCALE, ypexectime[i]%YPTIMERSCALE,
183 avgtime/YPTIMERSCALE, avgtime%YPTIMERSCALE,
184 avgtime2/YPTIMERSCALE, avgtime2%YPTIMERSCALE,
185 ypexecount[i],ypabscount[i]);
186 /*@=formatcode@*/
187 }
188 }
189
190 void yukline(int aboff,int emitlineno)
191 { /* this runs every time a source line is encountered */
192 int i;
193 int broken; /* hit a breakpoint, monitorpoint, viewbreak, until */
194 int keeplooping;
195 int templine;
196 int tempcmd;
197 int temp;
198 yptimer temptick;
199 char* text=textlines[lineofaboff[aboff]];
200 char copyloc[BUFSIZ+9];
201 const char* tempcharp;
202 if(!yukopts) return;
203 if(globalargc!=3)
204 ick_lose(IE778,emitlineno,(const char*)NULL);
205 if(yukopts & 1)
206 { /* profile */
207 temptick=YPGETTIME;
208 if(lastaboff) ypexectime[lastaboff]+=(yptimer)(temptick-tickcount);
209 tickcount=temptick;
210 if(ick_abstained[aboff]) ypabscount[aboff]++;
211 else ypexecount[aboff]++;
212 lastaboff=aboff;
213 }
214 if(yukopts & 2)
215 { /* debug */
216 if(firstrun)
217 {
218 /* GNU GPL requires a copyright notice at this point */
219 (void) puts("yuk debugger Copyright (C) 2006 Alex Smith.");
220 (void) puts("The yuk debugger is covered by the GNU GPL and can");
221 (void) puts("be redistributed freely, but comes with ABSOLUTELY");
222 (void) puts("NO WARRANTY. For more information, type *<RET>.\n");
223 (void) puts("For help on yuk, type ?<RET>.\n");
224 }
225 i=nbreakpoints;
226 broken=0;
227 while(i--) broken|=breakpoints[i]==lineofaboff[aboff];
228 if(yukloop&&broken&&*breakpoints!=lineofaboff[aboff]) broken=0;
229 if(broken)
230 {
231 if(*breakpoints!=lineofaboff[aboff])
232 printf("Breakpoint hit at line %d:\n",lineofaboff[aboff]);
233 singlestep=1;
234 }
235 else
236 {
237 i=nmonitors;
238 while(i--) broken|=monitors[i]==lineofaboff[aboff];
239 if(yukloop) broken=0;
240 if(broken) printf("Command flowed past line %d:\n",lineofaboff[aboff]);
241 }
242 if(ick_nextindex <= untilnext)
243 {
244 broken = 1;
245 singlestep = 1;
246 }
247 if(!broken&&yukerrcmdg==aboff)
248 {
249 singlestep = 1;
250 (void) puts("There are no commands on that line.");
251 /* To the user, nothing will have happened but the error message! */
252 }
253 i=-1;
254 while(++i,1)
255 {
256 if(yukvars[i].vartype==YUKEND) break;
257 if(yukvars[i].vartype==ick_ONESPOT)
258 {
259 if(onewatch[yukvars[i].intername] != (char)0)
260 {
261 if(ick_onespots[yukvars[i].intername]!=oneold[yukvars[i].intername]&&
262 onewatch[yukvars[i].intername]>(char)1)
263 {
264 oneold[yukvars[i].intername]=ick_onespots[yukvars[i].intername];
265 if(onewatch[yukvars[i].intername]==(char)2||!ick_onespots[yukvars[i].intername])
266 {
267 /*@-formatconst@*/ /* it's safe, I checked it */
268 printf(onewatch[yukvars[i].intername]==(char)2?
269 "Variable .%d changed.\n":"Variable .%d became 0.\n",
270 yukvars[i].extername);
271 /*@=formatconst@*/
272 broken=1; singlestep=1;
273 }
274 }
275 if(writelines||broken)
276 {
277 printf(".%d is:\n",yukvars[i].extername);
278 ick_pout(ick_onespots[yukvars[i].intername]);
279 }
280 }
281 }
282 if(yukvars[i].vartype==ick_TWOSPOT)
283 {
284 if(twowatch[yukvars[i].intername] != (char)0)
285 {
286 if(ick_twospots[yukvars[i].intername]!=twoold[yukvars[i].intername]&&
287 twowatch[yukvars[i].intername] > (char)1)
288 {
289 twoold[yukvars[i].intername]=ick_twospots[yukvars[i].intername];
290 if(twowatch[yukvars[i].intername]==(char)2||!ick_twospots[yukvars[i].intername])
291 {
292 /*@-formatconst@*/ /* there's just the one %d each way round */
293 printf(twowatch[yukvars[i].intername]==(char)2?
294 "Variable :%d changed.\n":"Variable :%d became 0.\n",
295 yukvars[i].extername);
296 /*@=formatconst@*/
297 broken=1; singlestep=1;
298 }
299 }
300 if(writelines||broken)
301 {
302 printf(":%d is:\n",yukvars[i].extername);
303 ick_pout(ick_twospots[yukvars[i].intername]);
304 }
305 }
306 }
307 }
308 if(writelines||broken)
309 {
310 /* write line that we're on */
311 printf("%5d:\t%s\n",lineofaboff[aboff],text);
312 /* write command within line that we're on */
313 tempcmd=aboff;
314 while(tempcmd&&lineofaboff[--tempcmd]==lineofaboff[aboff]);
315 printf("On C%d: Abstained %d time%s\n",aboff?aboff-tempcmd:1,
316 ick_abstained[aboff]-yukloop,ick_abstained[aboff]-yukloop==1?".":"s.");
317 }
318 if(singlestep)
319 {
320 (void)signal(SIGINT,handlesigint); /* placing this line here means that a rapid
321 ^C^C will terminate the program, if it's
322 stuck in a loop somewhere */
323 keeplooping = 1;
324 breakpoints[0] = 0; /* breakpoints[0] goes whenever a breakpoint is hit */
325 untilnext = -1;
326 if(yukloop)
327 { /* reverse the abstentions that g caused */
328 i = -1;
329 while(++i<yukcommands) ick_abstained[i]--;
330 }
331 yukloop = 0;
332 yukerrcmdg = -1;
333 do
334 {
335 printf("yuk007 "); /* this is our prompt, a sort of reverse
336 INTERCAL version of % */
337 (void) fgets(buf,20,stdin);
338 if(!strchr(buf,'\n'))
339 {
340 ick_lose(IE810,emitlineno,(const char*)NULL);
341 }
342 templine=0;
343 switch(*buf)
344 {
345 case '?':
346 case '@':
347 (void) puts("a<line>\tabstain once from all non-ick_abstained commands on <line>");
348 (void) puts("b<line>\tset breakpoint at <line>");
349 (void) puts("c\tcontinue execution until a breakpoint is reached");
350 (void) puts("d<line>\tdelete breakpoint at <line>");
351 (void) puts("e<line>\texplain the ick_main expression on <line>");
352 (void) puts("f<line>\tstop producing messages when commands on <line> are run");
353 (void) puts("g<line>\tchange currently executing command to the ick_first command");
354 (void) puts("\ton <line> or the ick_next command if already on <line>");
355 (void) puts("h\tlist 10 lines either side of the current line");
356 (void) puts("i<var>\tignore a variable");
357 (void) puts("j<var>\tremember a variable");
358 (void) puts("k\tcontinue until we RESUME back to the current nexting level");
359 (void) puts("\t(that is, step unless we are on a NEXT, in which case execute");
360 (void) puts("\tuntil a RESUME or FORGET back to the same or smaller NEXT stack)");
361 (void) puts("l<line>\tlist 10 lines either side of <line>");
362 (void) puts("m<line>\tproduce a message every time a command on <line> is run");
363 (void) puts("n\tshow the NEXT stack");
364 (void) puts("o\tcontinue until we RESUME/FORGET below the current nexting level");
365 (void) puts("\tie until the NEXT stack becomes smaller than it is at present");
366 (void) puts("p\tdisplay the values of all onespot and twospot variables");
367 (void) puts("q\tabort execution");
368 (void) puts("r<line>\treinstate once all ick_abstained commands on <line>");
369 (void) puts("s\texecute one command");
370 (void) puts("t\tcontinue until a breakpoint, displaying all lines executed");
371 (void) puts("u<line>\texecute until just before <line> is reached");
372 (void) puts("v<var>\tshow value of variable every time a command is printed");
373 (void) puts("w\tshow the current line and current command");
374 (void) puts("x<var>\tremove a variable view, breakchange, or breakzero");
375 (void) puts("y<var>\tview variable every displayed line, and break on change");
376 (void) puts("z<var>\tview variable every displayed line, and break on zero");
377 (void) puts("<var>\tview the value of a onespot or twospot variable");
378 (void) puts("<<var>\tset the value of a onespot or twospot variable");
379 (void) puts("*\tview the GNU General Public License");
380 (void) puts("?\tview this help screen");
381 (void) puts("@\tview this help screen");
382 (void) puts("Line numbers refer to lines of source code, not line labels.");
383 (void) puts("Listings have (Axxxxxx) at the start of each line: this shows");
384 (void) puts("the abstention status of each command on that line.");
385 (void) puts("The values of variables must be input in proper INTERCAL");
386 (void) puts("notation (i.e. ONE TWO THREE), and are output as butchered");
387 (void) puts("Roman ick_numerals.");
388 #ifdef __DJGPP__
389 (void) puts("You can press <CTRL>-<BREAK> to interrupt an executing program.");
390 #else
391 (void) puts("You can press <CTRL>-C to interrupt an executing program.");
392 #endif
393 break;
394 case 'q':
395 exit(0);
396 /*@-unreachable@*/ break; /*@=unreachable@*/
397 case 'n':
398 i=ick_nextindex;
399 if(!i)
400 {
401 (void) puts("The NEXT stack is empty.");
402 }
403 else
404 {
405 (void) puts("Commands NEXTED from:");
406 while(i--)
407 {
408 /* write NEXT line */
409 printf("%5d:\t%s\n",lineofaboff[ick_next[i]-1],
410 textlines[lineofaboff[ick_next[i]-1]]);
411 /* write NEXT command within line */
412 tempcmd=(int)ick_next[i];
413 while(tempcmd&&lineofaboff[--tempcmd]==lineofaboff[ick_next[i]-1]);
414 printf("NEXTED from command C%u: Abstained %d time%s\n",ick_next[i]-1?
415 ick_next[i]-1-tempcmd:1,ick_abstained[ick_next[i]-1],
416 ick_abstained[ick_next[i]-1]==1?".":"s.");
417 }
418 }
419 break;
420 case 'w':
421 /* write line that we're on */
422 printf("%5d:\t%s\n",lineofaboff[aboff],text);
423 /* write command within line that we're on */
424 tempcmd=aboff;
425 while(tempcmd&&lineofaboff[--tempcmd]==lineofaboff[aboff]);
426 printf("On C%d: Abstained %d time%s\n",aboff?aboff-tempcmd:1,ick_abstained[aboff],
427 ick_abstained[aboff]==1?".":"s.");
428 break;
429 case 'p':
430 i=-1;
431 while(++i,1)
432 {
433 if(yukvars[i].vartype==YUKEND) break;
434 if(yukvars[i].vartype==ick_ONESPOT)
435 {
436 printf("Variable .%d is:\n",yukvars[i].extername);
437 ick_pout(ick_onespots[yukvars[i].intername]);
438 }
439 if(yukvars[i].vartype==ick_TWOSPOT)
440 {
441 printf("Variable :%d is:\n",yukvars[i].extername);
442 ick_pout(ick_twospots[yukvars[i].intername]);
443 }
444 }
445 break;
446 case '.':
447 case ':':
448 temp = sscanf(buf+1,"%d",&templine);
449 if(templine<1 || temp != 1)
450 {
451 (void) puts("Don't know which variable you mean.");
452 break;
453 }
454 i=-1;
455 temp=0;
456 while(++i,!temp)
457 {
458 if(yukvars[i].vartype==YUKEND) break;
459 if((*buf=='.'&&yukvars[i].vartype==ick_ONESPOT)||
460 (*buf==':'&&yukvars[i].vartype==ick_TWOSPOT))
461 {
462 if(yukvars[i].extername==templine)
463 {
464 temp=1;
465 if(yukvars[i].vartype==ick_ONESPOT)
466 {
467 ick_pout(ick_onespots[yukvars[i].intername]);
468 (void) puts(ick_oneforget[yukvars[i].intername]?
469 "This variable is currently ignored.":
470 "This variable is currently remembered.");
471 }
472 if(yukvars[i].vartype==ick_TWOSPOT)
473 {
474 ick_pout(ick_twospots[yukvars[i].intername]);
475 (void) puts(ick_twoforget[yukvars[i].intername]?
476 "This variable is currently ignored.":
477 "This variable is currently remembered.");
478 }
479 }
480 }
481 }
482 if(temp) break;
483 (void) puts("That variable is not in the program.");
484 break;
485 case 'v':
486 case 'x':
487 case 'y':
488 case 'z':
489 if(buf[1]!='.'&&buf[1]!=':')
490 {
491 (void) puts("This command only works on onespot and twospot variables.");
492 break;
493 }
494 temp = sscanf(buf+2,"%d",&templine);
495 if(templine<1 || temp != 1)
496 {
497 (void) puts("Don't know which variable you mean.");
498 break;
499 }
500 i=-1;
501 temp=0;
502 while(++i,!temp)
503 {
504 if(yukvars[i].vartype==YUKEND) break;
505 if(yukvars[i].extername==templine)
506 {
507 if(buf[1]=='.'&&yukvars[i].vartype==ick_ONESPOT)
508 {
509 if(*buf=='v') onewatch[yukvars[i].intername]=(char)1;
510 if(*buf=='x') onewatch[yukvars[i].intername]=(char)0;
511 if(*buf=='y') onewatch[yukvars[i].intername]=(char)2;
512 if(*buf=='z') onewatch[yukvars[i].intername]=(char)3;
513 oneold[yukvars[i].intername]=ick_onespots[yukvars[i].intername];
514 temp=1;
515 }
516 if(buf[1]==':'&&yukvars[i].vartype==ick_TWOSPOT)
517 {
518 if(*buf=='v') twowatch[yukvars[i].intername]=(char)1;
519 if(*buf=='x') twowatch[yukvars[i].intername]=(char)0;
520 if(*buf=='y') twowatch[yukvars[i].intername]=(char)2;
521 if(*buf=='z') twowatch[yukvars[i].intername]=(char)3;
522 twoold[yukvars[i].intername]=ick_twospots[yukvars[i].intername];
523 temp=1;
524 }
525 }
526 }
527 if(!temp)
528 {
529 (void) puts("That variable is not in the program.");
530 break;
531 }
532 if(*buf=='v') (void) puts("Set a normal variable view.");
533 if(*buf=='x') (void) puts("Removed all views from that variable.");
534 if(*buf=='y') (void) puts("Set a breakchange variable view.");
535 if(*buf=='z') (void) puts("Set a breakzero variable view.");
536 break;
537 case 'i':
538 case 'j':
539 if(buf[1]!='.'&&buf[1]!=':'&&buf[1]!=','&&buf[1]!=';')
540 {
541 (void) puts("That isn't a real sort of variable.");
542 break;
543 }
544 temp = sscanf(buf+2,"%d",&templine);
545 if(templine<1 || temp != 1)
546 {
547 (void) puts("Don't know which variable you mean.");
548 break;
549 }
550 i=-1;
551 temp=0;
552 while(++i,!temp)
553 {
554 if(yukvars[i].vartype==YUKEND) break;
555 if((buf[1]=='.'&&yukvars[i].vartype==ick_ONESPOT)||
556 (buf[1]==':'&&yukvars[i].vartype==ick_TWOSPOT)||
557 (buf[1]==','&&yukvars[i].vartype==ick_TAIL)||
558 (buf[1]==';'&&yukvars[i].vartype==ick_HYBRID))
559 {
560 if(yukvars[i].extername==templine)
561 {
562 temp=1;
563 if(yukvars[i].vartype==ick_ONESPOT)
564 ick_oneforget[yukvars[i].intername]=*buf=='i';
565 if(yukvars[i].vartype==ick_TWOSPOT)
566 ick_twoforget[yukvars[i].intername]=*buf=='i';
567 if(yukvars[i].vartype==ick_TAIL)
568 ick_tailforget[yukvars[i].intername]=*buf=='i';
569 if(yukvars[i].vartype==ick_HYBRID)
570 ick_hyforget[yukvars[i].intername]=*buf=='i';
571 }
572 }
573 }
574 if(temp)
575 {
576 if(*buf=='i')
577 (void) puts("Variable ignored.");
578 else
579 (void) puts("Variable remembered.");
580 break;
581 }
582 (void) puts("That variable is not in the program.");
583 break;
584 case '<':
585 if(buf[1]!='.'&&buf[1]!=':')
586 {
587 (void) puts("You cannot set that sort of variable (if it exists at all).");
588 break;
589 }
590 temp = sscanf(buf+2,"%d",&templine);
591 if(templine<1 || temp != 1)
592 {
593 (void) puts("Don't know which variable you mean.");
594 break;
595 }
596 i=-1;
597 temp=0;
598 while(++i,!temp)
599 {
600 if(yukvars[i].vartype==YUKEND) break;
601 if((buf[1]=='.'&&yukvars[i].vartype==ick_ONESPOT)||
602 (buf[1]==':'&&yukvars[i].vartype==ick_TWOSPOT))
603 {
604 if(yukvars[i].extername==templine)
605 {
606 temp=1;
607 if(yukvars[i].vartype==ick_ONESPOT)
608 ick_onespots[yukvars[i].intername]=(ick_type16)ick_pin();
609 if(yukvars[i].vartype==ick_TWOSPOT)
610 ick_twospots[yukvars[i].intername]=(ick_type32)ick_pin();
611 /* note that when debugging, you can set an
612 ignored variable */
613 }
614 }
615 }
616 if(temp) break;
617 (void) puts("That variable is not in the program.");
618 break;
619 case 'g':
620 temp = sscanf(buf+1,"%d",&templine);
621 if(!templine || temp != 1)
622 {
623 (void) puts("Don't know which line you mean.");
624 break;
625 }
626 breakpoints[0] = templine;
627 yukloop = 1;
628 /* This is implemented by incrementing all ABSTAIN counts,
629 even the normally immutable ones on GIVE UP lines, setting
630 a temporary breakpoint ([0]) on the line given, and running the
631 program. When the breakpoint is hit singlestep will see that
632 yukloop is set (its purpose is to cause the program to go back
633 to the start when it reaches the end) and decrement all ABSTAIN
634 counts, putting the commands back the way they were. We set an error
635 breakpoint on this line in case the user is trying to jump to a
636 line with no commands (although this debugger command is called
637 'g', would I dare to describe this as a GOTO?) */
638 i = -1;
639 while(++i<yukcommands) ick_abstained[i]++;
640 yukerrcmdg = aboff;
641 singlestep = 0;
642 writelines = 0;
643 keeplooping = 0; /* to break out of the loop in the debugger! */
644 break;
645 case 'a':
646 case 'r':
647 temp = sscanf(buf+1,"%d",&templine);
648 if(!templine || temp != 1)
649 {
650 (void) puts("Don't know which line you mean.");
651 break;
652 }
653 i=-1;
654 tempcmd=1;
655 while(++i<yukcommands)
656 {
657 if(lineofaboff[i]==templine)
658 {
659 temp=ick_abstained[i];
660 if(*buf=='a') if(!temp) ick_abstained[i]=1;
661 if(*buf=='r') if(temp) ick_abstained[i]--;
662 printf("Command %d on line %d was ick_abstained %d time%s, "
663 "now ick_abstained %d time%s.\n",tempcmd,templine,
664 temp,temp==1?"":"s",ick_abstained[i],
665 ick_abstained[i]==1?"":"s");
666 tempcmd++;
667 }
668 }
669 if(tempcmd==1) (void) puts("No commands start on this line.");
670 break;
671 case 'k':
672 case 'o':
673 untilnext=ick_nextindex-(*buf=='o');
674 /*@fallthrough@*/
675 case 'c':
676 singlestep=0;
677 writelines=0;
678 keeplooping=0;
679 break;
680 case 'b':
681 temp = sscanf(buf+1,"%d",&templine);
682 if(templine && temp == 1)
683 {
684 printf("Breakpoint set at line %d.\n",templine);
685 breakpoints[nbreakpoints++]=templine;
686 if(nbreakpoints>=80) ick_lose(IE811,emitlineno,(const char*)NULL);
687 }
688 else
689 (void) puts("Don't know which line you mean.");
690 break;
691 case 'd':
692 temp = sscanf(buf+1,"%d",&templine);
693 if(templine && temp == 1)
694 {
695 printf("All breakpoints removed from line %d.\n",templine);
696 i=nbreakpoints;
697 while(i--) if(templine==breakpoints[i])
698 {
699 memmove(breakpoints+i,breakpoints+i+1,sizeof(int)*(nbreakpoints-i));
700 nbreakpoints--;
701 }
702 }
703 else
704 (void) puts("Don't know which line you mean.");
705 break;
706 case 'm':
707 temp = sscanf(buf+1,"%d",&templine);
708 if(templine && temp == 1)
709 {
710 printf("Monitor set at line %d.\n",templine);
711 monitors[nmonitors++]=templine;
712 if(nmonitors>=80) ick_lose(IE811,emitlineno,(const char*)NULL);
713 }
714 else
715 (void) puts("Don't know which line you mean.");
716 break;
717 case 'f':
718 temp = sscanf(buf+1,"%d",&templine);
719 if(templine && temp == 1)
720 {
721 printf("All monitors removed from line %d.\n",templine);
722 i=nmonitors;
723 while(i--) if(templine==monitors[i])
724 {
725 memmove(monitors+i,monitors+i+1,sizeof(int)*(nmonitors-i));
726 nmonitors--;
727 }
728 }
729 else
730 (void) puts("Don't know which line you mean.");
731 break;
732 case 's':
733 singlestep=1;
734 writelines=1;
735 keeplooping=0;
736 break;
737 case 't':
738 singlestep=0;
739 writelines=1;
740 keeplooping=0;
741 break;
742 case 'u':
743 temp = sscanf(buf+1,"%d",&templine);
744 if(templine && temp == 1)
745 {
746 breakpoints[0]=templine;
747 singlestep=0;
748 writelines=0;
749 keeplooping=0;
750 }
751 else
752 (void) puts("Don't know which line you mean.");
753 break;
754 case 'e':
755 temp = sscanf(buf+1,"%d",&templine);
756 if(!templine || temp != 1)
757 {
758 (void) puts("Don't know which line you mean.");
759 break;
760 }
761 tempcmd=-1;
762 temp=0;
763 i=0;
764 while(++tempcmd<yukcommands)
765 {
766 if(lineofaboff[tempcmd]==templine)
767 {
768 if(!yukexplain[tempcmd]) ++i;
769 else
770 {
771 printf("C%d: Expression is %s\n",++i,yukexplain[tempcmd]);
772 temp++;
773 }
774 }
775 }
776 if(!temp) (void) puts("No expressions on that line.");
777 break;
778 case 'l':
779 temp = sscanf(buf+1,"%d",&templine);
780 if(!templine || temp != 1)
781 {
782 (void) puts("Don't know which line you mean.");
783 break;
784 }
785 /*@fallthrough@*/
786 case 'h':
787 if(!templine) templine=lineofaboff[aboff];
788 templine-=10;
789 if(templine+21>=yuklines) templine=yuklines-22;
790 if(templine<1) templine=1;
791 i=templine;
792 while(i<templine+21&&i<yuklines)
793 {
794 buf[6]='\0';
795 buf[0]=buf[1]=buf[2]=buf[3]=buf[4]=buf[5]=' ';
796 tempcmd=-1;
797 temp=0;
798 while(++tempcmd<yukcommands)
799 {
800 if(lineofaboff[tempcmd]==i)
801 {
802 if(ick_abstained[tempcmd]>9) buf[temp++]='!';
803 else buf[temp++]='0'+(char)ick_abstained[tempcmd];
804 if(temp==6) break;
805 }
806 }
807 printf("(A%s)%5d:\t%s\n",buf,i,textlines[i]);
808 i++;
809 }
810 break;
811 case '*':
812 tempcharp=ick_findandtestopen("COPYING.txt",globalargv[1],
813 "r",globalargv[2]);
814 if(tempcharp != NULL)
815 {
816 #ifndef HAVE_SNPRINTF
817 (void) sprintf(copyloc,"more < %s",tempcharp);
818 #else
819 (void) snprintf(copyloc,sizeof copyloc,"more < %s",tempcharp);
820 #endif
821 (void) system(copyloc); /* display the GNU GPL copyright */
822 }
823 else
824 (void) puts("Couldn't find license file. See the file COPYING.txt that\n"
825 "came with your C-INTERCAL distribution.");
826 break;
827 default:
828 (void) puts("Not sure what you mean. Try typing ?<RET>.");
829 break;
830 }
831 } while(keeplooping);
832 }
833 }
834 firstrun=0;
835 }