diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interps/c-intercal/src/yuk.c	Sun Dec 09 19:30:08 2012 +0000
@@ -0,0 +1,835 @@
+/****************************************************************************
+
+NAME
+    yuk.c -- C-INTERCAL debugger and profiler code, linked into programs.
+
+DESCRIPTION
+    File linked into programs as a debugger or profiler.
+
+LICENSE TERMS
+    Copyright (C) 2006 Alex Smith
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+****************************************************************************/
+#include "config.h" /* AIS: Generated by autoconf */
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# ifdef TIME_WITH_SYS_TIME
+#  include <time.h>
+# endif
+#else
+# include <time.h>
+#endif
+#include <signal.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <setjmp.h>
+#include <string.h>
+
+#define YUKDEBUG 1
+
+#include "yuk.h"
+#include "ick_lose.h"
+#include "sizes.h"
+#include "abcess.h"
+#include "uncommon.h"
+
+#if YPTIMERTYPE == 4
+#include <sys/times.h>
+#endif
+
+extern signed char onewatch[];
+extern signed char twowatch[];
+extern ick_type16      oneold[];
+extern ick_type32      twoold[];
+
+char** globalargv;
+int globalargc;
+int yuklines = 0;
+int yukloop = 0;
+int yukcommands = 0; /* these 5 lines because externs must be defined
+			somewhere */
+/* Global variable storage types:
+   static: limited to the file
+   unadorned: defining an extern
+   extern: defined elsewhere (unless initialised) */
+
+static char buf[21];
+
+static sig_atomic_t singlestep = 1; /* if 0, run until a breakpoint */
+static sig_atomic_t writelines = 1; /* whether to display executed lines onscreen */
+static int breakpoints[80]; /* initialised to all 0s. Breakpoint locations */
+static int nbreakpoints = 1; /* how many breakpoints we have */
+static int monitors[80]; /* monitors give a message when program flow passes them */
+static int nmonitors = 0;
+static int untilnext = -1; /* NEXTING level to break the program at */
+static int firstrun = 1; /* ick_first time an interactive command point is reached */
+static int yukerrcmdg = -1; /* the aboff that indicates an error in the 'g' command */
+
+static yptimer tickcount; /* yptimer of last run */
+static int lastaboff = 0; /* last value of aboff */
+
+static void handlesigint(int i)
+{ /* this is a signal handler, so can't do much */
+  singlestep = 1;
+  writelines = 1;
+  /*@-noeffect@*/ (void) i; /*@=noeffect@*/
+}
+
+#if YPTIMERTYPE==1 || YPTIMERTYPE==2
+static yptimer yukgettimeofday()
+{
+  static struct timeval tp;
+  yptimer temp;
+  /* gettimeofday is POSIX; config.sh has checked that it's
+     available, so turn off the unrecog warning */
+  /*@-unrecog@*/
+  gettimeofday(&tp,0);
+  /*@=unrecog@*/
+  temp=(yptimer)tp.tv_usec +
+    (yptimer)tp.tv_sec * (yptimer)1000000LU;
+  /* here we make use of unsigned wraparound. In the case
+     YPTIMERTYPE == 1, it seems quite likely that we're going
+     to wraparound, but because everything is cast to the
+     unsigned integral type yptimer, we get a value that will
+     wraparound in such a way that - will give us the correct
+     time interval. */
+  return temp;
+}
+#elif YPTIMERTYPE == 4
+yptimer yuktimes()
+{
+  static struct tms tp;
+  times(&tp);
+  return tp.tms_utime + tp.tms_stime;
+}
+#elif YPTIMERTYPE == 5
+static yptimer yukclock_gettime()
+{
+  static struct timespec ts;
+  yptimer temp;
+  /* We've checked that this function is available; -lrt will be linked in. */
+  /*@-unrecog@*/
+#if defined(_POSIX_CPUTIME) && _POSIX_CPUTIME > 0
+  clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&ts);
+#else
+# if defined(_POSIX_THREAD_CPUTIME) && _POSIX_THREAD_CPUTIME > 0
+  clock_gettime(CLOCK_THREAD_CPUTIME_ID,&ts);
+# else
+#  if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK > 0
+  clock_gettime(CLOCK_MONOTONIC,&ts);
+#  else
+#   ifndef CLOCK_REALTIME
+#    error clock_gettime is defined, but no clocks seem to be; try changing YPTIMERTYPE in src/yuk.h
+#   endif
+  clock_gettime(CLOCK_REALTIME,&ts);
+#  endif
+# endif
+#endif
+  /*@=unrecog@*/
+  temp=(yptimer)ts.tv_nsec +
+    (yptimer)ts.tv_sec * (yptimer)1000000000LU;
+  /* using wraparound as with gettimeofday */
+  return temp;
+}
+#endif /* YPTIMERTYPE */
+
+void yukterm(void)
+{
+  int i,lastline,thisline,inrow=0;
+  yptimer avgtime,avgtime2;
+  if(yukopts==2) (void) puts("Program ended without error.");
+  if(!(yukopts&1)) return;
+  /* Print profiling information */
+  (void) puts("Profiling information saved to \"yuk.out\".");
+  (void) freopen("yuk.out","w",stdout);
+  i=-1;
+  lastline=-1;
+  while(++i<yukcommands)
+  {
+    thisline=lineofaboff[i];
+    if(thisline==lastline) inrow++; else
+    {
+      inrow=1;
+      printf("%5d:\t%s\n",thisline,textlines[thisline]);
+    }
+    lastline=thisline;
+    avgtime=ypexecount[i]+ypabscount[i];
+    if(avgtime) avgtime=ypexectime[i]/avgtime;
+    avgtime2=0;
+    if(ypexecount[i]) avgtime2=ypexectime[i]/ypexecount[i];
+    /*@-formatcode@*/ /* Splint doesn't understand string interpolation */
+    printf("C%d: Time%4" YPTIMERTFORMAT ".%0" YPTIMERTFORMATD
+	   ", Avg%2" YPTIMERTFORMAT ".%0" YPTIMERTFORMATD ", "
+	   "Avg Exec%2" YPTIMERTFORMAT ".%0" YPTIMERTFORMATD
+	   ", Exec%8" YPCOUNTERTFORMAT ", Abs%8" YPCOUNTERTFORMAT "\n",
+	   inrow,ypexectime[i]/YPTIMERSCALE, ypexectime[i]%YPTIMERSCALE,
+	   avgtime/YPTIMERSCALE, avgtime%YPTIMERSCALE,
+	   avgtime2/YPTIMERSCALE, avgtime2%YPTIMERSCALE,
+	   ypexecount[i],ypabscount[i]);
+    /*@=formatcode@*/
+  }
+}
+
+void yukline(int aboff,int emitlineno)
+{ /* this runs every time a source line is encountered */
+  int i;
+  int broken; /* hit a breakpoint, monitorpoint, viewbreak, until */
+  int keeplooping;
+  int templine;
+  int tempcmd;
+  int temp;
+  yptimer temptick;
+  char* text=textlines[lineofaboff[aboff]];
+  char copyloc[BUFSIZ+9];
+  const char* tempcharp;
+  if(!yukopts) return;
+  if(globalargc!=3)
+    ick_lose(IE778,emitlineno,(const char*)NULL);
+  if(yukopts & 1)
+  { /* profile */
+    temptick=YPGETTIME;
+    if(lastaboff) ypexectime[lastaboff]+=(yptimer)(temptick-tickcount);
+    tickcount=temptick;
+    if(ick_abstained[aboff]) ypabscount[aboff]++;
+    else ypexecount[aboff]++;
+    lastaboff=aboff;
+  }
+  if(yukopts & 2)
+  { /* debug */
+    if(firstrun)
+    {
+      /* GNU GPL requires a copyright notice at this point */
+      (void) puts("yuk debugger Copyright (C) 2006 Alex Smith.");
+      (void) puts("The yuk debugger is covered by the GNU GPL and can");
+      (void) puts("be redistributed freely, but comes with ABSOLUTELY");
+      (void) puts("NO WARRANTY. For more information, type *<RET>.\n");
+      (void) puts("For help on yuk, type ?<RET>.\n");
+    }
+    i=nbreakpoints;
+    broken=0;
+    while(i--) broken|=breakpoints[i]==lineofaboff[aboff];
+    if(yukloop&&broken&&*breakpoints!=lineofaboff[aboff]) broken=0;
+    if(broken)
+    {
+      if(*breakpoints!=lineofaboff[aboff])
+	printf("Breakpoint hit at line %d:\n",lineofaboff[aboff]);
+      singlestep=1;
+    }
+    else
+    {
+      i=nmonitors;
+      while(i--) broken|=monitors[i]==lineofaboff[aboff];
+      if(yukloop) broken=0;
+      if(broken) printf("Command flowed past line %d:\n",lineofaboff[aboff]);
+    }
+    if(ick_nextindex <= untilnext)
+    {
+      broken = 1;
+      singlestep = 1;
+    }
+    if(!broken&&yukerrcmdg==aboff)
+    {
+      singlestep = 1;
+      (void) puts("There are no commands on that line.");
+      /* To the user, nothing will have happened but the error message! */
+    }
+    i=-1;
+    while(++i,1)
+    {
+      if(yukvars[i].vartype==YUKEND) break;
+      if(yukvars[i].vartype==ick_ONESPOT)
+      {
+	if(onewatch[yukvars[i].intername] != (char)0)
+	{
+	  if(ick_onespots[yukvars[i].intername]!=oneold[yukvars[i].intername]&&
+	     onewatch[yukvars[i].intername]>(char)1)
+	  {
+	    oneold[yukvars[i].intername]=ick_onespots[yukvars[i].intername];
+	    if(onewatch[yukvars[i].intername]==(char)2||!ick_onespots[yukvars[i].intername])
+	    {
+	      /*@-formatconst@*/ /* it's safe, I checked it */
+	      printf(onewatch[yukvars[i].intername]==(char)2?
+		     "Variable .%d changed.\n":"Variable .%d became 0.\n",
+		     yukvars[i].extername);
+	      /*@=formatconst@*/
+	      broken=1; singlestep=1;
+	    }
+	  }
+	  if(writelines||broken)
+	  {
+	    printf(".%d is:\n",yukvars[i].extername);
+	    ick_pout(ick_onespots[yukvars[i].intername]);
+	  }
+	}
+      }
+      if(yukvars[i].vartype==ick_TWOSPOT)
+      {
+	if(twowatch[yukvars[i].intername] != (char)0)
+	{
+	  if(ick_twospots[yukvars[i].intername]!=twoold[yukvars[i].intername]&&
+	     twowatch[yukvars[i].intername] > (char)1)
+	  {
+	    twoold[yukvars[i].intername]=ick_twospots[yukvars[i].intername];
+	    if(twowatch[yukvars[i].intername]==(char)2||!ick_twospots[yukvars[i].intername])
+	    {
+	      /*@-formatconst@*/ /* there's just the one %d each way round */
+	      printf(twowatch[yukvars[i].intername]==(char)2?
+		     "Variable :%d changed.\n":"Variable :%d became 0.\n",
+		     yukvars[i].extername);
+	      /*@=formatconst@*/
+	      broken=1; singlestep=1;
+	    }
+	  }
+	  if(writelines||broken)
+	  {
+	    printf(":%d is:\n",yukvars[i].extername);
+	    ick_pout(ick_twospots[yukvars[i].intername]);
+	  }
+	}
+      }
+    }
+    if(writelines||broken)
+    {
+      /* write line that we're on */
+      printf("%5d:\t%s\n",lineofaboff[aboff],text);
+      /* write command within line that we're on */
+      tempcmd=aboff;
+      while(tempcmd&&lineofaboff[--tempcmd]==lineofaboff[aboff]);
+      printf("On C%d: Abstained %d time%s\n",aboff?aboff-tempcmd:1,
+	     ick_abstained[aboff]-yukloop,ick_abstained[aboff]-yukloop==1?".":"s.");
+    }
+    if(singlestep)
+    {
+      (void)signal(SIGINT,handlesigint); /* placing this line here means that a rapid
+					    ^C^C will terminate the program, if it's
+					    stuck in a loop somewhere */
+      keeplooping = 1;
+      breakpoints[0] = 0; /* breakpoints[0] goes whenever a breakpoint is hit */
+      untilnext = -1;
+      if(yukloop)
+      { /* reverse the abstentions that g caused */
+	i = -1;
+	while(++i<yukcommands) ick_abstained[i]--;
+      }
+      yukloop = 0;
+      yukerrcmdg = -1;
+      do
+      {
+	printf("yuk007 "); /* this is our prompt, a sort of reverse
+			      INTERCAL version of % */
+	(void) fgets(buf,20,stdin);
+	if(!strchr(buf,'\n'))
+	{
+	  ick_lose(IE810,emitlineno,(const char*)NULL);
+	}
+	templine=0;
+	switch(*buf)
+	{
+	case '?':
+	case '@':
+	  (void) puts("a<line>\tabstain once from all non-ick_abstained commands on <line>");
+	  (void) puts("b<line>\tset breakpoint at <line>");
+	  (void) puts("c\tcontinue execution until a breakpoint is reached");
+	  (void) puts("d<line>\tdelete breakpoint at <line>");
+	  (void) puts("e<line>\texplain the ick_main expression on <line>");
+	  (void) puts("f<line>\tstop producing messages when commands on <line> are run");
+	  (void) puts("g<line>\tchange currently executing command to the ick_first command");
+	  (void) puts("\ton <line> or the ick_next command if already on <line>");
+	  (void) puts("h\tlist 10 lines either side of the current line");
+	  (void) puts("i<var>\tignore a variable");
+	  (void) puts("j<var>\tremember a variable");
+	  (void) puts("k\tcontinue until we RESUME back to the current nexting level");
+	  (void) puts("\t(that is, step unless we are on a NEXT, in which case execute");
+	  (void) puts("\tuntil a RESUME or FORGET back to the same or smaller NEXT stack)");
+	  (void) puts("l<line>\tlist 10 lines either side of <line>");
+	  (void) puts("m<line>\tproduce a message every time a command on <line> is run");
+	  (void) puts("n\tshow the NEXT stack");
+	  (void) puts("o\tcontinue until we RESUME/FORGET below the current nexting level");
+	  (void) puts("\tie until the NEXT stack becomes smaller than it is at present");
+	  (void) puts("p\tdisplay the values of all onespot and twospot variables");
+	  (void) puts("q\tabort execution");
+	  (void) puts("r<line>\treinstate once all ick_abstained commands on <line>");
+	  (void) puts("s\texecute one command");
+	  (void) puts("t\tcontinue until a breakpoint, displaying all lines executed");
+	  (void) puts("u<line>\texecute until just before <line> is reached");
+	  (void) puts("v<var>\tshow value of variable every time a command is printed");
+	  (void) puts("w\tshow the current line and current command");
+	  (void) puts("x<var>\tremove a variable view, breakchange, or breakzero");
+	  (void) puts("y<var>\tview variable every displayed line, and break on change");
+	  (void) puts("z<var>\tview variable every displayed line, and break on zero");
+	  (void) puts("<var>\tview the value of a onespot or twospot variable");
+	  (void) puts("<<var>\tset the value of a onespot or twospot variable");
+	  (void) puts("*\tview the GNU General Public License");
+	  (void) puts("?\tview this help screen");
+	  (void) puts("@\tview this help screen");
+	  (void) puts("Line numbers refer to lines of source code, not line labels.");
+	  (void) puts("Listings have (Axxxxxx) at the start of each line: this shows");
+	  (void) puts("the abstention status of each command on that line.");
+	  (void) puts("The values of variables must be input in proper INTERCAL");
+	  (void) puts("notation (i.e. ONE TWO THREE), and are output as butchered");
+	  (void) puts("Roman ick_numerals.");
+#ifdef __DJGPP__
+	  (void) puts("You can press <CTRL>-<BREAK> to interrupt an executing program.");
+#else
+	  (void) puts("You can press <CTRL>-C to interrupt an executing program.");
+#endif
+	  break;
+	case 'q':
+	  exit(0);
+	  /*@-unreachable@*/ break; /*@=unreachable@*/
+	case 'n':
+	  i=ick_nextindex;
+	  if(!i)
+	  {
+	    (void) puts("The NEXT stack is empty.");
+	  }
+	  else
+	  {
+	    (void) puts("Commands NEXTED from:");
+	    while(i--)
+	    {
+	      /* write NEXT line */
+	      printf("%5d:\t%s\n",lineofaboff[ick_next[i]-1],
+		     textlines[lineofaboff[ick_next[i]-1]]);
+	      /* write NEXT command within line */
+	      tempcmd=(int)ick_next[i];
+	      while(tempcmd&&lineofaboff[--tempcmd]==lineofaboff[ick_next[i]-1]);
+	      printf("NEXTED from command C%u: Abstained %d time%s\n",ick_next[i]-1?
+		     ick_next[i]-1-tempcmd:1,ick_abstained[ick_next[i]-1],
+		     ick_abstained[ick_next[i]-1]==1?".":"s.");
+    	    }
+	  }
+	  break;
+	case 'w':
+	  /* write line that we're on */
+	  printf("%5d:\t%s\n",lineofaboff[aboff],text);
+	  /* write command within line that we're on */
+	  tempcmd=aboff;
+	  while(tempcmd&&lineofaboff[--tempcmd]==lineofaboff[aboff]);
+	  printf("On C%d: Abstained %d time%s\n",aboff?aboff-tempcmd:1,ick_abstained[aboff],
+	     ick_abstained[aboff]==1?".":"s.");
+	  break;
+	case 'p':
+	  i=-1;
+	  while(++i,1)
+	  {
+	    if(yukvars[i].vartype==YUKEND) break;
+	    if(yukvars[i].vartype==ick_ONESPOT)
+	    {
+	      printf("Variable .%d is:\n",yukvars[i].extername);
+	      ick_pout(ick_onespots[yukvars[i].intername]);
+	    }
+	    if(yukvars[i].vartype==ick_TWOSPOT)
+	    {
+	      printf("Variable :%d is:\n",yukvars[i].extername);
+	      ick_pout(ick_twospots[yukvars[i].intername]);
+	    }
+	  }
+	  break;
+	case '.':
+	case ':':
+	  temp = sscanf(buf+1,"%d",&templine);
+	  if(templine<1 || temp != 1)
+	  {
+	    (void) puts("Don't know which variable you mean.");
+	    break;
+	  }
+	  i=-1;
+	  temp=0;
+	  while(++i,!temp)
+	  {
+	    if(yukvars[i].vartype==YUKEND) break;
+	    if((*buf=='.'&&yukvars[i].vartype==ick_ONESPOT)||
+	       (*buf==':'&&yukvars[i].vartype==ick_TWOSPOT))
+	    {
+	      if(yukvars[i].extername==templine)
+	      {
+		temp=1;
+		if(yukvars[i].vartype==ick_ONESPOT)
+		{
+		  ick_pout(ick_onespots[yukvars[i].intername]);
+		  (void) puts(ick_oneforget[yukvars[i].intername]?
+		       "This variable is currently ignored.":
+		       "This variable is currently remembered.");
+		}
+		if(yukvars[i].vartype==ick_TWOSPOT)
+		{
+		  ick_pout(ick_twospots[yukvars[i].intername]);
+		  (void) puts(ick_twoforget[yukvars[i].intername]?
+		       "This variable is currently ignored.":
+		       "This variable is currently remembered.");
+		}
+	      }
+	    }
+	  }
+	  if(temp) break;
+	  (void) puts("That variable is not in the program.");
+	  break;
+	case 'v':
+	case 'x':
+	case 'y':
+	case 'z':
+	  if(buf[1]!='.'&&buf[1]!=':')
+	  {
+	    (void) puts("This command only works on onespot and twospot variables.");
+	    break;
+	  }
+	  temp = sscanf(buf+2,"%d",&templine);
+	  if(templine<1 || temp != 1)
+	  {
+	    (void) puts("Don't know which variable you mean.");
+	    break;
+	  }
+	  i=-1;
+	  temp=0;
+	  while(++i,!temp)
+	  {
+	    if(yukvars[i].vartype==YUKEND) break;
+	    if(yukvars[i].extername==templine)
+	    {
+	      if(buf[1]=='.'&&yukvars[i].vartype==ick_ONESPOT)
+	      {
+		if(*buf=='v') onewatch[yukvars[i].intername]=(char)1;
+		if(*buf=='x') onewatch[yukvars[i].intername]=(char)0;
+		if(*buf=='y') onewatch[yukvars[i].intername]=(char)2;
+		if(*buf=='z') onewatch[yukvars[i].intername]=(char)3;
+		oneold[yukvars[i].intername]=ick_onespots[yukvars[i].intername];
+		temp=1;
+	      }
+	      if(buf[1]==':'&&yukvars[i].vartype==ick_TWOSPOT)
+	      {
+		if(*buf=='v') twowatch[yukvars[i].intername]=(char)1;
+		if(*buf=='x') twowatch[yukvars[i].intername]=(char)0;
+		if(*buf=='y') twowatch[yukvars[i].intername]=(char)2;
+		if(*buf=='z') twowatch[yukvars[i].intername]=(char)3;
+		twoold[yukvars[i].intername]=ick_twospots[yukvars[i].intername];
+		temp=1;
+	      }
+	    }
+	  }
+	  if(!temp)
+	  {
+	    (void) puts("That variable is not in the program.");
+	    break;
+	  }
+	  if(*buf=='v') (void) puts("Set a normal variable view.");
+	  if(*buf=='x') (void) puts("Removed all views from that variable.");
+	  if(*buf=='y') (void) puts("Set a breakchange variable view.");
+	  if(*buf=='z') (void) puts("Set a breakzero variable view.");
+	  break;
+	case 'i':
+	case 'j':
+	  if(buf[1]!='.'&&buf[1]!=':'&&buf[1]!=','&&buf[1]!=';')
+	  {
+	    (void) puts("That isn't a real sort of variable.");
+	    break;
+	  }
+	  temp = sscanf(buf+2,"%d",&templine);
+	  if(templine<1 || temp != 1)
+	  {
+	    (void) puts("Don't know which variable you mean.");
+	    break;
+	  }
+	  i=-1;
+	  temp=0;
+	  while(++i,!temp)
+	  {
+	    if(yukvars[i].vartype==YUKEND) break;
+	    if((buf[1]=='.'&&yukvars[i].vartype==ick_ONESPOT)||
+	       (buf[1]==':'&&yukvars[i].vartype==ick_TWOSPOT)||
+	       (buf[1]==','&&yukvars[i].vartype==ick_TAIL)||
+	       (buf[1]==';'&&yukvars[i].vartype==ick_HYBRID))
+	    {
+	      if(yukvars[i].extername==templine)
+	      {
+		temp=1;
+		if(yukvars[i].vartype==ick_ONESPOT)
+		  ick_oneforget[yukvars[i].intername]=*buf=='i';
+		if(yukvars[i].vartype==ick_TWOSPOT)
+		  ick_twoforget[yukvars[i].intername]=*buf=='i';
+		if(yukvars[i].vartype==ick_TAIL)
+		  ick_tailforget[yukvars[i].intername]=*buf=='i';
+		if(yukvars[i].vartype==ick_HYBRID)
+		  ick_hyforget[yukvars[i].intername]=*buf=='i';
+	      }
+	    }
+	  }
+	  if(temp)
+	  {
+	    if(*buf=='i')
+	      (void) puts("Variable ignored.");
+	    else
+	      (void) puts("Variable remembered.");
+	    break;
+	  }
+	  (void) puts("That variable is not in the program.");
+	  break;
+	  	case '<':
+	  if(buf[1]!='.'&&buf[1]!=':')
+	  {
+	    (void) puts("You cannot set that sort of variable (if it exists at all).");
+	    break;
+	  }
+	  temp = sscanf(buf+2,"%d",&templine);
+	  if(templine<1 || temp != 1)
+	  {
+	    (void) puts("Don't know which variable you mean.");
+	    break;
+	  }
+	  i=-1;
+	  temp=0;
+	  while(++i,!temp)
+	  {
+	    if(yukvars[i].vartype==YUKEND) break;
+	    if((buf[1]=='.'&&yukvars[i].vartype==ick_ONESPOT)||
+	       (buf[1]==':'&&yukvars[i].vartype==ick_TWOSPOT))
+	    {
+	      if(yukvars[i].extername==templine)
+	      {
+		temp=1;
+		if(yukvars[i].vartype==ick_ONESPOT)
+		  ick_onespots[yukvars[i].intername]=(ick_type16)ick_pin();
+		if(yukvars[i].vartype==ick_TWOSPOT)
+		  ick_twospots[yukvars[i].intername]=(ick_type32)ick_pin();
+		/* note that when debugging, you can set an
+		   ignored variable */
+	      }
+	    }
+	  }
+	  if(temp) break;
+	  (void) puts("That variable is not in the program.");
+	  break;
+	case 'g':
+	  temp = sscanf(buf+1,"%d",&templine);
+	  if(!templine || temp != 1)
+	  {
+	    (void) puts("Don't know which line you mean.");
+	    break;
+	  }
+	  breakpoints[0] = templine;
+	  yukloop = 1;
+	  /* This is implemented by incrementing all ABSTAIN counts,
+	     even the normally immutable ones on GIVE UP lines, setting
+	     a temporary breakpoint ([0]) on the line given, and running the
+	     program. When the breakpoint is hit singlestep will see that
+	     yukloop is set (its purpose is to cause the program to go back
+	     to the start when it reaches the end) and decrement all ABSTAIN
+	     counts, putting the commands back the way they were. We set an error
+	     breakpoint on this line in case the user is trying to jump to a
+	     line with no commands (although this debugger command is called
+	     'g', would I dare to describe this as a GOTO?) */
+	  i = -1;
+	  while(++i<yukcommands) ick_abstained[i]++;
+	  yukerrcmdg = aboff;
+	  singlestep = 0;
+	  writelines = 0;
+	  keeplooping = 0; /* to break out of the loop in the debugger! */
+	  break;
+	case 'a':
+	case 'r':
+	  temp = sscanf(buf+1,"%d",&templine);
+	  if(!templine || temp != 1)
+	  {
+	    (void) puts("Don't know which line you mean.");
+	    break;
+	  }
+	  i=-1;
+	  tempcmd=1;
+	  while(++i<yukcommands)
+	  {
+	    if(lineofaboff[i]==templine)
+	    {
+	      temp=ick_abstained[i];
+	      if(*buf=='a') if(!temp) ick_abstained[i]=1;
+	      if(*buf=='r') if(temp) ick_abstained[i]--;
+	      printf("Command %d on line %d was ick_abstained %d time%s, "
+		     "now ick_abstained %d time%s.\n",tempcmd,templine,
+		     temp,temp==1?"":"s",ick_abstained[i],
+		     ick_abstained[i]==1?"":"s");
+	      tempcmd++;
+	    }
+	  }
+	  if(tempcmd==1) (void) puts("No commands start on this line.");
+	  break;
+	case 'k':
+	case 'o':
+	  untilnext=ick_nextindex-(*buf=='o');
+	  /*@fallthrough@*/
+	case 'c':
+	  singlestep=0;
+	  writelines=0;
+	  keeplooping=0;
+	  break;
+	case 'b':
+	  temp = sscanf(buf+1,"%d",&templine);
+	  if(templine && temp == 1)
+	  {
+	    printf("Breakpoint set at line %d.\n",templine);
+	    breakpoints[nbreakpoints++]=templine;
+	    if(nbreakpoints>=80) ick_lose(IE811,emitlineno,(const char*)NULL);
+	  }
+	  else
+	    (void) puts("Don't know which line you mean.");
+	  break;
+	case 'd':
+	  temp = sscanf(buf+1,"%d",&templine);
+	  if(templine && temp == 1)
+	  {
+	    printf("All breakpoints removed from line %d.\n",templine);
+	    i=nbreakpoints;
+	    while(i--) if(templine==breakpoints[i])
+	    {
+	      memmove(breakpoints+i,breakpoints+i+1,sizeof(int)*(nbreakpoints-i));
+	      nbreakpoints--;
+	    }
+	  }
+	  else
+	    (void) puts("Don't know which line you mean.");
+	  break;
+	case 'm':
+	  temp = sscanf(buf+1,"%d",&templine);
+	  if(templine && temp == 1)
+	  {
+	    printf("Monitor set at line %d.\n",templine);
+	    monitors[nmonitors++]=templine;
+	    if(nmonitors>=80) ick_lose(IE811,emitlineno,(const char*)NULL);
+	  }
+	  else
+	    (void) puts("Don't know which line you mean.");
+	  break;
+	case 'f':
+	  temp = sscanf(buf+1,"%d",&templine);
+	  if(templine && temp == 1)
+	  {
+	    printf("All monitors removed from line %d.\n",templine);
+	    i=nmonitors;
+	    while(i--) if(templine==monitors[i])
+	    {
+	      memmove(monitors+i,monitors+i+1,sizeof(int)*(nmonitors-i));
+	      nmonitors--;
+	    }
+	  }
+	  else
+	    (void) puts("Don't know which line you mean.");
+	  break;
+	case 's':
+	  singlestep=1;
+	  writelines=1;
+	  keeplooping=0;
+	  break;
+	case 't':
+	  singlestep=0;
+	  writelines=1;
+	  keeplooping=0;
+	  break;
+	case 'u':
+	  temp = sscanf(buf+1,"%d",&templine);
+	  if(templine && temp == 1)
+	  {
+	    breakpoints[0]=templine;
+	    singlestep=0;
+	    writelines=0;
+	    keeplooping=0;
+	  }
+	  else
+	    (void) puts("Don't know which line you mean.");
+	  break;
+	case 'e':
+	  temp = sscanf(buf+1,"%d",&templine);
+	  if(!templine || temp != 1)
+	  {
+	    (void) puts("Don't know which line you mean.");
+	    break;
+	  }
+	  tempcmd=-1;
+	  temp=0;
+	  i=0;
+	  while(++tempcmd<yukcommands)
+	  {
+	    if(lineofaboff[tempcmd]==templine)
+	    {
+	      if(!yukexplain[tempcmd]) ++i;
+	      else
+	      {
+		printf("C%d: Expression is %s\n",++i,yukexplain[tempcmd]);
+		temp++;
+	      }
+	    }
+	  }
+	  if(!temp) (void) puts("No expressions on that line.");
+	  break;
+	case 'l':
+	  temp = sscanf(buf+1,"%d",&templine);
+	  if(!templine || temp != 1)
+	  {
+	    (void) puts("Don't know which line you mean.");
+	    break;
+	  }
+	  /*@fallthrough@*/
+	case 'h':
+	  if(!templine) templine=lineofaboff[aboff];
+	  templine-=10;
+	  if(templine+21>=yuklines) templine=yuklines-22;
+	  if(templine<1) templine=1;
+	  i=templine;
+	  while(i<templine+21&&i<yuklines)
+	  {
+	    buf[6]='\0';
+	    buf[0]=buf[1]=buf[2]=buf[3]=buf[4]=buf[5]=' ';
+	    tempcmd=-1;
+	    temp=0;
+	    while(++tempcmd<yukcommands)
+	    {
+	      if(lineofaboff[tempcmd]==i)
+	      {
+		if(ick_abstained[tempcmd]>9) buf[temp++]='!';
+		else buf[temp++]='0'+(char)ick_abstained[tempcmd];
+		if(temp==6) break;
+	      }
+	    }
+	    printf("(A%s)%5d:\t%s\n",buf,i,textlines[i]);
+	    i++;
+	  }
+	  break;
+	case '*':
+	  tempcharp=ick_findandtestopen("COPYING.txt",globalargv[1],
+				    "r",globalargv[2]);
+	  if(tempcharp != NULL)
+	  {
+#ifndef HAVE_SNPRINTF
+	    (void) sprintf(copyloc,"more < %s",tempcharp);
+#else
+	    (void) snprintf(copyloc,sizeof copyloc,"more < %s",tempcharp);
+#endif
+	    (void) system(copyloc); /* display the GNU GPL copyright */
+	  }
+	  else
+	    (void) puts("Couldn't find license file. See the file COPYING.txt that\n"
+			"came with your C-INTERCAL distribution.");
+	  break;
+	default:
+	  (void) puts("Not sure what you mean. Try typing ?<RET>.");
+	  break;
+	}
+      } while(keeplooping);
+    }
+  }
+  firstrun=0;
+}