Introduced -devel and -extras subpackages for gawk
[platform/upstream/gawk.git] / debug.c
1 /*
2  * debug.c - gawk debugger 
3  */
4
5 /* 
6  * Copyright (C) 2004, 2010, 2011 the Free Software Foundation, Inc.
7  * 
8  * This file is part of GAWK, the GNU implementation of the
9  * AWK Programming Language.
10  * 
11  * GAWK is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * GAWK is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
24  */
25
26 #include "awk.h"
27 #include "cmd.h"
28
29 #ifndef O_RDONLY
30 #include <fcntl.h>      /* open() */
31 #endif
32
33 extern int exiting;
34 extern SRCFILE *srcfiles;
35 extern INSTRUCTION *rule_list;
36 extern INSTRUCTION *code_block;
37 extern NODE **fcall_list;
38 extern long fcall_count;
39 extern FILE *output_fp;
40 extern IOBUF *curfile;
41 extern const char *command_file;
42 extern const char *get_spec_varname(Func_ptr fptr);
43 extern int r_interpret(INSTRUCTION *);
44 extern int zzparse(void);
45 #define read_command()          (void) zzparse()
46
47 extern int free_instruction(INSTRUCTION *, int *);
48 extern void destroy_symbol(char *name);
49 extern const char *redir2str(int redirtype);
50
51 static char *linebuf = NULL;    /* used to print a single line of source */
52 static size_t linebuf_len;
53
54 FILE *out_fp;
55 char *dPrompt;
56 char *commands_Prompt = "> ";   /* breakpoint or watchpoint commands list */
57 char *eval_Prompt = "@> ";              /* awk statement(s) */
58
59 int input_from_tty = FALSE;
60 int input_fd;
61
62 static SRCFILE *cur_srcfile;
63 static long cur_frame = 0;
64 static INSTRUCTION *cur_pc;
65 int cur_rule = 0;
66
67 static int prog_running = FALSE;
68
69 struct condition {
70         INSTRUCTION *code;
71         AWK_CONTEXT *ctxt;
72         char *expr;
73 };
74
75 struct commands_item {
76         struct commands_item *next;
77         struct commands_item *prev;
78         int cmd;
79         char *cmd_string;
80         CMDARG *arg;
81 };
82
83 /* breakpoint structure */              
84 typedef struct break_point {
85         struct break_point *next;
86         struct break_point *prev;
87         int number;
88
89         long ignore_count;
90         long hit_count;
91         char *src;
92         INSTRUCTION *bpi;       /* Op_breakpoint */
93
94         struct commands_item commands;  /* list of commands to run */
95         int silent;
96
97         struct condition cndn;
98
99         short flags;
100 #define BP_ENABLE       1
101 #define BP_ENABLE_ONCE  2               /* enable once */
102 #define BP_TEMP         4
103 #define BP_IGNORE       8
104
105 } BREAKPOINT; 
106
107 static BREAKPOINT breakpoints = { &breakpoints, &breakpoints, 0 };
108
109 #ifdef HAVE_LIBREADLINE
110 /* do_save -- save command */
111 static int sess_history_base = 0;
112 #endif
113
114 /* 'list' command */
115 static int last_printed_line = 0;
116 static int last_print_count;    /* # of lines printed */
117
118 /* watch or display item */
119 struct list_item {
120         struct list_item *next;
121         struct list_item *prev;
122         int number;     /* item number */
123
124         NODE *symbol;   /* variable or function param */
125         NODE **subs;    /* subscripts */
126         int num_subs;   /* subscript(dimension) count */ 
127         char *sname;    /* symbol or param name */
128
129         long fcall_count;
130
131         struct commands_item commands;          
132         int silent;
133         struct condition cndn;
134
135         /* This is for the value of the watched item */
136         union {
137                 NODE *n;
138                 long l;
139         } value[2];
140 #define cur_value value[0].n
141 #define cur_size  value[0].l
142 #define old_value value[1].n
143 #define old_size  value[1].l
144
145         int flags;
146 #define PARAM           1
147 #define SUBSCRIPT       2
148 #define FIELD_NUM       4
149 #define OLD_IS_ARRAY    8    /* old item is array */ 
150 #define CUR_IS_ARRAY    16   /* current item is array */ 
151 };
152
153 #define IS_PARAM(d)     (((d)->flags & PARAM) != 0)
154 #define IS_SUBSCRIPT(d) (((d)->flags & SUBSCRIPT) != 0)
155 #define IS_FIELD(d)     (((d)->flags & FIELD_NUM) != 0)
156 #define WATCHING_ARRAY(d)       (((d)->flags & CUR_IS_ARRAY) != 0)
157
158 static struct list_item display_list = { &display_list, &display_list, 0 };
159 static struct list_item watch_list = { &watch_list, &watch_list, 0 };
160
161
162 /* Structure to maintain data for processing debugger commands */
163
164 static struct {
165         long fcall_count;    /* 'finish', 'until', 'next', 'step', 'nexti' commands */
166         int sourceline;      /* source line number last
167                               * time we stopped execution,
168                               * used by next, until and step commands
169                               */
170         char *source;        /* next, until and step */
171
172         INSTRUCTION *pc;     /* 'until' and 'return' commands */
173         int repeat_count;    /* 'step', 'next', 'stepi', 'nexti' commands */
174         int print_frame;     /* print frame info,  'finish' and 'until' */
175         int print_ret;       /* print returned value, 'finish' */ 
176         int break_point;     /* non-zero (breakpoint number) if stopped at break point */
177         int watch_point;     /* non-zero (watchpoint number) if stopped at watch point */
178
179         int (*check_func)(INSTRUCTION **);  /* function to decide when to suspend
180                                                  * awk interpreter and return control
181                                                  * to debugger command interpreter.
182                                                  */
183  
184         enum argtype command;            /* command type */
185 } stop;
186
187
188 /* restart related stuff */
189 extern char **d_argv;   /* copy of argv array */
190 static int need_restart = FALSE;
191 enum { BREAK=1, WATCH, DISPLAY, HISTORY, OPTION };
192 static const char *const env_variable[] = {
193 "",
194 "DGAWK_BREAK",
195 "DGAWK_WATCH",
196 "DGAWK_DISPLAY",
197 "DGAWK_HISTORY",
198 "DGAWK_OPTION",
199 };
200 static void serialize(int );
201 static void unserialize(int );
202 static const char *commands_string = NULL;
203 static int commands_string_len = 0;
204 static char line_sep;
205 #define FSEP    (char)'\037'
206 #define RSEP    (char)'\036'
207 #define CSEP    (char)'\035'
208
209
210 /* debugger option */
211 struct dbg_option {
212         const char *name;
213         int *num_val;
214         char **str_val;
215         void (*assign)(const char *);
216         const char *help_txt; 
217 };
218
219 #define DEFAULT_HISTFILE        "./.dgawk_history"
220 #define DEFAULT_OPTFILE         "./.dgawkrc"
221 #define DEFAULT_PROMPT          "dgawk> "
222 #define DEFAULT_LISTSIZE        15
223 #define DEFAULT_HISTSIZE        100
224
225 static void set_gawk_output(const char *file);
226 static void set_prompt(const char *value);
227 static void set_listsize(const char *value);
228 static void set_trace(const char *value);
229 static void set_save_history(const char *value);
230 static void set_save_options(const char *value);
231 static void set_history_size(const char *value);
232 static const char *options_file = DEFAULT_OPTFILE;
233 #ifdef HAVE_LIBREADLINE
234 static const char *history_file = DEFAULT_HISTFILE;
235 #endif
236
237 /* keep all option variables in one place */
238
239 static char *output_file = "/dev/stdout";  /* gawk output redirection */
240 char *dgawk_Prompt = NULL;          /* initialized in interpret */
241 static int list_size = DEFAULT_LISTSIZE;   /* # of lines that 'list' prints */
242 static int do_trace = FALSE;
243 static int do_save_history = TRUE;
244 static int do_save_options = TRUE;
245 static int history_size = DEFAULT_HISTSIZE;  /* max # of lines in history file */
246
247 static const struct dbg_option option_list[] = {
248 {"history_size", &history_size, NULL, &set_history_size,
249         gettext_noop("set or show the number of lines to keep in history file.") },
250 {"listsize", &list_size, NULL, &set_listsize,
251         gettext_noop("set or show the list command window size.") },
252 {"outfile", NULL, &output_file, &set_gawk_output,
253         gettext_noop("set or show gawk output file.") },
254 {"prompt", NULL, &dgawk_Prompt, &set_prompt,
255         gettext_noop("set or show debugger prompt."), },
256 {"save_history", &do_save_history, NULL, &set_save_history,
257         gettext_noop("(un)set or show saving of command history (value=on|off).") },
258 {"save_options", &do_save_options, NULL, &set_save_options,
259         gettext_noop("(un)set or show saving of options (value=on|off).") },
260 {"trace", &do_trace, NULL, &set_trace,
261         gettext_noop("(un)set or show instruction tracing (value=on|off).") },
262 {0, NULL, NULL, NULL, 0},
263 };
264
265 static void save_options(const char *file);
266
267
268 /* pager */
269 jmp_buf pager_quit_tag;
270 int pager_quit_tag_valid;
271 static int screen_width = INT_MAX;      /* no of columns */
272 static int screen_height = INT_MAX;     /* no of rows */
273 static int pager_lines_printed = 0;     /* no of lines printed so far */ 
274
275 static void restart(int run) ATTRIBUTE_NORETURN;
276 static void close_all(void);
277 static int open_readfd(const char *file);
278 static int find_lines(SRCFILE *s);
279 static SRCFILE *source_find(char *src);
280 static int print_lines(char *src, int start_line, int nlines);
281 static void print_symbol(NODE *r, int isparam);
282 static NODE *find_frame(long num);
283 static NODE *find_param(const char *name, long num, char **pname);
284 static NODE *find_symbol(const char *name, char **pname);
285 static NODE *find_array(const char *name);
286 static void print_field(long field_num);
287 static int print_function(INSTRUCTION *pc, void *);
288 static void print_frame(NODE *func, char *src, int srcline);
289 static void print_numbered_frame(long num);
290 static void print_cur_frame_and_sourceline(void);
291 static INSTRUCTION *find_rule(char *src, long lineno);
292 static INSTRUCTION *mk_breakpoint(char *src, int srcline);
293 static int execute_commands(struct commands_item *commands);
294 static void delete_commands_item(struct commands_item *c);
295 static NODE *execute_code(volatile INSTRUCTION *code);
296 static int pre_execute_code(INSTRUCTION **pi);
297 static int parse_condition(int type, int num, char *expr);
298 static BREAKPOINT *add_breakpoint(INSTRUCTION *, INSTRUCTION *, char *, int);
299 static BREAKPOINT *set_breakpoint_next(INSTRUCTION *rp, INSTRUCTION *ip);
300 static BREAKPOINT *set_breakpoint_at(INSTRUCTION *, int, int);
301 static int set_breakpoint(CMDARG *arg, int temporary);
302 static void delete_breakpoint(BREAKPOINT *b);
303 static BREAKPOINT *find_breakpoint(long num);
304 static void display(struct list_item *d);
305 static struct list_item *find_item(struct list_item *list, long num);
306 static struct list_item *add_item(struct list_item *list, int type, NODE *symbol, char *pname);
307 static void delete_item(struct list_item *d);
308 static int breakpoint_triggered(BREAKPOINT *b);
309 static int watchpoint_triggered(struct list_item *w);
310
311 static void print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump);
312 static void next_command();
313 static char *g_readline(const char *prompt);
314 static int prompt_yes_no(const char *, char , int , FILE *);
315
316 static struct pf_data {
317         Func_print print_func;
318         int defn;
319         FILE *fp;
320 } pf_data;
321
322 char * (*read_a_line)(const char *) = 0;        /* reads a line of input */
323
324 struct command_source
325 {
326         int fd;
327         int is_tty;
328         char * (*read_func)(const char *);
329         int (*close_func)(int);
330         int eof_status;         /* see push_cmd_src */
331         int cmd;                        /* D_source or 0 */
332         char *str;                      /* sourced file */
333         struct command_source *next;
334 };
335
336 static struct command_source *cmd_src = NULL;
337
338 #define get_param_count(f)   (f)->lnode->param_cnt
339 #define get_params(f)        (f)->parmlist
340
341
342 #define CHECK_PROG_RUNNING() \
343         do { \
344                 if (! prog_running) { \
345                         d_error(_("program not running.")); \
346                         return FALSE; \
347                 } \
348         } while (FALSE)
349
350
351 /* g_readline --  read a line of text; the interface is like 'readline' but
352  *              without any command-line editing; used when not compiled with
353  *              readline support and/or input is not from terminal (prompt set to NULL).
354  */
355
356 static char *
357 g_readline(const char *prompt)
358 {
359         char *line;
360         size_t line_size = 100;
361         static char buf[2];
362         char *p, *end;
363         int n;
364
365         if (input_from_tty && prompt && *prompt)
366                 fprintf(out_fp, "%s", prompt);
367
368         emalloc(line, char *, line_size + 1, "g_readline");
369         p = line;
370         end = line + line_size;
371         while ((n = read(input_fd, buf, 1)) > 0) {
372                 if (buf[0] == '\n') {
373                         if (p > line && p[-1] == '\r')
374                                 p--;
375                         break;
376                 }
377                 if (p == end) {
378                         erealloc(line, char *, 2 * line_size + 1, "g_readline");
379                         p = line + line_size;
380                         line_size *= 2;
381                         end = line + line_size;
382                 }
383                 *p++ = buf[0];
384         }
385         if (n == -1 || (n == 0 && p == line)) {
386                 efree(line);
387                 return NULL;
388         }
389         *p = '\0';
390         return line;
391 }
392
393
394 /* d_error --- print an error message */
395
396 void
397 d_error(const char *mesg, ...)
398 {
399         va_list args;
400         va_start(args, mesg);
401         fprintf(out_fp, _("error: "));
402         vfprintf(out_fp, mesg, args);
403         fprintf(out_fp, "\n");
404         va_end(args);
405 }
406
407 /* find_lines --- find the positions of the lines in the source file. */
408
409 static int
410 find_lines(SRCFILE *s)
411 {
412         char *buf, *p, *end;
413         int n;
414         int ofs = 0;
415         int *pos;
416         int pos_size;
417         int maxlen = 0;
418         int numlines = 0;
419         char lastchar = '\0';
420
421         emalloc(buf, char *, s->bufsize, "find_lines");
422         pos_size = s->srclines;
423         emalloc(s->line_offset, int *, (pos_size + 2) * sizeof(int), "find_lines");
424         pos = s->line_offset;
425         pos[0] = 0;
426
427         while ((n = read(s->fd, buf, s->bufsize)) > 0) {
428                 end = buf + n;
429                 lastchar = buf[n - 1];
430                 p = buf;
431                 while (p < end) {
432                         if (*p++ == '\n') {
433                                 if (++numlines > pos_size) {
434                                         erealloc(s->line_offset, int *, (2 * pos_size + 2) * sizeof(int), "find_lines");
435                                         pos = s->line_offset + pos_size;
436                                         pos_size *= 2;
437                                 }
438                                 *++pos = ofs + (p - buf);
439                                 if ((pos[0] - pos[-1]) > maxlen)
440                                         maxlen = pos[0] - pos[-1];      /* length including NEWLINE */
441                         }
442                 }
443                 ofs += n;
444         }
445         efree(buf);
446
447         if (n == -1) {
448                 d_error(_("can't read source file `%s' (%s)"),
449                                         s->src, strerror(errno));
450                 return -1;
451         }
452         if (ofs <= 0) {
453                 fprintf(out_fp, _("source file `%s' is empty.\n"), s->src);
454                 return -1;
455         }
456
457         if (lastchar != '\n') {
458                 /* fake a NEWLINE at end */
459                 *++pos = ofs + 1;
460                 numlines++;
461                 if ((pos[0] - pos[-1]) > maxlen)
462                         maxlen = pos[0] - pos[-1];
463         }
464         s->maxlen = maxlen;
465         s->srclines = numlines;
466         return 0;
467 }
468
469 /* source_find --- return the SRCFILE struct for the source 'src' */
470
471 static SRCFILE *
472 source_find(char *src)
473 {
474         SRCFILE *s;
475         struct stat sbuf;
476         char *path;
477         int errno_val = 0;
478
479         if (src == NULL || *src == '\0') {
480                 d_error(_("no current source file."));
481                 return NULL;
482         }
483
484         if (cur_srcfile->src == src)  /* strcmp(cur_srcfile->src, src) == 0 */
485                 return cur_srcfile;
486
487         for (s = srcfiles->next; s != srcfiles; s = s->next) {
488                 if ((s->stype == SRC_FILE || s->stype == SRC_INC)
489                                 && strcmp(s->src, src) == 0)
490                         return s;
491         }
492
493         path = find_source(src, &sbuf, &errno_val);
494         if (path != NULL) {
495                 for (s = srcfiles->next; s != srcfiles; s = s->next) {
496                         if ((s->stype == SRC_FILE || s->stype == SRC_INC)
497                             && files_are_same(path, s)) {
498                                 efree(path);
499                                 return s;
500                         }
501                 }
502                 efree(path);
503         }
504
505         d_error(_("cannot find source file named `%s' (%s)"), src, strerror(errno_val));
506         return NULL;
507 }
508
509 /* print_lines --- print source lines, and update 'cur_srcfile' */
510
511 static int
512 print_lines(char *src, int start_line, int nlines)
513 {
514         SRCFILE *s;
515         int *pos;
516         int i;
517         struct stat sbuf;
518
519         s = source_find(src);
520         if (s == NULL)
521                 return -1;
522         if (s->fd <= INVALID_HANDLE && (s->fd = srcopen(s)) <= INVALID_HANDLE) {
523                 d_error(_("can't open source file `%s' for reading (%s)"),
524                                 src, strerror(errno));
525                 return -1;
526         }
527
528         if (fstat(s->fd, &sbuf) == 0 && s->mtime < sbuf.st_mtime) {
529                 fprintf(out_fp, _("WARNING: source file `%s' modified since program compilation.\n"),
530                                 src);
531                 efree(s->line_offset);
532                 s->line_offset = NULL;
533                 s->mtime = sbuf.st_mtime;
534
535                 /* reopen source file */
536                 close(s->fd);
537                 s->fd = INVALID_HANDLE;
538                 if ((s->fd = srcopen(s)) <= INVALID_HANDLE) {
539                         d_error(_("can't open source file `%s' for reading (%s)"),
540                                         src, strerror(errno));
541                         return -1;
542                 }
543         }
544
545         if (s->line_offset == NULL && find_lines(s) != 0)
546                 return -1;
547         if (start_line < 1 || start_line > s->srclines) {
548                 d_error(_("line number %d out of range; `%s' has %d lines"),
549                                         start_line, src, s->srclines);
550                 return -1;
551         }
552
553         assert(nlines > 0);
554         if ((start_line + nlines - 1) > s->srclines)
555                 nlines = s->srclines - start_line + 1;
556
557         pos = s->line_offset;
558         if (lseek(s->fd, (off_t) pos[start_line - 1], SEEK_SET) < 0) {
559                 d_error("%s: %s", src, strerror(errno));
560                 return -1;
561         }
562
563         if (linebuf == NULL) {
564                 emalloc(linebuf, char *, s->maxlen + 20, "print_lines"); /* 19 for line # */
565                 linebuf_len = s->maxlen;
566         } else if (linebuf_len < s->maxlen) {
567                 erealloc(linebuf, char *, s->maxlen + 20, "print_lines");
568                 linebuf_len = s->maxlen;
569         }
570
571         for (i = start_line; i < start_line + nlines; i++) {
572                 int supposed_len, len;
573                 char *p;
574                 
575                 sprintf(linebuf, "%-8d", i);
576
577                 /* mark the line about to be executed with =>; nlines > 1
578                  * condition makes sure that we are in list command
579                  */
580                 if (nlines > 1) {
581                         BREAKPOINT *b;
582                         int has_bpt = FALSE;            
583                         for (b = breakpoints.prev; b != &breakpoints; b = b->prev) {
584                                 if (src == b->src && i == b->bpi->source_line) {
585                                         has_bpt = TRUE;
586                                         break;
587                                 }
588                         }
589                         if (prog_running && src == source && i == sourceline) {
590                                 if (has_bpt)
591                                         sprintf(linebuf, "%-4d:b=>", i);
592                                 else
593                                         sprintf(linebuf, "%-4d  =>", i);
594                         } else if (has_bpt)
595                                 sprintf(linebuf, "%-4d:b  ", i);                        
596                 }
597
598                 p = linebuf + strlen(linebuf);
599                 supposed_len = pos[i] - pos[i - 1];
600                 len = read(s->fd, p, supposed_len);
601                 switch (len) {
602                 case -1:
603                         d_error(_("can't read source file `%s' (%s)"),
604                                                 src, strerror(errno));
605                         return -1;
606
607                 case 0:
608                         d_error(_("unexpected eof while reading file `%s', line %d"),
609                                                 src, i);
610                         return -1;
611
612                 default:
613                         if (i == s->srclines && p[len - 1] != '\n')
614                                 p[len++] = '\n';
615 #if 0
616                         if (len != supposed_len || p[len - 1] != '\n') {
617                                 d_error(_("source file `%s' modified since start of program execution"),
618                                                 src);
619                                 return -1;
620                         }
621 #endif
622                         len += (p - linebuf);
623                         if (fwrite(linebuf, sizeof(char), len, out_fp) != len)
624                                 return -1;
625                 }
626         }
627
628         if (cur_srcfile != s) {
629                 if (cur_srcfile->fd != INVALID_HANDLE) {
630                         close(cur_srcfile->fd);
631                         cur_srcfile->fd = INVALID_HANDLE;
632                 }
633                 cur_srcfile = s;
634         }
635         return (i - 1);         /* no of lines printed */
636 }
637
638 /* do_list --- list command */
639
640 int
641 do_list(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
642 {
643         long line_first, line_last;
644         long count = list_size;
645         INSTRUCTION *rp;
646         char *src = cur_srcfile->src;
647         
648         line_first = last_printed_line + 1;             /* default or no arg */
649         if (arg == NULL)        /* list or list + */
650                 goto list;
651
652         switch (arg->type) {
653         case D_int:             /* list n or list - */
654                 if (arg->a_int < 0) {           /* list - */
655                         line_first = last_printed_line - last_print_count - list_size + 1;
656                         if (line_first < 1) {
657                                 if (last_printed_line != last_print_count)
658                                         line_first = 1;
659                                 else
660                                         return FALSE;
661                         }
662                 } else {
663 line:
664                         line_first = arg->a_int - list_size / 2;
665                         if (line_first < 1)
666                                 line_first = 1;
667                 }
668                 break;
669
670         case D_range:   /* list m-n */
671 range:
672                 line_first = arg->a_int;
673                 arg = arg->next;
674                 assert(arg != NULL);
675                 assert(arg->type == D_int);
676                 count = arg->a_int - line_first + 1;
677                 break;
678
679         case D_string:          
680                 src = arg->a_string;
681                 if (arg->next != NULL) {
682                         arg = arg->next;                
683                         if (arg->type == D_int) /* list file:n */
684                                 goto line;
685                         else if (arg->type == D_range)  /* list file:m-n */
686                                 goto range;
687                         else if (arg->type == D_func)   /* list file:function */
688                                 goto func;
689                         else
690                                 line_first = 1;
691                 } else
692                         line_first = 1;
693                 break;
694
695         case D_func:    /* list function */
696 func:
697                 rp = arg->a_node->code_ptr;
698                 src = rp->source_file;
699                 line_first = rp->source_line - list_size / 2;
700                 if (line_first < 1)
701                         line_first = 1;
702                 break;
703
704         default:
705                 break;
706         }
707
708 list:
709         line_last = print_lines(src, line_first, count);
710         if (line_last != -1) {
711                 last_printed_line = line_last;
712                 last_print_count = line_last - line_first + 1;
713         } 
714         return FALSE;
715 }
716
717 /* do_info --- info command */
718
719 int
720 do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
721 {
722         if (arg == NULL || arg->type != D_argument)
723                 return FALSE;
724
725         switch (arg->a_argument) {
726         case A_SOURCE:
727                 fprintf(out_fp, _("Current source file: %s\n"), cur_srcfile->src);
728                 fprintf(out_fp, _("Number of lines: %d\n"), cur_srcfile->srclines);
729                 break;
730
731         case A_SOURCES:
732         {
733                 SRCFILE *s;
734                 for (s = srcfiles->next; s != srcfiles; s = s->next) {
735                         fprintf(out_fp, _("Source file (lines): %s (%d)\n"),
736                                         (s->stype == SRC_FILE || s->stype == SRC_INC) ? s->src
737                                                                               : "cmd. line",
738                                         s->srclines);
739                 }
740         }
741                 break;
742
743         case A_BREAK:
744                 initialize_pager(out_fp);
745                 if (setjmp(pager_quit_tag) == 0) {
746                         BREAKPOINT *b;
747                         struct commands_item *c;
748
749                         gprintf(out_fp, _("Number  Disp  Enabled  Location\n\n"));
750                         for (b = breakpoints.prev; b != &breakpoints; b = b->prev) {
751                                 char *disp = "keep";
752                                 if (b->flags & BP_ENABLE_ONCE)
753                                         disp = "dis";
754                                 else if(b->flags & BP_TEMP)
755                                         disp = "del";
756                                 gprintf(out_fp, "%-6d  %-4.4s  %-7.7s  file %s, line #%d\n",
757                                                 b->number, disp, (b->flags & BP_ENABLE) ? "yes" : "no",
758                                                 b->src, b->bpi->source_line);
759                                 if (b->hit_count > 0)
760                                         gprintf(out_fp, _("\tno of hits = %ld\n"), b->hit_count);
761                                 if (b->flags & BP_IGNORE)
762                                         gprintf(out_fp, _("\tignore next %ld hit(s)\n"), b->ignore_count);
763                                 if (b->cndn.code != NULL)
764                                         gprintf(out_fp, _("\tstop condition: %s\n"), b->cndn.expr);
765                                 if (b->commands.next != &b->commands)
766                                         gprintf(out_fp, _("\tcommands:\n"));
767                                 for (c = b->commands.next; c != &b->commands; c = c->next) {
768                                         gprintf(out_fp, "\t%s\n", c->cmd_string);
769                                         if (c->cmd == D_eval) {
770                                                 char *start, *end;
771                                                 CMDARG *a = c->arg;
772                                                 start = strchr(a->a_string, '{');
773                                                 end = strrchr(a->a_string, '}');
774                                                 if (start == NULL || end == NULL)
775                                                         continue;
776                                                 start++;
777                                                 *end = '\0';
778                                                 gprintf(out_fp, "%s", start);   /* FIXME: translate ? */ 
779                                                 *end = '}';
780                                         }
781                                 }
782                         }
783                 }
784                 break;
785
786         case A_FRAME:
787                 CHECK_PROG_RUNNING();
788                 fprintf(out_fp, _("Current frame: "));
789                 print_numbered_frame(cur_frame);
790                 if (cur_frame < fcall_count) {
791                         fprintf(out_fp, _("Called by frame: "));
792                         print_numbered_frame(cur_frame + 1);
793                 }
794                 if (cur_frame > 0) {
795                         fprintf(out_fp, _("Caller of frame: "));
796                         print_numbered_frame(cur_frame - 1);
797                 }
798                 break;
799
800         case A_ARGS:
801         case A_LOCALS:
802         {
803                 NODE *f, *func;
804                 INSTRUCTION *pc;
805                 int arg_count, pcount;
806                 int i, from, to;
807                 char **pnames;
808
809                 CHECK_PROG_RUNNING();
810                 f = find_frame(cur_frame);
811                 func = f->func_node;
812                 if (func == NULL) {
813                         /* print ARGV ? */
814                         fprintf(out_fp, _("None in main().\n"));
815                         return FALSE;
816                 }
817
818                 pcount = get_param_count(func);        /* # of defined params */
819                 pnames = get_params(func);             /* param names */
820
821                 pc = (INSTRUCTION *) f->reti;          /* Op_func_call instruction */
822                 arg_count = (pc + 1)->expr_count;      /* # of arguments supplied */
823
824                 if (arg_count > pcount)                /* extra args */
825                         arg_count = pcount;
826                 if (arg->a_argument == A_ARGS) {
827                         from = 0;
828                         to = arg_count - 1;
829                 } else {
830                         from = arg_count;
831                         to = pcount - 1;
832                 }
833
834                 for (i = from; i <= to; i++) {
835                         NODE *r;
836                         r = f->stack[i];
837                         if (r->type == Node_array_ref)
838                                 r = r->orig_array;
839                         fprintf(out_fp, "%s = ", pnames[i]);
840                         print_symbol(r, TRUE);
841                 }
842                 if (to < from)
843                         fprintf(out_fp, "%s",
844                                 arg->a_argument == A_ARGS ?
845                                         _("No arguments.\n") :
846                                         _("No locals.\n"));
847         }
848                 break;
849
850         case A_VARIABLES:
851                 initialize_pager(out_fp);
852                 if (setjmp(pager_quit_tag) == 0) {
853                         gprintf(out_fp, _("All defined variables:\n\n"));
854                         print_vars(gprintf, out_fp);
855                 }
856                 break;
857
858         case A_FUNCTIONS:
859                 initialize_pager(out_fp);
860                 if (setjmp(pager_quit_tag) == 0) {
861                         gprintf(out_fp, _("All defined functions:\n\n"));
862                         pf_data.print_func = gprintf;
863                         pf_data.fp = out_fp;
864                         pf_data.defn = TRUE;
865                         (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_function,
866                                             FALSE, /* sort */
867                                             &pf_data /* data */
868                                            );
869                 }
870                 break;
871
872         case A_DISPLAY:
873         case A_WATCH:
874                 initialize_pager(out_fp);
875                 if (setjmp(pager_quit_tag) == 0) {
876                         struct list_item *d, *list;
877
878                         if (arg->a_argument == A_DISPLAY) {
879                                 list = &display_list;
880                                 gprintf(out_fp, _("Auto-display variables:\n\n"));
881                         } else {
882                                 list = &watch_list;
883                                 gprintf(out_fp, _("Watch variables:\n\n"));
884                         }
885                         for (d = list->prev; d != list; d = d->prev) {
886                                 int i;
887                                 struct commands_item *c;
888                                 NODE *symbol = d->symbol;
889
890                                 if (IS_SUBSCRIPT(d)) {
891                                         gprintf(out_fp, "%d:\t%s",  d->number, d->sname);
892                                         for (i = 0; i < d->num_subs; i++) {
893                                                 NODE *sub;
894                                                 sub = d->subs[i];
895                                                 gprintf(out_fp, "[\"%s\"]", sub->stptr);
896                                         }
897                                         gprintf(out_fp, "\n");  
898                                 } else if (IS_FIELD(d))
899                                         gprintf(out_fp, "%d:\t$%ld\n", d->number, (long) symbol->numbr);
900                                 else
901                                         gprintf(out_fp, "%d:\t%s\n", d->number, d->sname);
902                                 if (d->cndn.code != NULL)
903                                         gprintf(out_fp, _("\tstop condition: %s\n"), d->cndn.expr);
904                                 if (d->commands.next != &d->commands)
905                                         gprintf(out_fp, _("\tcommands:\n"));
906                                 for (c = d->commands.next; c != &d->commands; c = c->next) {
907                                         gprintf(out_fp, "\t%s\n", c->cmd_string);
908                                         if (c->cmd == D_eval) {
909                                                 char *start, *end;
910                                                 CMDARG *a = c->arg;
911                                                 start = strchr(a->a_string, '{');
912                                                 end = strrchr(a->a_string, '}');
913                                                 if (start == NULL || end == NULL)
914                                                         continue;
915                                                 start++;
916                                                 *end = '\0';
917                                                 gprintf(out_fp, "%s", start);   /* FIXME: translate ? */  
918                                                 *end = '}';
919                                         }
920                                 }
921
922                         }
923                 }
924                 break;
925
926         default:
927                 break;
928         }
929
930         return FALSE;
931 }
932
933 /* print_symbol --- print a symbol table entry */
934
935 static void
936 print_symbol(NODE *r, int isparam)
937 {
938         switch (r->type) {
939         case Node_var_new:
940                 fprintf(out_fp, "untyped variable\n");
941                 break;
942         case Node_var:
943                 if (! isparam && r->var_update)
944                         r->var_update();
945                 valinfo(r->var_value, fprintf, out_fp);
946                 break;
947         case Node_var_array:
948                 fprintf(out_fp, "array, %ld elements\n", r->table_size);
949                 break;
950         case Node_func:
951                 fprintf(out_fp, "`function'\n");
952                 break;
953         default:
954                 break;
955         }
956 }
957
958 /* find_frame --- find frame given a frame number */
959
960 static NODE *
961 find_frame(long num)
962 {
963         assert(num >= 0);
964         if (num == 0)
965                 return frame_ptr;
966
967         assert(prog_running == TRUE);
968         assert(num <= fcall_count);
969         assert(fcall_list[num] != NULL);
970         return fcall_list[num];
971 }
972
973 /* find_param --- find a function parameter in a given frame number */
974
975 static NODE *
976 find_param(const char *name, long num, char **pname)
977 {
978         NODE *r = NULL;
979         NODE *f;
980
981         if (pname)
982                 *pname = NULL;
983
984         if (num < 0 || num > fcall_count || name == NULL)
985                 return NULL;
986         f = find_frame(num);
987         if (f->func_node != NULL) {             /* in function */
988                 NODE *func;
989                 char **pnames;
990                 int i, pcount;
991
992                 func = f->func_node;
993                 pnames = get_params(func);
994                 pcount = get_param_count(func);
995
996                 for (i = 0; i < pcount; i++) {
997                         if (strcmp(name, pnames[i]) == 0) {
998                                 r = f->stack[i];
999                                 if (r->type == Node_array_ref)
1000                                         r = r->orig_array;
1001                                 if (pname)
1002                                         *pname = pnames[i];
1003                                 break;
1004                         }
1005                 }
1006         }
1007         return r;
1008 }
1009
1010 /* find_symbol --- find a symbol in current context */
1011
1012 static
1013 NODE *find_symbol(const char *name, char **pname)
1014 {
1015         NODE *r = NULL;
1016
1017         if (pname)
1018                 *pname = NULL;
1019         if (prog_running)
1020                 r = find_param(name, cur_frame, pname);
1021         if (r == NULL)
1022                 r = lookup(name);
1023         if (r == NULL)
1024                 fprintf(out_fp, _("no symbol `%s' in current context\n"), name);
1025         return r;
1026 }
1027
1028 /* find_array -- find an array in current context */
1029
1030 static NODE *
1031 find_array(const char *name)
1032 {
1033         NODE *r;
1034         r = find_symbol(name, NULL);
1035         if (r != NULL && r->type != Node_var_array) {
1036                 fprintf(out_fp, _("`%s' is not an array\n"), name);
1037                 return NULL;
1038         }
1039         return r;
1040 }
1041
1042 /* print_field --- print the value of $n */
1043
1044 static void
1045 print_field(long field_num)
1046 {
1047         NODE **lhs;
1048         lhs = get_field(field_num, NULL);
1049         if (*lhs == Null_field || *lhs == Nnull_string)
1050                 fprintf(out_fp, _("$%ld = uninitialized field\n"), field_num);
1051         else {
1052                 fprintf(out_fp, "$%ld = ", field_num);
1053                 valinfo(*lhs, fprintf, out_fp);
1054         }
1055 }
1056
1057 /* print_array --- print the contents of an array */
1058
1059 static int
1060 print_array(volatile NODE *arr, char *arr_name)
1061 {
1062         NODE *bucket;
1063         NODE **list;
1064         int i;
1065         size_t num_elems = 0;
1066         volatile NODE *r;
1067         volatile int ret = 0;
1068         volatile jmp_buf pager_quit_tag_stack;
1069
1070         if (arr->var_array == NULL || arr->table_size == 0) {
1071                 gprintf(out_fp, _("array `%s' is empty\n"), arr_name);
1072                 return 0;
1073         }
1074
1075         num_elems = arr->table_size;
1076
1077         /* sort indices, sub_arrays are also sorted! */
1078         list = assoc_list((NODE *) arr, "@ind_str_asc", SORTED_IN);
1079
1080         PUSH_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid);
1081         if (setjmp(pager_quit_tag) == 0) {
1082                 for (i = 0; ret == 0 && i < num_elems; i++) {
1083                         bucket = list[i];
1084                         r = bucket->ahvalue;
1085                         if (r->type == Node_var_array)
1086                                 ret = print_array(r, r->vname);
1087                         else {
1088                                 gprintf(out_fp, "%s[\"%s\"] = ", arr_name, bucket->ahname_str);
1089                                 valinfo((NODE *) r, gprintf, out_fp);
1090                         }
1091                 }
1092         } else
1093                 ret = 1;
1094
1095         POP_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid);
1096
1097         for (i = 0; i < num_elems; i++)
1098                 unref(list[i]);
1099         efree(list);
1100
1101         return ret;
1102 }
1103
1104 /* print_subscript --- print an array element */
1105
1106 static void
1107 print_subscript(NODE *arr, char *arr_name, CMDARG *a, int count)
1108 {
1109         NODE *r, *subs;
1110
1111         subs = a->a_node;
1112         r = in_array(arr, subs);
1113         if (r == NULL)
1114                 fprintf(out_fp, _("[\"%s\"] not in array `%s'\n"), subs->stptr, arr_name);
1115         else if (r->type == Node_var_array) {
1116                 if (count > 1)
1117                         print_subscript(r, r->vname, a->next, count - 1);
1118                 else {
1119                         /* print # of elements in array */
1120                         fprintf(out_fp, "%s = ", r->vname);
1121                         print_symbol(r, FALSE); 
1122                 }
1123         } else {
1124                 fprintf(out_fp, "%s[\"%s\"] = ", arr_name, subs->stptr);
1125                 valinfo(r, fprintf, out_fp);
1126         }
1127 }
1128
1129 /* do_print_var --- print command */
1130
1131 int
1132 do_print_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1133 {
1134         NODE *r;
1135         CMDARG *a;
1136         char *name, *pname;
1137
1138         for (a = arg; a != NULL; a = a->next) {
1139                 switch (a->type) {
1140                 case D_variable:
1141                         name = a->a_string;
1142                         if ((r = find_symbol(name, &pname)) != NULL) {
1143                                 fprintf(out_fp, "%s = ", name);
1144                                 print_symbol(r, (pname != NULL));
1145                         }
1146                         break;
1147
1148                 case D_subscript:
1149                         assert(a->a_count > 0);
1150                         name = a->a_string;
1151                         r = find_array(name);
1152                         if (r != NULL)
1153                                 print_subscript(r, name, a->next, a->a_count);
1154                         break;
1155
1156                 case D_array:
1157                         name = a->a_string;
1158                         if ((r = find_array(name)) != NULL) {
1159                                 int count = a->a_count;
1160                                 for (; count > 0; count--) {
1161                                         NODE *value, *subs; 
1162                                         a = a->next;
1163                                         subs = a->a_node;
1164                                         value = in_array(r, subs);
1165                                         if (value == NULL) {
1166                                                 fprintf(out_fp, _("[\"%s\"] not in array `%s'\n"),
1167                                                                         subs->stptr, name);
1168                                                 break;
1169                                         } else if (value->type != Node_var_array) {
1170                                                 fprintf(out_fp, _("`%s[\"%s\"]' is not an array\n"),
1171                                                                         name, subs->stptr);
1172                                                 break;
1173                                         } else {
1174                                                 r = value;
1175                                                 name = r->vname;
1176                                         }
1177                                 }
1178                                 if (count == 0) {
1179                                         initialize_pager(out_fp);
1180                                         print_array((volatile NODE *) r, name);
1181                                 }
1182                         }
1183                         break;
1184
1185                 case D_field:
1186                         print_field(a->a_node->numbr);
1187                         break;
1188
1189                 default:
1190                         /* notably D_node, subscript for invalid array name; skip */
1191                         break;
1192                 }
1193         }       
1194         return FALSE;
1195 }               
1196
1197 /* do_set_var --- set command */
1198
1199 int
1200 do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1201 {
1202         NODE *r, *val;
1203         NODE **lhs;
1204         char *name, *pname;
1205
1206         switch (arg->type) {
1207         case D_variable:
1208                 name = arg->a_string;
1209                 arg = arg->next;
1210                 val = arg->a_node;
1211
1212                 if ((r = find_symbol(name, &pname)) == NULL)
1213                         break;
1214
1215                 switch (r->type) {
1216                 case Node_var_new:
1217                         r->type = Node_var;
1218                         r->var_value = Nnull_string;
1219                         /* fall through */
1220                 case Node_var:
1221                         lhs = &r->var_value;
1222                         unref(*lhs);
1223                         *lhs = dupnode(val);
1224                         if (pname == NULL && r->var_assign != NULL)
1225                                 r->var_assign();
1226                         fprintf(out_fp, "%s = ", name);
1227                         print_symbol(r, (pname != NULL));
1228                         break;
1229
1230                 default:
1231                         d_error(_("`%s' is not a scalar variable"), name);
1232                         break;
1233                 }
1234                 break;
1235
1236         case D_subscript:
1237         {
1238                 NODE *subs, *value;
1239                 int count = arg->a_count;
1240
1241                 assert(count > 0);
1242                 name = arg->a_string;
1243                 r = find_array(name);
1244                 if (r == NULL)
1245                         break;
1246                 for (; count > 0; count--) {
1247                         arg = arg->next;
1248                         subs = arg->a_node;
1249                         value = in_array(r, subs);
1250
1251                         if (count == 1) {
1252                                 if (value != NULL && value->type == Node_var_array)
1253                                         d_error(_("attempt to use array `%s[\"%s\"]' in a scalar context"),
1254                                                                 name, subs->stptr);
1255                                 else {
1256                                         arg = arg->next;
1257                                         val = arg->a_node;
1258                                         lhs = assoc_lookup(r, subs, FALSE);
1259                                         unref(*lhs);
1260                                         *lhs = dupnode(val);
1261                                         fprintf(out_fp, "%s[\"%s\"] = ", name, subs->stptr);
1262                                         valinfo(*lhs, fprintf, out_fp);
1263                                 }
1264                         } else {
1265                                 if (value == NULL) {
1266                                         NODE *array;
1267
1268                                         getnode(array);
1269                                         array->type = Node_var_array;
1270                                         array->var_array = NULL;
1271                                         array->vname = estrdup(subs->stptr, subs->stlen);
1272                                         *assoc_lookup(r, subs, FALSE) = array;
1273                                         r = array;
1274                                 } else if (value->type != Node_var_array) {
1275                                         d_error(_("attempt to use scalar `%s[\"%s\"]' as array"),
1276                                                         name, subs->stptr);
1277                                         break;
1278                                 } else {
1279                                         r = value;
1280                                         name = r->vname;
1281                                 }
1282                         }
1283                 }
1284         }
1285                 break;
1286
1287         case D_field:
1288         {
1289                 long field_num;
1290                 Func_ptr assign = NULL;
1291
1292                 field_num = (long) arg->a_node->numbr;
1293                 assert(field_num >= 0);
1294                 arg = arg->next;
1295                 val = arg->a_node;
1296                 lhs = get_field(field_num, &assign);
1297                 unref(*lhs);
1298                 *lhs = dupnode(val);
1299                 if (assign)
1300                         assign();
1301                 print_field(field_num);
1302         }
1303                 break;
1304
1305         default:
1306                 break;
1307         }
1308         return FALSE;
1309 }               
1310
1311 /* find_item --- find an item in the watch/display list */
1312
1313 static struct list_item *
1314 find_item(struct list_item *list, long num)
1315 {
1316         struct list_item *d;
1317
1318         if (num <= 0)
1319                 return NULL;
1320         for (d = list->next; d != list; d = d->next) {
1321                 if (d->number == num)
1322                         return d;
1323         }
1324         return NULL;
1325 }
1326
1327 /* delete_item --- delete an item from the watch/display list */
1328
1329 static void
1330 delete_item(struct list_item *d)
1331 {
1332         struct commands_item *c;
1333         int i;
1334
1335         if (IS_SUBSCRIPT(d)) {
1336                 for (i = 0; i < d->num_subs; i++)
1337                         unref(d->subs[i]);
1338                 efree(d->subs);
1339         } else if (IS_FIELD(d))
1340                 unref(d->symbol);
1341
1342         if ((d->flags & CUR_IS_ARRAY) == 0)
1343                 unref(d->cur_value);
1344         if ((d->flags & OLD_IS_ARRAY) == 0)
1345                 unref(d->old_value);
1346
1347         /* delete commands */
1348         for (c = d->commands.next; c != &d->commands; c = c->next) {
1349                 c = c->prev;
1350                 delete_commands_item(c->next);
1351         }
1352
1353         free_context(d->cndn.ctxt, FALSE);      
1354         if (d->cndn.expr != NULL)
1355                 efree(d->cndn.expr);
1356         
1357         d->next->prev = d->prev;
1358         d->prev->next = d->next;
1359         efree(d);
1360 }
1361
1362 /* add_item --- craete a watch/display item and add it to the list */
1363
1364 static struct list_item *
1365 add_item(struct list_item *list, int type, NODE *symbol, char *pname)
1366 {
1367         struct list_item *d;
1368
1369         emalloc(d, struct list_item *, sizeof(struct list_item), "add_item");
1370         memset(d, 0, sizeof(struct list_item));
1371         d->commands.next = d->commands.prev = &d->commands;
1372
1373         d->number = ++list->number;
1374         d->sname = symbol->vname;
1375         if (pname != NULL) {    /* function param */
1376                 d->sname = pname;
1377                 d->flags |= PARAM;
1378                 d->fcall_count = fcall_count - cur_frame;
1379         }
1380
1381         if (type == D_field) { /* field number */
1382                 d->symbol = symbol;
1383                 d->flags |= FIELD_NUM;
1384         } else if (type == D_subscript) {       /* subscript */
1385                 d->symbol = symbol;
1386                 d->flags |= SUBSCRIPT;
1387         } else /* array or variable */
1388                 d->symbol = symbol;
1389
1390         /* add to list */
1391         d->next = list->next;
1392         d->prev = list;
1393         list->next = d;
1394         d->next->prev = d;
1395         return d;
1396 }
1397
1398 /* do_add_item --- add an item to the watch/display list */
1399
1400 static struct list_item *
1401 do_add_item(struct list_item *list, CMDARG *arg)
1402 {
1403         NODE *symbol = NULL;
1404         char *name, *pname = NULL;
1405         struct list_item *item = NULL;
1406
1407         switch (arg->type) {
1408         case D_subscript:
1409         case D_variable:
1410                 name = arg->a_string;
1411                 if ((symbol = find_symbol(name, &pname)) == NULL)
1412                         return NULL;
1413                 if (symbol->type == Node_func) {
1414                         d_error(_("`%s' is a function"), name);
1415                         return NULL;
1416                 }
1417                 if (arg->type == D_subscript && symbol->type != Node_var_array) {
1418                         d_error(_("`%s' is not an array\n"), name);
1419                         return NULL;
1420                 }
1421
1422                 item = add_item(list, arg->type, symbol, pname);
1423                 if (item != NULL && arg->type == D_subscript) {
1424                         NODE **subs;
1425                         int count = arg->a_count;
1426                         int i;
1427
1428                         assert(count > 0);
1429                         emalloc(subs, NODE **, count * sizeof(NODE *), "do_add_item");
1430                         for (i = 0; i < count; i++) {
1431                                 arg = arg->next;
1432                                 subs[i] = dupnode(arg->a_node);
1433                                 (void) force_string(subs[i]);
1434                         }
1435                         item->subs = subs;
1436                         item->num_subs = count;
1437                 }
1438                 break;
1439
1440         case D_field:
1441                 symbol = dupnode(arg->a_node);
1442                 item = add_item(list, D_field, symbol, NULL);
1443                 break;
1444
1445         default:
1446                 break;
1447         }
1448
1449         /* watch condition if any */
1450         if (list == &watch_list) {
1451                 arg = arg->next;
1452                 if (item != NULL && arg != NULL) {
1453                         if (parse_condition(D_watch, item->number, arg->a_string) == 0)
1454                                 arg->a_string = NULL;   /* don't let free_cmdarg free it */
1455                         else
1456                                 fprintf(out_fp, _("watchpoint %d is unconditional\n"), item->number);
1457                 }
1458         }
1459         return item;
1460 }
1461
1462 /* do_delete_item --- delete a watch/display item from list. */
1463
1464 static void
1465 do_delete_item(struct list_item *list, CMDARG *arg)
1466 {
1467         if (arg == NULL) {
1468                 while (list->next != list)
1469                         delete_item(list->next);
1470         }
1471
1472         for (; arg != NULL; arg = arg->next) {
1473                 struct list_item *d;
1474                 if (arg->type == D_range) {
1475                         long i, j;
1476
1477                         i = arg->a_int;
1478                         arg = arg->next;
1479                         j = arg->a_int;
1480                         if (j > list->number)
1481                                 j = list->number;
1482                         for (; i <= j; i++) {
1483                                 if ((d = find_item(list, i)) != NULL)
1484                                         delete_item(d);
1485                         }
1486                 } else {
1487                         if ((d = find_item(list, arg->a_int)) == NULL) {
1488                                 /* split into two for easier message translation */
1489                                 if (list == &display_list)
1490                                         d_error(_("No display item numbered %ld"),
1491                                                 arg->a_int);
1492                                 else
1493                                         d_error(_("No watch item numbered %ld"),
1494                                                 arg->a_int);
1495                         } else
1496                                 delete_item(d);
1497                 }
1498         }
1499 }
1500
1501 /* display --- print an item from the auto-display list */
1502
1503 static void
1504 display(struct list_item *d)
1505 {
1506         NODE *symbol;
1507
1508         symbol = d->symbol;
1509         if (IS_PARAM(d) && (d->fcall_count != (fcall_count - cur_frame)))
1510                 return;
1511
1512         if (IS_SUBSCRIPT(d)) {
1513                 NODE *sub, *r;
1514                 int i = 0, count = d->num_subs;
1515                 for (i = 0; i < count; i++) {
1516                         sub = d->subs[i];
1517                         r = in_array(symbol, sub);
1518                         if (r == NULL) {
1519                                 fprintf(out_fp, _("%d: [\"%s\"] not in array `%s'\n"),
1520                                                         d->number, sub->stptr, d->sname);
1521                                 break;
1522                         }
1523                         if (r->type == Node_var_array) {
1524                                 symbol = r;
1525                                 if (i == count - 1)     /* it's a sub-array */
1526                                         goto print_sym;         /* print # of elements in sub-array */
1527                         } else {                                                        
1528                                 if (i != count - 1)
1529                                         return;         /* FIXME msg and delete item ? */
1530                                 fprintf(out_fp, "%d: %s[\"%s\"] = ", d->number,
1531                                                         d->sname, sub->stptr);
1532                                 valinfo(r, fprintf, out_fp);
1533                         }
1534                 }
1535         } else if (IS_FIELD(d)) {
1536                 NODE *r = d->symbol;
1537                 fprintf(out_fp, "%d: ", d->number);
1538                 print_field(r->numbr);
1539         } else {
1540 print_sym:
1541                 fprintf(out_fp, "%d: %s = ", d->number, d->sname);
1542                 print_symbol(symbol, IS_PARAM(d));
1543         }
1544 }
1545
1546
1547 /* do_display --- display command */
1548
1549 int
1550 do_display(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1551 {
1552         struct list_item *d;
1553
1554         if (arg == NULL) {
1555                 /* display all items */
1556                 for (d = display_list.prev; d != &display_list; d = d->prev)
1557                         display(d);
1558                 return FALSE;
1559         }
1560
1561         if ((d = do_add_item(&display_list, arg)) != NULL)
1562                 display(d);
1563
1564         return FALSE;
1565 }
1566
1567 /* do_undisplay --- undisplay command */
1568         
1569 int
1570 do_undisplay(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1571 {
1572         do_delete_item(&display_list, arg);
1573         return FALSE; 
1574 }
1575
1576 /* condition_triggered --- test if a condition expression is true */ 
1577
1578 static int
1579 condition_triggered(struct condition *cndn)
1580 {
1581         NODE *r;
1582         int di;
1583
1584         assert(cndn != NULL);
1585         if (cndn->code == NULL)
1586                 return TRUE;
1587
1588         push_context(cndn->ctxt);
1589         r = execute_code((volatile INSTRUCTION *) cndn->code);
1590         pop_context();  /* switch to prev context */
1591         if (r == NULL)      /* fatal error */
1592                 return FALSE;   /* not triggered */
1593
1594         force_number(r);
1595         di = (r->numbr != 0.0);
1596         DEREF(r);
1597         return di;
1598 }
1599
1600
1601
1602 static int
1603 find_subscript(struct list_item *item, NODE **ptr)
1604 {
1605         NODE *symbol = item->symbol;
1606         NODE *sub, *r;
1607         int i = 0, count = item->num_subs;
1608
1609         r = *ptr = NULL;
1610         for (i = 0; i < count; i++) {
1611                 sub = item->subs[i];
1612                 r = in_array(symbol, sub);
1613                 if (r == NULL)
1614                         return 0;
1615                 if (r->type == Node_var_array)
1616                         symbol = r;
1617                 else if (i < count - 1)
1618                         return -1;
1619         }
1620         *ptr = r;
1621         return 0;
1622 }
1623
1624 /* cmp_val --- compare values of watched item, returns TRUE if different; */
1625  
1626 static int
1627 cmp_val(struct list_item *w, NODE *old, NODE *new) 
1628 {
1629                 /*
1630                  *      case    old     new     result
1631                  *      ------------------------------
1632                  *      1:      NULL    ARRAY   TRUE    
1633                  *      2:      NULL    SCALAR  TRUE
1634                  *      3:      NULL    NULL    FALSE
1635                  *      4:      SCALAR  SCALAR  cmp_node
1636                  *      5:      SCALAR  ARRAY   TRUE
1637                  *      6:      SCALAR  NULL    TRUE
1638                  *      7:      ARRAY   SCALAR  TRUE
1639                  *      8:      ARRAY   ARRAY   compare size    
1640                  *      9:      ARRAY   NULL    TRUE
1641                  */
1642
1643         if (WATCHING_ARRAY(w)) {
1644                 long size = 0;
1645                 if (! new)              /* 9 */
1646                         return TRUE;
1647                 if (new->type == Node_val)      /* 7 */
1648                         return TRUE;
1649                 /* new->type == Node_var_array */       /* 8 */
1650                 if (new->var_array != NULL)
1651                         size = new->table_size;
1652                 if (w->cur_size == size)
1653                         return FALSE;
1654                 return TRUE;
1655         }
1656
1657         if (! old && ! new)     /* 3 */
1658                 return FALSE;
1659         if ((! old && new)      /* 1, 2 */
1660                         || (old && ! new))      /* 6 */
1661                 return TRUE;
1662
1663         if (new->type == Node_var_array)        /* 5 */
1664                 return TRUE;
1665         return cmp_nodes(old, new);                     /* 4 */
1666 }
1667
1668 /* watchpoint_triggered --- check if we should stop at this watchpoint;
1669  *                          update old and current values accordingly.
1670  */
1671
1672 static int
1673 watchpoint_triggered(struct list_item *w)
1674 {
1675         NODE *symbol;
1676         NODE *t1, *t2;
1677
1678         symbol = w->symbol;
1679         if (IS_PARAM(w) && (w->fcall_count != (fcall_count - cur_frame)))
1680                 return 0; /* parameter with same name in a different function */
1681         if (! condition_triggered(&w->cndn))
1682                 return 0;
1683
1684         t1 = w->cur_value;
1685         t2 = (NODE *) 0;
1686         if (IS_SUBSCRIPT(w))
1687                 (void) find_subscript(w, &t2);
1688         else if (IS_FIELD(w)) {
1689                 long field_num;
1690                 field_num = (long) w->symbol->numbr;
1691                 t2 = *get_field(field_num, NULL);
1692         } else {
1693                 switch (symbol->type) {
1694                 case Node_var:
1695                         t2 = symbol->var_value;
1696                         break;
1697                 case Node_var_array:
1698                         t2 = symbol;
1699                         break;
1700                 case Node_var_new:
1701                         break;
1702                 default:
1703                         cant_happen();
1704                 }
1705         }
1706
1707         if (! cmp_val(w, t1, t2))
1708                 return 0;
1709
1710         /* update old and current values */
1711
1712         if ((w->flags & OLD_IS_ARRAY) == 0)
1713                 unref(w->old_value);
1714         w->flags &= ~OLD_IS_ARRAY;
1715         if (WATCHING_ARRAY(w)) {        /* 7, 8, 9 */
1716                 w->old_size = w->cur_size;
1717                 w->flags |= OLD_IS_ARRAY;
1718                 if (! t2) {
1719                         w->flags &= ~CUR_IS_ARRAY;
1720                         w->cur_value = 0;
1721                 } else if (t2->type == Node_val) {
1722                         w->flags &= ~CUR_IS_ARRAY;
1723                         w->cur_value = dupnode(t2);
1724                 } else
1725                         w->cur_size = (t2->var_array != NULL) ? t2->table_size : 0;
1726         } else if (! t1) { /* 1, 2 */
1727                 w->old_value = 0;
1728                 /* new != NULL */
1729                 if (t2->type == Node_val)
1730                         w->cur_value = dupnode(t2);
1731                 else {
1732                         w->flags |= CUR_IS_ARRAY;
1733                         w->cur_size = (t2->var_array != NULL) ? t2->table_size : 0;
1734                 }
1735         } else /* if (t1->type == Node_val) */ {        /* 4, 5, 6 */
1736                 w->old_value = w->cur_value;
1737                 if (! t2)
1738                         w->cur_value = 0;
1739                 else if (t2->type == Node_var_array) {
1740                         w->flags |= CUR_IS_ARRAY;
1741                         w->cur_size = (t2->var_array != NULL) ? t2->table_size : 0;
1742                 } else
1743                         w->cur_value = dupnode(t2);
1744         }
1745
1746         return w->number;
1747 }
1748
1749 /* initialize_watch_item --- initialize current value of a watched item */
1750
1751 static int
1752 initialize_watch_item(struct list_item *w)
1753 {
1754         NODE *t, *r;
1755         NODE *symbol = w->symbol;
1756
1757         if (IS_SUBSCRIPT(w)) {
1758                 if (find_subscript(w, &r) == -1) {
1759                         d_error(_("attempt to use scalar value as array"));
1760                         return -1;
1761                 }
1762
1763                 if (r == NULL)
1764                         w->cur_value = (NODE *) 0;
1765                 else if (r->type == Node_var_array) { /* it's a sub-array */
1766                         w->flags |= CUR_IS_ARRAY;
1767                         w->cur_size = (r->var_array != NULL) ? r->table_size : 0;
1768                 } else
1769                         w->cur_value = dupnode(r);
1770         } else if (IS_FIELD(w)) {
1771                 long field_num;
1772                 t = w->symbol;
1773                 field_num = (long) t->numbr;
1774                 r = *get_field(field_num, NULL);
1775                 w->cur_value = dupnode(r);
1776         } else {
1777                 if (symbol->type == Node_var_new)
1778                         w->cur_value = (NODE *) 0;
1779                 else if (symbol->type == Node_var) {
1780                         r = symbol->var_value;
1781                         w->cur_value = dupnode(r);
1782                 } else if (symbol->type == Node_var_array) {
1783                         w->flags |= CUR_IS_ARRAY;
1784                         w->cur_size = (symbol->var_array != NULL) ? symbol->table_size : 0;
1785                 } /* else
1786                         can't happen */
1787         }
1788         return 0;
1789 }
1790
1791 /* do_watch --- watch command */
1792
1793 int
1794 do_watch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1795 {
1796         struct list_item *w;
1797         NODE *symbol, *sub;
1798         int i;
1799
1800         w = do_add_item(&watch_list, arg);
1801         if (w == NULL)
1802                 return FALSE;
1803
1804         if (initialize_watch_item(w) == -1) {
1805                 delete_item(w);
1806                 return FALSE;
1807         }
1808
1809         fprintf(out_fp, "Watchpoint %d: ", w->number);
1810         symbol = w->symbol;
1811
1812 /* FIXME: common code also in print_watch_item */
1813         if (IS_SUBSCRIPT(w)) {
1814                 fprintf(out_fp, "%s", w->sname);
1815                 for (i = 0; i < w->num_subs; i++) {
1816                         sub = w->subs[i];
1817                         fprintf(out_fp, "[\"%s\"]", sub->stptr);
1818                 }
1819                 fprintf(out_fp, "\n");
1820         } else if (IS_FIELD(w))
1821                 fprintf(out_fp, "$%ld\n", (long) symbol->numbr);
1822         else
1823                 fprintf(out_fp, "%s\n", w->sname);
1824
1825         return FALSE;
1826 }
1827
1828 /* do_unwatch --- unwatch command */
1829         
1830 int
1831 do_unwatch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1832 {
1833         do_delete_item(&watch_list, arg);
1834         return FALSE;
1835 }
1836
1837 /* callback from pop_frame in eval.c */
1838
1839 void
1840 frame_popped()
1841 {
1842         struct list_item *item;
1843
1844         /* delete all out of scope watchpoints */
1845         for (item = watch_list.next; item != &watch_list; item = item->next) {
1846                 if (IS_PARAM(item) && (item->fcall_count > fcall_count)) {
1847                         fprintf(out_fp,
1848                                 _("Watchpoint %d deleted because parameter is out of scope.\n"),
1849                                 item->number);
1850                         item = item->prev;
1851                         delete_item(item->next);
1852                 }
1853         }
1854
1855         /* delete all out of scope display items */
1856         for (item = display_list.next; item != &display_list; item = item->next) {
1857                 if (IS_PARAM(item) && (item->fcall_count > fcall_count)) {
1858                         fprintf(out_fp,
1859                                 _("Display %d deleted because parameter is out of scope.\n"),
1860                                 item->number);
1861                         item = item->prev;
1862                         delete_item(item->next);
1863                 }
1864         }
1865 }
1866
1867 /* print_function --- print function name, parameters, and optionally
1868  *                file and line number.
1869  */
1870
1871 static int
1872 print_function(INSTRUCTION *pc, void *x)
1873 {
1874         NODE *func;
1875         int i, pcount;
1876         char **pnames;
1877         struct pf_data *data = (struct pf_data *) x;  
1878         int defn = data->defn;
1879         Func_print print_func = data->print_func;       
1880         FILE *fp = data->fp;
1881
1882         func = pc->func_body;
1883         pcount = get_param_count(func);
1884         pnames = get_params(func);
1885
1886         print_func(fp, "%s(", func->lnode->param);
1887         for (i = 0; i < pcount; i++) {
1888                 print_func(fp, "%s", pnames[i]);
1889                 if (i < pcount - 1)               
1890                         print_func(fp, ", ");
1891         }
1892         print_func(fp, ")");
1893         if (defn)
1894                 print_func(fp, _(" in file `%s', line %d\n"),
1895                                 pc->source_file, pc->source_line);
1896         return 0;
1897 }
1898
1899 /* print_frame --- print function name, parameters,
1900  *                 source and line number of where it is
1901  *                 executing.
1902  */
1903
1904 static void
1905 print_frame(NODE *func, char *src, int srcline)
1906 {
1907         if (func == NULL)
1908                 fprintf(out_fp, "main()");
1909         else {
1910                 pf_data.print_func = fprintf;
1911                 pf_data.fp = out_fp;
1912                 pf_data.defn = FALSE;
1913                 (void) print_function(func->code_ptr, &pf_data);
1914         }
1915         fprintf(out_fp, _(" at `%s':%d"), src, srcline);
1916 }
1917
1918 /* print_numbered_frame --- print a frame given its number */
1919
1920 static void
1921 print_numbered_frame(long num)
1922 {
1923         NODE *f;
1924
1925         assert(prog_running == TRUE);
1926         f = find_frame(num);
1927         if (num == 0) {
1928                 fprintf(out_fp, "#%ld\t ", num);
1929                 print_frame(f->func_node, source, sourceline);
1930         } else {
1931                 fprintf(out_fp, _("#%ld\tin "), num);
1932                 print_frame(f->func_node, f->vname,
1933                         ((INSTRUCTION *) find_frame(num - 1)->reti)->source_line); 
1934         }
1935         fprintf(out_fp, "\n");
1936 }
1937
1938 /* do_backtrace --- backtrace command */
1939
1940 int
1941 do_backtrace(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1942 {
1943         long cur = 0;
1944         long last = fcall_count;
1945
1946         CHECK_PROG_RUNNING();
1947         if (arg != NULL && arg->type == D_int) {
1948                 long count = arg->a_int;
1949
1950                 /* frame_ptr (frame #0),  fcall_list[1, 2, ... fcall_count] => total count */
1951                 if (count >= 0) {
1952                         /* toward outermost frame #fcall_count */
1953                         last = count - 1;
1954                         if (last > fcall_count)
1955                                  last = fcall_count;
1956                 } else {
1957                         /* toward innermost frame #0 */
1958                         cur = 1 + fcall_count + count;
1959                         if (cur < 0)
1960                                 cur = 0;
1961                 }
1962         } 
1963
1964         for (; cur <= last; cur++) {
1965                 print_numbered_frame(cur);
1966         }
1967         if (cur <= fcall_count)
1968                 fprintf(out_fp, _("More stack frames follow ...\n"));
1969         return FALSE;
1970 }       
1971
1972 /* print_cur_frame_and_sourceline --- print current frame, and
1973  *                                    current source line.
1974  */
1975  
1976 static void
1977 print_cur_frame_and_sourceline()
1978 {
1979         NODE *f;
1980         int srcline;
1981         char *src;
1982
1983         assert(prog_running == TRUE);
1984         f = find_frame(cur_frame);
1985         if (cur_frame == 0) {
1986                 src = source;
1987                 srcline = sourceline;
1988         } else {
1989                 f = find_frame(cur_frame);
1990                 src = f->vname;
1991                 srcline = ((INSTRUCTION *) find_frame(cur_frame - 1)->reti)->source_line;
1992         }
1993
1994         fprintf(out_fp, (cur_frame > 0 ? _("#%ld\tin ") : "#%ld\t "), cur_frame);
1995         print_frame(f->func_node, src, srcline);
1996         fprintf(out_fp, "\n");
1997         print_lines(src, srcline, 1);
1998         last_printed_line = srcline - list_size / 2;
1999         if (last_printed_line < 0)
2000                 last_printed_line = 0;
2001 }
2002
2003 /* do_frame --- frame command */
2004
2005 int
2006 do_frame(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2007 {
2008         CHECK_PROG_RUNNING();
2009         if (arg && arg->type == D_int) {
2010                 if (arg->a_int < 0 || arg->a_int > fcall_count) {
2011                         d_error(_("invalid frame number"));
2012                         return FALSE;
2013                 }
2014                 cur_frame = arg->a_int;
2015         }
2016         print_cur_frame_and_sourceline();
2017         return FALSE;
2018 }
2019
2020 /* do_up --- up command */
2021
2022 int
2023 do_up(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2024 {
2025         CHECK_PROG_RUNNING();
2026         if (arg != NULL && arg->type == D_int)
2027                 cur_frame += arg->a_int;
2028         else
2029                 cur_frame++;
2030         if (cur_frame < 0)
2031                 cur_frame = 0;
2032         else if (cur_frame > fcall_count)
2033                 cur_frame = fcall_count;
2034         print_cur_frame_and_sourceline();
2035         return FALSE;
2036 }
2037
2038 /* do_down --- down command */
2039
2040 int
2041 do_down(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2042 {
2043         CHECK_PROG_RUNNING();
2044         if (arg != NULL && arg->type == D_int)
2045                 cur_frame -= arg->a_int;
2046         else
2047                 cur_frame--;
2048         if (cur_frame < 0)
2049                 cur_frame = 0;
2050         else if (cur_frame > fcall_count)
2051                 cur_frame = fcall_count;
2052         print_cur_frame_and_sourceline();
2053         return FALSE;
2054 }
2055
2056 /* find_rule --- find a rule or function in file 'src' containing
2057  *               source line 'lineno'
2058  */
2059
2060 static INSTRUCTION *
2061 find_rule(char *src, long lineno)
2062 {
2063         INSTRUCTION *rp;
2064
2065         assert(lineno > 0);
2066         for (rp = rule_list->nexti; rp != NULL; rp = rp->nexti) {
2067                 if ((rp - 1)->source_file == src
2068                                 && lineno >= (rp + 1)->first_line
2069                                 && lineno <= (rp + 1)->last_line)
2070                         return (rp - 1);
2071         }
2072         return NULL;
2073 }
2074
2075 /* mk_breakpoint --- create a breakpoint instruction and the corresponding
2076  *                   breakpoint structure.
2077  */
2078  
2079 static INSTRUCTION *
2080 mk_breakpoint(char *src, int srcline)
2081 {
2082         INSTRUCTION *bp;
2083         BREAKPOINT *b;
2084
2085         bp = bcalloc(Op_breakpoint, 1, srcline);
2086         emalloc(b, BREAKPOINT *, sizeof(BREAKPOINT), "mk_breakpoint");
2087         memset(&b->cndn, 0, sizeof(struct condition));
2088         b->commands.next = b->commands.prev = &b->commands;
2089         b->silent = FALSE;
2090
2091
2092         b->number = ++watch_list.number;        /* breakpoints and watchpoints use same counter */
2093         b->ignore_count = 0;
2094         b->hit_count = 0;
2095         b->flags = BP_ENABLE;
2096         b->src = src;
2097         bp->break_pt = b;
2098         b->bpi = bp;
2099                         
2100         /* prepend to list */
2101         b->next = breakpoints.next;
2102         b->prev = &breakpoints;
2103         breakpoints.next = b;
2104         b->next->prev = b;
2105         return bp;
2106 }
2107
2108 /* delete_breakpoint --- delete a breakpoint structure and
2109  *                       disable the breakpoint instruction.
2110  */
2111
2112 static void
2113 delete_breakpoint(BREAKPOINT *b)
2114 {
2115         INSTRUCTION *pc = b->bpi;
2116         struct commands_item *c;
2117
2118         /* N.B.: easiest thing to do is to turn Op_breakpoint into a no-op;
2119          * deleteing the instruction is not that simple,
2120          * since could have reference to it somewhere else (e.g. cur_pc).
2121          */
2122   
2123         pc->opcode = Op_no_op;
2124         pc->source_line = 0;
2125         pc->break_pt = NULL;
2126
2127         /* delete commands */
2128         for (c = b->commands.next; c != &b->commands; c = c->next) {
2129                 c = c->prev;
2130                 delete_commands_item(c->next);
2131         }
2132
2133         free_context(b->cndn.ctxt, FALSE);      
2134         if (b->cndn.expr != NULL)
2135                 efree(b->cndn.expr);
2136
2137         /* remove from list */
2138         b->next->prev = b->prev;
2139         b->prev->next = b->next;
2140         efree(b);
2141 }
2142
2143 /* find_breakpoint --- find the breakpoint structure from a breakpoint number */
2144
2145 static BREAKPOINT *
2146 find_breakpoint(long num)
2147 {
2148         BREAKPOINT *b;
2149
2150         if (num <= 0)
2151                 return NULL; 
2152
2153         for (b = breakpoints.next; b != &breakpoints; b = b->next) {
2154                 if (b->number == num)
2155                         return b;
2156         }
2157         return NULL;
2158 }
2159
2160 /* add_breakpoint --- add a breakpoint instruction between PREVP and IP */
2161  
2162 static BREAKPOINT *
2163 add_breakpoint(INSTRUCTION *prevp, INSTRUCTION *ip, char *src, int silent)
2164 {
2165         BREAKPOINT *b;
2166         INSTRUCTION *bp;
2167         int lineno = ip->source_line;
2168
2169         /* add new breakpoint instruction at the end of
2170          * already set breakpoints at this line number.
2171          */
2172
2173         while (ip->opcode == Op_breakpoint && ip->source_line == lineno) {
2174                 if (! silent) {
2175                         b = ip->break_pt;
2176                         /*
2177                          * This is more verbose that it might otherwise be,
2178                          * in order to provide easily translatable strings.
2179                          */
2180                         if (b->flags & BP_ENABLE) {
2181                                 if (b->flags & BP_IGNORE)
2182                                         fprintf(out_fp,
2183                         _("Note: breakpoint %d (enabled, ignore next %ld hits), also set at %s:%d"),
2184                                                 b->number,
2185                                                 b->ignore_count,
2186                                                 b->src,
2187                                                 lineno);
2188                                 else
2189                                         fprintf(out_fp,
2190                         _("Note: breakpoint %d (enabled), also set at %s:%d"),
2191                                                 b->number,
2192                                                 b->src,
2193                                                 lineno);
2194                         } else {
2195                                 if (b->flags & BP_IGNORE)
2196                                         fprintf(out_fp,
2197                         _("Note: breakpoint %d (disabled, ignore next %ld hits), also set at %s:%d"),
2198                                                 b->number,
2199                                                 b->ignore_count,
2200                                                 b->src,
2201                                                 lineno);
2202                                 else
2203                                         fprintf(out_fp,
2204                         _("Note: breakpoint %d (disabled), also set at %s:%d"),
2205                                                 b->number,
2206                                                 b->src,
2207                                                 lineno);
2208                         }
2209                 }
2210                 prevp = ip;
2211                 ip = ip->nexti;
2212         }
2213
2214         assert(ip->source_line == lineno);
2215
2216         bp = mk_breakpoint(src, lineno);
2217         prevp->nexti = bp;
2218         bp->nexti = ip;
2219         b = bp->break_pt;
2220         if (! silent)
2221                 fprintf(out_fp, _("Breakpoint %d set at file `%s', line %d\n"),
2222                                                 b->number, src, lineno);
2223         return b;
2224 }
2225
2226 /* set_breakpoint_at --- set a breakpoint at given line number*/
2227
2228 static BREAKPOINT *
2229 set_breakpoint_at(INSTRUCTION *rp, int lineno, int silent)
2230 {
2231         INSTRUCTION *ip, *prevp;
2232
2233         for (prevp = rp, ip = rp->nexti; ip; prevp = ip, ip = ip->nexti) {
2234                 if (ip->opcode == Op_K_case) {
2235                         INSTRUCTION *i1, *i2;
2236
2237                         /* Special case: the code line numbers for a switch do not form
2238                          * a monotonically increasing sequence. Check if the line # is between
2239                          * the first and last statements of the case block before continuing
2240                          * the search.
2241                          */ 
2242                         for (i2 = ip->stmt_start, i1 = i2->nexti; i2 != ip->stmt_end;
2243                                                                 i2 = i1, i1 = i1->nexti) {
2244                                 if (i1->source_line >= lineno)
2245                                         return add_breakpoint(i2, i1, rp->source_file, silent);
2246                                 if (i1 == ip->stmt_end)
2247                                         break;
2248                         }
2249                 }
2250
2251                 if (ip->source_line >= lineno)
2252                         return add_breakpoint(prevp, ip, rp->source_file, silent);
2253                 if (ip == (rp + 1)->lasti)
2254                         break;
2255         }
2256         return NULL;
2257 }
2258
2259 /* set_breakpoint_next --- set a breakpoint at the next instruction */
2260
2261 static BREAKPOINT *
2262 set_breakpoint_next(INSTRUCTION *rp, INSTRUCTION *ip)
2263 {
2264         INSTRUCTION *prevp;
2265
2266         if (ip == (rp + 1)->lasti)
2267                 return NULL;
2268         prevp = ip;
2269         if (ip->opcode != Op_breakpoint)
2270                 ip = ip->nexti;
2271         for (; ip; prevp = ip, ip = ip->nexti) {
2272                 if (ip->source_line > 0)
2273                         return add_breakpoint(prevp, ip, rp->source_file, FALSE);
2274                 if (ip == (rp + 1)->lasti)
2275                         break;
2276         }
2277         return NULL;
2278 }
2279                 
2280 /* set_breakpoint --- set a breakpoint */
2281
2282 static int
2283 set_breakpoint(CMDARG *arg, int temporary)
2284 {
2285         int lineno;
2286         BREAKPOINT *b = NULL;
2287         INSTRUCTION *rp, *ip;
2288         NODE *func;
2289         SRCFILE *s = cur_srcfile;
2290         char *src = cur_srcfile->src;
2291
2292         if (arg == NULL) {
2293 /*
2294 * (From GDB Documentation):
2295
2296 * When called without any arguments, break sets a breakpoint at the next instruction
2297 * to be executed in the selected stack frame (see section Examining the Stack).
2298 * In any selected frame but the innermost, this makes your program stop as soon
2299 * as control returns to that frame. This is similar to the effect of a finish command
2300 * in the frame inside the selected frame--except that finish does not leave an
2301 * active breakpoint. If you use break without an argument in the innermost frame,
2302 * GDB stops the next time it reaches the current location; this may be useful
2303 * inside loops.
2304 * GDB normally ignores breakpoints when it resumes execution, until at least
2305 * one instruction has been executed. If it did not do this,
2306 * you would be unable to proceed past a breakpoint without first disabling the
2307 * breakpoint. This rule applies whether or not the breakpoint already existed
2308 * when your program stopped. 
2309 */
2310                 CHECK_PROG_RUNNING();
2311                 if (cur_frame == 0) {
2312                         src = source;
2313                         ip = cur_pc;
2314                 } else {
2315                         NODE *f;
2316                         f = find_frame(cur_frame);
2317                         src = f->vname;
2318                         ip = (INSTRUCTION *) find_frame(cur_frame - 1)->reti;  /* Op_func_call */
2319                 }
2320                 rp = find_rule(src, ip->source_line);
2321                 assert(rp != NULL);
2322                 if ((b = set_breakpoint_next(rp, ip)) == NULL)
2323                         fprintf(out_fp, _("Can't set breakpoint in file `%s'\n"), src);
2324                 else {
2325                         if (cur_frame == 0) {   /* stop next time */
2326                                 b->flags |= BP_IGNORE;
2327                                 b->ignore_count = 1;
2328                         }
2329                         if (temporary)
2330                                 b->flags |= BP_TEMP;
2331                 }
2332                 return FALSE;
2333         }
2334
2335         /* arg != NULL */
2336
2337         switch (arg->type) {
2338         case D_string:  /* break filename:lineno|function */
2339                 s = source_find(arg->a_string);
2340                 arg = arg->next;
2341                 if (s == NULL || arg == NULL
2342                                 || (arg->type != D_int && arg->type != D_func))
2343                         return FALSE;
2344                 src = s->src;
2345                 if (arg->type == D_func) /* break filename:function */
2346                         goto func;
2347                 else
2348                         /* fall through */
2349         case D_int:             /* break lineno */
2350                 lineno = (int) arg->a_int;
2351                 if (lineno <= 0 || lineno > s->srclines)
2352                         d_error(_("line number %d in file `%s' out of range"), lineno, src);
2353                 else {
2354                         rp = find_rule(src, lineno);
2355                         if (rp == NULL)
2356                                 fprintf(out_fp, _("Can't find rule!!!\n"));
2357                         if (rp == NULL || (b = set_breakpoint_at(rp, lineno, FALSE)) == NULL)
2358                                 fprintf(out_fp, _("Can't set breakpoint at `%s':%d\n"),
2359                                                 src, lineno);
2360                         if (b != NULL && temporary)
2361                                 b->flags |= BP_TEMP;
2362                 }
2363                 break;
2364
2365         case D_func:    /* break function */
2366 func:
2367                 func = arg->a_node;
2368                 rp = func->code_ptr;
2369                 if ((b = set_breakpoint_at(rp, rp->source_line, FALSE)) == NULL)
2370                         fprintf(out_fp, _("Can't set breakpoint in function `%s'\n"),
2371                                                 func->lnode->param);
2372                 else if (temporary)
2373                         b->flags |= BP_TEMP;
2374                 lineno = b->bpi->source_line;
2375                 break;
2376
2377         default:
2378                 return FALSE;
2379         }
2380         /* condition if any */
2381         arg = arg->next;
2382         if (b != NULL && arg != NULL) {
2383                 if (parse_condition(D_break, b->number, arg->a_string) == 0)
2384                         arg->a_string = NULL;   /* don't let free_cmdarg free it */
2385                 else
2386                         fprintf(out_fp, _("breakpoint %d set at file `%s', line %d is unconditional\n"),
2387                                                         b->number, src, lineno);
2388         }
2389         return FALSE;
2390 }
2391
2392
2393 /* breakpoint_triggered --- check if we should stop at this breakpoint */
2394
2395 static int
2396 breakpoint_triggered(BREAKPOINT *b)
2397 {
2398         if ((b->flags & BP_ENABLE) == 0)
2399                 return 0;
2400         if ((b->flags & BP_IGNORE) != 0) {
2401                 if (--b->ignore_count <= 0)
2402                         b->flags &= ~BP_IGNORE;
2403                 return 0;
2404         }
2405
2406         if (! condition_triggered(&b->cndn))
2407                 return 0;
2408
2409         b->hit_count++;
2410         if (b->flags & BP_ENABLE_ONCE) {
2411                 b->flags &= ~BP_ENABLE_ONCE;
2412                 b->flags &= ~BP_ENABLE;
2413         } 
2414         return b->number;
2415 }
2416
2417 /* do_breakpoint --- break command */
2418
2419 int
2420 do_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2421 {
2422         return set_breakpoint(arg, FALSE);
2423 }       
2424
2425 /* do_tmp_breakpoint --- tbreak command */
2426
2427 int
2428 do_tmp_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2429 {
2430         return set_breakpoint(arg, TRUE);
2431 }
2432
2433 /* do_clear --- clear command */
2434
2435 int
2436 do_clear(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2437 {
2438         int lineno;
2439         BREAKPOINT *b;
2440         INSTRUCTION *rp, *ip;
2441         NODE *func;
2442         SRCFILE *s = cur_srcfile;
2443         char *src = cur_srcfile->src;
2444         int bp_found = FALSE;
2445
2446         if (arg == NULL) {      /* clear */
2447                 CHECK_PROG_RUNNING();
2448                 if (cur_frame == 0) {
2449                         lineno = sourceline;
2450                         src = source;
2451                 } else {
2452                         NODE *f;
2453                         f = find_frame(cur_frame);
2454                         src = f->vname;
2455                         lineno = ((INSTRUCTION *) find_frame(cur_frame - 1)->reti)->source_line;
2456                 }
2457                 goto delete_bp;
2458         }
2459
2460         switch (arg->type) {
2461         case D_string:  /* clear filename:lineno|function */
2462                 s = source_find(arg->a_string);
2463                 arg = arg->next;
2464                 if (s == NULL || arg == NULL ||
2465                                 (arg->type != D_int && arg->type != D_func))
2466                         return FALSE;
2467                 src = s->src;
2468                 if (arg->type == D_func)
2469                         goto func;
2470                 /* else
2471                         fall through */
2472         case D_int:     /* clear lineno */
2473                 lineno = (int) arg->a_int;
2474                 if (lineno <= 0 || lineno > s->srclines) {
2475                         d_error(_("line number %d in file `%s' out of range"), lineno, src);
2476                         return FALSE;
2477                 }
2478                 break;
2479
2480         case D_func:    /* clear function */
2481 func:
2482                 func = arg->a_node;
2483                 rp = func->code_ptr;
2484                 for (ip = rp->nexti; ip; ip = ip->nexti) {
2485                         if (ip->source_line <= 0)
2486                                 continue;
2487                         if (ip->opcode != Op_breakpoint)
2488                                 break;
2489                         b = ip->break_pt;
2490                         if (++bp_found == 1)
2491                                 fprintf(out_fp, _("Deleted breakpoint %d"), b->number);
2492                         else
2493                                 fprintf(out_fp, ", %d", b->number);
2494                         delete_breakpoint(b);
2495                 }
2496                 if (! bp_found)
2497                         fprintf(out_fp, _("No breakpoint(s) at entry to function `%s'\n"),
2498                                         func->lnode->param);
2499                 else
2500                         fprintf(out_fp, "\n");
2501                 /* fall through */
2502         default:
2503                 return FALSE;
2504         }
2505
2506 delete_bp:
2507         rp = find_rule(src, lineno);
2508         if (rp != NULL) {
2509                 for (ip = rp->nexti; ip; ip = ip->nexti) {
2510                         if (ip->opcode == Op_breakpoint && ip->source_line == lineno) {
2511                                 b = ip->break_pt;
2512                                 if (++bp_found == 1)
2513                                         fprintf(out_fp, _("Deleted breakpoint %d"), b->number);
2514                                 else
2515                                         fprintf(out_fp, ", %d", b->number);
2516                                 delete_breakpoint(b);
2517                         }
2518                         if (ip == (rp + 1)->lasti)
2519                                 break;
2520                 }
2521         }
2522
2523         if (! bp_found)
2524                 fprintf(out_fp, _("No breakpoint at file `%s', line #%d\n"),
2525                                         src, (int) lineno);
2526         else
2527                 fprintf(out_fp, "\n");
2528         return FALSE;
2529 }
2530
2531 /* enable_breakpoint --- enable a breakpoint and set its disposition */
2532
2533 static inline void
2534 enable_breakpoint(BREAKPOINT *b, short disp)
2535 {
2536         b->flags &= ~(BP_ENABLE_ONCE|BP_TEMP);
2537         b->flags |= BP_ENABLE;
2538         if (disp)
2539                 b->flags |= disp;
2540 }
2541
2542 /* do_enable_breakpoint --- enable command */
2543
2544 int
2545 do_enable_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2546 {
2547         BREAKPOINT *b;
2548         short disp = 0;
2549
2550         if (arg != NULL && arg->type == D_argument) {
2551                 if (arg->a_argument == A_DEL)   /* del */
2552                         disp = BP_TEMP;
2553                 else                                            /* once */
2554                         disp = BP_ENABLE_ONCE;
2555                 arg = arg->next;
2556         }
2557
2558         if (arg == NULL) {      /* enable [once|del] */
2559                 for (b = breakpoints.next; b != &breakpoints; b = b->next)
2560                         enable_breakpoint(b, disp);
2561         }
2562
2563         for (; arg != NULL; arg = arg->next) {
2564                 if (arg->type == D_range) {
2565                         long i, j;
2566
2567                         i = arg->a_int;
2568                         arg = arg->next;
2569                         j = arg->a_int;
2570                         if (j > breakpoints.number)
2571                                 j = breakpoints.number;
2572                         for (; i <= j; i++) {
2573                                 if ((b = find_breakpoint(i)) != NULL)
2574                                         enable_breakpoint(b, disp);
2575                         }
2576                 } else {
2577                         assert(arg->type == D_int);
2578                         if ((b = find_breakpoint(arg->a_int)) == NULL)
2579                                 d_error(_("invalid breakpoint number"));
2580                         else
2581                                 enable_breakpoint(b, disp);
2582                 }
2583         }
2584         return FALSE;
2585 }
2586
2587 /* do_delete_breakpoint --- delete command */
2588
2589 int
2590 do_delete_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2591 {
2592         if (arg == NULL) {
2593                 int delete_all = TRUE;
2594                 delete_all = prompt_yes_no(
2595                                         _("Delete all breakpoints? (y or n) "),
2596                                         _("y")[0], TRUE, out_fp);
2597                 
2598                 if (delete_all) {
2599                         while (breakpoints.next != &breakpoints)
2600                                 delete_breakpoint(breakpoints.next);
2601                 }
2602         }
2603
2604         for (; arg != NULL; arg = arg->next) {
2605                 BREAKPOINT *b;
2606                 if (arg->type == D_range) {
2607                         long i, j;
2608
2609                         i = arg->a_int;
2610                         arg = arg->next;
2611                         j = arg->a_int;
2612                         if (j > breakpoints.number)
2613                                 j = breakpoints.number;
2614                         for (; i <= j; i++) {
2615                                 if ((b = find_breakpoint(i)) != NULL)
2616                                         delete_breakpoint(b);
2617                         }
2618                 } else {
2619                         if ((b = find_breakpoint(arg->a_int)) == NULL)
2620                                 d_error(_("invalid breakpoint number"));
2621                         else
2622                                 delete_breakpoint(b);
2623                 }
2624         }
2625         return FALSE;
2626 }
2627
2628 /* do_ignore_breakpoint --- ignore command */
2629
2630 int
2631 do_ignore_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2632 {
2633         BREAKPOINT *b;
2634
2635         if (arg == NULL || arg->type != D_int
2636                         || arg->next == NULL || arg->next->type != D_int)
2637                 return FALSE;
2638
2639         if ((b = find_breakpoint(arg->a_int)) == NULL)
2640                 d_error(_("invalid breakpoint number"));
2641         else {
2642                 b->ignore_count = arg->next->a_int;
2643                 if (b->ignore_count > 0) {
2644                         b->flags |= BP_IGNORE;
2645                         fprintf(out_fp, _("Will ignore next %ld crossing(s) of breakpoint %d.\n"),
2646                                         b->ignore_count, b->number);
2647                 } else {
2648                         b->flags &= ~BP_IGNORE;
2649                         fprintf(out_fp, _("Will stop next time breakpoint %d is reached.\n"),
2650                                         b->number);
2651                 }
2652         }
2653         return FALSE;
2654 }
2655
2656 /* do_disable_breakpoint --- disable command */
2657
2658 int
2659 do_disable_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2660 {
2661         BREAKPOINT *b;
2662
2663         if (arg == NULL) {
2664                 /* disable all */
2665                 for (b = breakpoints.next; b != &breakpoints; b = b->next)
2666                         b->flags &= ~BP_ENABLE;
2667         }
2668
2669         for (; arg != NULL; arg = arg->next) {
2670                 if (arg->type == D_range) {
2671                         long i, j;
2672
2673                         i = arg->a_int;
2674                         arg = arg->next;
2675                         j = arg->a_int;
2676                         if (j > breakpoints.number)
2677                                 j = breakpoints.number;
2678                         for (; i <= j; i++)
2679                                 if ((b = find_breakpoint(i)) != NULL)
2680                                         b->flags &= ~BP_ENABLE;
2681                 } else {
2682                         if ((b = find_breakpoint(arg->a_int)) == NULL)
2683                                 d_error(_("invalid breakpoint number"));
2684                         else
2685                                 b->flags &= ~BP_ENABLE;
2686                 }
2687         }
2688         return FALSE;
2689 }
2690
2691 #ifdef HAVE_LIBREADLINE
2692
2693 /* get_parmlist --- list of function params in current context */
2694
2695 char **
2696 get_parmlist()
2697 {
2698         NODE *func;
2699
2700         if (! prog_running)
2701                 return NULL;
2702         func = find_frame(cur_frame)->func_node;
2703         if (func == NULL)       /* in main */
2704                 return NULL;
2705         return func->parmlist;
2706 }
2707
2708 /* initialize_readline --- initialize readline */
2709
2710 static void
2711 initialize_readline()
2712 {
2713         /* tell readline which stream to use for output,
2714          * default input stream is stdin.
2715          */
2716         rl_outstream = out_fp;
2717
2718         /* allow conditional parsing of the ~/.inputrc file. */
2719         rl_readline_name = "gawk";
2720
2721         /* our completion function. */
2722         rl_attempted_completion_function = command_completion;
2723
2724         read_a_line = readline;  
2725 }
2726 #else
2727 #define initialize_readline()   /* nothing */
2728 #endif
2729
2730
2731 /* interpret --- debugger entry point */
2732
2733 int
2734 interpret(INSTRUCTION *pc)
2735 {
2736         char *run;
2737
2738         input_fd = fileno(stdin);
2739         out_fp = stdout;
2740         if (os_isatty(input_fd))
2741                 input_from_tty = TRUE;
2742         if (input_fd == 0 && input_from_tty)
2743                 initialize_readline();
2744
2745         if (! read_a_line)
2746                 read_a_line = g_readline;
2747
2748         push_cmd_src(input_fd, input_from_tty, read_a_line, 0, 0, EXIT_FATAL); 
2749
2750         setbuf(out_fp, (char *) NULL);                                                           
2751         for (cur_srcfile = srcfiles->prev; cur_srcfile != srcfiles;
2752                         cur_srcfile = cur_srcfile->prev) {
2753                 if (cur_srcfile->stype == SRC_FILE
2754                         || cur_srcfile->stype == SRC_INC)
2755                         break;
2756         }
2757
2758         if (cur_srcfile == srcfiles) {
2759                 fprintf(out_fp, _("Can only debug programs provided with the `-f' option.\n"));
2760                 exit(EXIT_FAILURE);
2761         }
2762
2763         dgawk_Prompt = estrdup(DEFAULT_PROMPT, strlen(DEFAULT_PROMPT));
2764         dPrompt = dgawk_Prompt;
2765
2766         memset(&stop, 0, sizeof(stop));
2767         stop.command = D_illegal;
2768
2769         if ((run = getenv("DGAWK_RESTART")) != NULL) {
2770                 /* We are restarting; restore state (breakpoints, history etc.)
2771                  * passed as environment variables and optionally execute the run command.
2772                  */
2773                 unserialize(BREAK);
2774                 unserialize(WATCH);
2775                 unserialize(DISPLAY);
2776                 unserialize(HISTORY);
2777                 unserialize(OPTION);
2778                 unsetenv("DGAWK_RESTART");
2779                 fprintf(out_fp, "Restarting ...\n");    
2780                 if (run[0] == 'T') 
2781                         (void) do_run(NULL, 0);
2782
2783         } else if (command_file != NULL) {
2784                 /* run commands from a file (--command=file  or -R file) */
2785                 int fd;
2786                 fd = open_readfd(command_file);
2787                 if (fd == INVALID_HANDLE) {
2788                         fprintf(stderr, _("can't open source file `%s' for reading (%s)"),
2789                                                 command_file, strerror(errno));
2790                         exit(EXIT_FAILURE);
2791                 }
2792                 push_cmd_src(fd, FALSE, g_readline, close, 0, EXIT_FAILURE);
2793                 cmd_src->str = estrdup(command_file, strlen(command_file));
2794
2795         } else {
2796                 int fd;
2797
2798 #ifdef HAVE_LIBREADLINE
2799                 (void) read_history(history_file);
2800                 sess_history_base = history_length;
2801 #endif
2802
2803                 /* read saved options */
2804                 fd = open_readfd(options_file);
2805                 if (fd > INVALID_HANDLE)
2806                         push_cmd_src(fd, FALSE, g_readline, close, 0, EXIT_SUCCESS);
2807         }
2808
2809         /* start the command interpreter */
2810         read_command(); /* yyparse */
2811         return EXIT_SUCCESS;
2812 }
2813
2814
2815 /* N.B.: ignore breakpoints and watchpoints for return command */
2816
2817 /* check_watchpoint --- check if any watchpoint triggered */
2818
2819 static int
2820 check_watchpoint()
2821 {
2822         struct list_item *w;
2823
2824         if (stop.command == D_return)
2825                 return FALSE;
2826         for (w = watch_list.prev; w != &watch_list; w = w->prev) {
2827                 int wnum = watchpoint_triggered(w);
2828                 if (wnum > 0) {
2829                         stop.watch_point = wnum;
2830                         stop.print_frame = TRUE;
2831                         return TRUE;
2832                 }
2833         }
2834         return FALSE;
2835 }
2836
2837 /* check_breakpoint --- check if breakpoint triggered */
2838
2839 static int
2840 check_breakpoint(INSTRUCTION **pi)
2841 {
2842         INSTRUCTION *pc;
2843
2844         pc = *pi;
2845         if (stop.command == D_return)
2846                 return FALSE; 
2847         if (pc->opcode == Op_breakpoint) {
2848                 int bnum;
2849                 *pi = pc->nexti;    /* skip past the breakpoint instruction;
2850                                      * interpreter doesn't process Op_breakpoint.
2851                                      */
2852                 bnum = breakpoint_triggered(pc->break_pt);
2853                 if (bnum > 0) {
2854                         stop.break_point = bnum;
2855                         stop.print_frame = TRUE;
2856                         return TRUE;
2857                 }
2858         }
2859         return FALSE;
2860 }
2861
2862 /* restart --- restart the debugger */
2863
2864 static void
2865 restart(int run)
2866 {
2867         /* save state in the environment after serialization */
2868         serialize(BREAK);
2869         serialize(WATCH);
2870         serialize(DISPLAY);
2871         serialize(HISTORY);
2872         serialize(OPTION);
2873
2874         /* tell the new process to restore state from the environment */
2875         setenv("DGAWK_RESTART", (run ? "TRUE" : "FALSE"), 1);
2876
2877         /* close all open files */
2878         close_all();
2879
2880         /* start a new process replacing the current process */
2881         execvp(d_argv[0], d_argv);
2882
2883         /* execvp failed !!! */
2884         fprintf(out_fp, _("Failed to restart debugger"));
2885         exit(EXIT_FAILURE);
2886 }
2887
2888 /* do_run --- run command */
2889
2890 int
2891 do_run(CMDARG *arg ATTRIBUTE_UNUSED, int cmd ATTRIBUTE_UNUSED)
2892 {
2893         if (prog_running) {
2894                 if (! input_from_tty)
2895                         need_restart = TRUE;    /* handled later */
2896                 else {
2897                         need_restart = prompt_yes_no(
2898                                  _("Program already running. Restart from beginning (y/n)? "),
2899                                  _("y")[0], FALSE, out_fp);
2900
2901                         if (! need_restart) {
2902                                 fprintf(out_fp, _("Program not restarted\n"));
2903                                 return FALSE;
2904                         }
2905                 }
2906         }
2907
2908         if (need_restart) {
2909                 /* avoid endless cycles of restarting */
2910                 if (command_file != NULL) {
2911                         /* input_from_tty = FALSE */
2912                         fprintf(stderr, _("error: cannot restart, operation not allowed\n"));
2913                         exit(EXIT_FAILURE);
2914                 }
2915
2916                 if (cmd_src->cmd == D_source) {
2917                         /* input_from_tty = FALSE */
2918                         fprintf(out_fp, _("error (%s): cannot restart, ignoring rest of the commands\n"), cmd_src->str);
2919                         pop_cmd_src();
2920                         return FALSE;
2921                 }
2922
2923                 restart(TRUE);  /* does not return */
2924         }
2925
2926         fprintf(out_fp, _("Starting program: \n"));
2927
2928         prog_running = TRUE;
2929         fatal_tag_valid = TRUE;
2930         if (setjmp(fatal_tag) == 0)
2931                 (void) r_interpret(code_block);
2932
2933         fatal_tag_valid = FALSE;
2934         prog_running = FALSE;
2935         fprintf(out_fp, _("Program exited %s with exit value: %d\n"),
2936                                         (! exiting && exit_val != EXIT_SUCCESS) ? "abnormally"
2937                                                                                 : "normally",
2938                                         exit_val);
2939         need_restart = TRUE;
2940         return FALSE;
2941 }
2942
2943 /* do_quit --- quit command */
2944
2945 int
2946 do_quit(CMDARG *arg ATTRIBUTE_UNUSED, int cmd ATTRIBUTE_UNUSED)
2947 {
2948         int terminate = TRUE;
2949         if (prog_running)
2950                 terminate = prompt_yes_no(
2951                             _("The program is running. Exit anyway (y/n)? "),
2952                             _("y")[0], TRUE, out_fp);
2953         if (terminate) {
2954                 close_all();
2955                 do_trace = FALSE;       /* don't save 'trace on' */
2956
2957 #ifdef HAVE_LIBREADLINE
2958                 if (do_save_history && input_from_tty) {
2959                         int ret;
2960                         ret = write_history(history_file);
2961                         if (ret == 0 && history_length > history_size)
2962                                 (void) history_truncate_file(history_file, history_size);
2963                 }
2964 #endif
2965                 if (do_save_options && input_from_tty)
2966                         save_options(options_file);
2967
2968                 exit(exit_val);
2969         }
2970         return FALSE;
2971 }
2972
2973 /* do_continue --- continue command */
2974
2975 int
2976 do_continue(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2977 {
2978         BREAKPOINT *b;
2979
2980         CHECK_PROG_RUNNING();
2981         if (! arg || arg->type != D_int)
2982                 return TRUE;
2983
2984         /* arg is breakpoint ignore count if stopped at a breakpoint */
2985         if (! stop.break_point) {
2986                 fprintf(out_fp, _("Not stopped at any breakpoint; argument ignored.\n"));
2987                 return TRUE;
2988         }
2989         b = find_breakpoint(stop.break_point);
2990         if (b == NULL) {
2991                 d_error(_("invalid breakpoint number %d."), stop.break_point);
2992                 return FALSE;
2993         }
2994         b->flags |= BP_IGNORE;
2995         b->ignore_count = arg->a_int;
2996         fprintf(out_fp, _("Will ignore next %ld crossings of breakpoint %d.\n"),
2997                                 b->ignore_count, stop.break_point);
2998         return TRUE;
2999 }
3000
3001 /* next_step --- common code for next and step commands */
3002
3003 static int
3004 next_step(CMDARG *arg, int cmd)
3005 {
3006         CHECK_PROG_RUNNING();
3007         if (arg != NULL && arg->type == D_int)
3008                 stop.repeat_count = arg->a_int;
3009         else
3010                 stop.repeat_count = 1;
3011         stop.command = cmd;
3012         return TRUE;
3013 }
3014
3015 /* check_step --- process step command, return TRUE if stopping */
3016
3017 static int
3018 check_step(INSTRUCTION **pi)
3019 {
3020         if (fcall_count != stop.fcall_count) {
3021                 stop.fcall_count = fcall_count;
3022                 stop.sourceline = sourceline;
3023                 stop.source = source;
3024                 stop.print_frame = TRUE;
3025                 return (--stop.repeat_count == 0);
3026         }
3027
3028         if (source != stop.source) {
3029                 stop.source = source;
3030                 stop.sourceline = sourceline;
3031                 return (--stop.repeat_count == 0);
3032         }
3033
3034         if (sourceline != stop.sourceline) {
3035                 stop.sourceline = sourceline;
3036                 return (--stop.repeat_count == 0);
3037         }
3038         return FALSE;
3039 }
3040
3041 /* do_step -- process step command, return TRUE if stopping */
3042
3043 int
3044 do_step(CMDARG *arg, int cmd)
3045 {
3046         int ret;
3047         ret = next_step(arg, cmd);
3048         if (ret) {
3049                 stop.fcall_count = fcall_count;
3050                 stop.source = source;
3051                 stop.sourceline = sourceline;
3052                 stop.check_func = check_step;
3053         }
3054         return ret;
3055 }
3056
3057 /* do_stepi -- process stepi command, return TRUE if stopping */
3058
3059 static int
3060 check_stepi(INSTRUCTION **pi)
3061 {
3062         return (--stop.repeat_count == 0);
3063 }
3064
3065 /* do_stepi -- stepi command */
3066
3067 int
3068 do_stepi(CMDARG *arg, int cmd)
3069 {
3070         int ret;
3071         ret = next_step(arg, cmd);
3072         if (ret)
3073                 stop.check_func = check_stepi;
3074         return ret;
3075 }
3076
3077
3078 /* check_next -- process next command returning TRUE if stopping */
3079
3080 static int
3081 check_next(INSTRUCTION **pi)
3082 {
3083         /* make sure not to step inside function calls */
3084
3085         if (fcall_count < stop.fcall_count) {
3086                 stop.fcall_count = fcall_count;
3087                 stop.sourceline = sourceline;
3088                 stop.source = source;
3089                 stop.print_frame = TRUE;
3090                 return (--stop.repeat_count == 0);
3091         }
3092
3093         if (fcall_count == stop.fcall_count) {
3094                 if (source != stop.source) {
3095                         stop.source = source;
3096                         stop.sourceline = sourceline;
3097                         return (--stop.repeat_count == 0);
3098                 }
3099                 if (sourceline != stop.sourceline) {
3100                         stop.sourceline = sourceline;
3101                         return (--stop.repeat_count == 0);
3102                 }
3103         }
3104
3105 #if 0
3106         /* redundant ? */
3107         if (fcall_count > stop.fcall_count) {
3108                 stop.source = source;
3109                 stop.sourceline = sourceline;
3110         }
3111 #endif
3112
3113         return FALSE;
3114 }
3115
3116 /* do_next -- next command */
3117
3118 int
3119 do_next(CMDARG *arg, int cmd)
3120 {
3121         int ret;
3122
3123         ret = next_step(arg, cmd);
3124         if (ret) {
3125                 stop.source = source;
3126                 stop.sourceline = sourceline;
3127                 stop.fcall_count = fcall_count;
3128                 stop.check_func = check_next;
3129         }
3130         return ret;
3131 }
3132
3133 /* check_nexti --- process nexti command, returns TRUE if stopping */
3134
3135 static int
3136 check_nexti(INSTRUCTION **pi)
3137 {
3138
3139         /* make sure not to step inside function calls */
3140
3141         if (fcall_count < stop.fcall_count) {
3142                 stop.print_frame = TRUE;
3143                 stop.fcall_count = fcall_count;
3144         }
3145         return (fcall_count == stop.fcall_count
3146                         && --stop.repeat_count == 0);
3147 }
3148
3149 /* do_nexti -- nexti command */
3150
3151 int
3152 do_nexti(CMDARG *arg, int cmd)
3153 {
3154         int ret;
3155
3156         ret = next_step(arg, cmd);
3157         if (ret) {
3158                 stop.fcall_count = fcall_count;
3159                 stop.check_func = check_nexti;
3160         }
3161         return ret;
3162 }
3163
3164 /* check_finish --- process finish command, returns TRUE if stopping */
3165
3166 static int
3167 check_finish(INSTRUCTION **pi)
3168 {
3169         if (fcall_count == stop.fcall_count) {
3170                 stop.print_frame = TRUE;
3171                 return TRUE;
3172         }
3173         return FALSE;
3174 }
3175
3176 /* do_finish --- finish command */
3177
3178 int
3179 do_finish(CMDARG *arg ATTRIBUTE_UNUSED, int cmd)
3180 {
3181         CHECK_PROG_RUNNING();
3182         if (cur_frame == fcall_count) {
3183                 fprintf(out_fp,
3184                         _("'finish' not meaningful in the outermost frame main()\n"));
3185                 return FALSE;
3186         }
3187         stop.fcall_count = fcall_count - cur_frame - 1;
3188         assert(stop.fcall_count >= 0);
3189         fprintf(out_fp, _("Run till return from "));
3190         print_numbered_frame(cur_frame);
3191         stop.check_func = check_finish;
3192         stop.command = cmd;
3193         stop.print_ret = TRUE;
3194         return TRUE;
3195 }
3196
3197 /* check_return --- process return, returns TRUE if stopping */
3198
3199 static int
3200 check_return(INSTRUCTION **pi)
3201 {
3202         assert(fcall_count >= stop.fcall_count);
3203
3204         if (fcall_count == stop.fcall_count) {
3205                 stop.print_frame = TRUE;
3206                 return TRUE;
3207         }
3208
3209         if (fcall_count > stop.fcall_count) {   /* innermost frame just returned */
3210                 /* force this one to return too */
3211                 NODE *func;
3212
3213                 func = find_frame(cur_frame)->func_node;
3214                 assert(func != NULL);
3215                 *pi = (func->code_ptr + 1)->lasti;              
3216                 /* assert((*pi)->opcode == Op_K_return); */
3217         }
3218
3219         return FALSE;
3220 }
3221
3222 /* do_return --- return command */
3223
3224 int
3225 do_return(CMDARG *arg, int cmd)
3226 {
3227         NODE *func;
3228
3229         CHECK_PROG_RUNNING();
3230         func = find_frame(cur_frame)->func_node;
3231         if (func == NULL) {
3232                 fprintf(out_fp, _("'return' not meaningful in the outermost frame main()\n"));
3233                 return FALSE;
3234         }
3235
3236         stop.fcall_count = fcall_count - cur_frame - 1;
3237         assert(stop.fcall_count >= 0);
3238         stop.pc = (func->code_ptr + 1)->lasti;
3239         assert(stop.pc->opcode == Op_K_return);
3240         stop.command = cmd;
3241
3242         stop.check_func = check_return;
3243
3244         if (arg != NULL && arg->type == D_node) {       /* optional return value */
3245                 NODE *n;
3246                 n = dupnode(arg->a_node);
3247                 PUSH(n);
3248         } else
3249                 PUSH(Nnull_string);
3250
3251         return TRUE;
3252 }
3253
3254 /* check_until --- process until, returns TRUE if stopping */
3255
3256 int
3257 check_until(INSTRUCTION **pi)
3258 {
3259         if (fcall_count < stop.fcall_count) { /* current stack frame returned */
3260                 stop.print_frame = TRUE;
3261                 return TRUE;
3262         } else if (fcall_count == stop.fcall_count) {
3263                 if (stop.pc && *pi == stop.pc)          /* until location */
3264                         return TRUE;
3265                 if (stop.sourceline > 0         /* until */
3266                                 && source == stop.source
3267                                 && sourceline > stop.sourceline)
3268                         return TRUE;
3269         }
3270         return FALSE;
3271 }
3272
3273 /* do_until --- until command */
3274
3275 int
3276 do_until(CMDARG *arg, int cmd)
3277 {
3278         SRCFILE *s = cur_srcfile;
3279         char *src = cur_srcfile->src;
3280         int lineno;
3281         INSTRUCTION *rp, *ip;
3282         NODE *func;
3283         
3284         CHECK_PROG_RUNNING();
3285         stop.pc = NULL;
3286         stop.sourceline = 0;
3287
3288         if (arg == NULL) {      /* until without argument */
3289
3290     /* GDB doc.: continue running until a source line past the current line,
3291      * in the current stack frame, is reached. Is used to avoid single
3292      * stepping through a loop more than once. ...
3293      * This means that when you reach the end of a loop after single
3294      * stepping though it, until makes your program continue execution
3295      * until it exits the loop. In contrast, a next command at the end
3296      * of a loop simply steps back to the beginning of the loop, which
3297      * forces you to step through the next iteration.
3298      */
3299
3300                 stop.source = source;
3301                 stop.sourceline = sourceline;
3302                 stop.fcall_count = fcall_count - cur_frame;
3303                 stop.check_func = check_until;
3304                 stop.command = cmd;
3305                 return TRUE;
3306         }
3307
3308     /* GDB: until location - continue running program until
3309      * either the specified location is reached, or the
3310      * current stack frame returns.
3311      */
3312
3313         switch (arg->type) {
3314         case D_string:  /* until filename : lineno|function */
3315                 s = source_find(arg->a_string);
3316                 arg = arg->next;
3317                 if (s == NULL || arg == NULL
3318                         || (arg->type != D_int && arg->type != D_func))
3319                         return FALSE;
3320                 src = s->src;
3321                 if (arg->type == D_func)
3322                         goto func;
3323                 /* else
3324                         fall through */
3325         case D_int:     /* until lineno */
3326                 lineno = arg->a_int;
3327                 if (lineno <= 0 || lineno > s->srclines) {
3328                         d_error(_("line number %d in file `%s' out of range"),
3329                                                 lineno, src);
3330                         return FALSE;
3331                 }
3332                 break;
3333
3334         case D_func:    /* until function */
3335 func:
3336                 func = arg->a_node;
3337                 rp = func->code_ptr;
3338                 for (ip = rp->nexti; ip; ip = ip->nexti) {
3339                         if (ip->opcode != Op_breakpoint && ip->source_line > 0) {
3340                                 stop.pc = ip;
3341                                 stop.fcall_count = fcall_count - cur_frame;
3342                                 stop.check_func = check_until;
3343                                 stop.command = cmd;
3344                                 return TRUE;
3345                         }
3346                 }
3347                 fprintf(out_fp, _("Can't find specified location in function `%s'\n"),
3348                                 func->lnode->param);
3349                 /* fall through */
3350         default:
3351                 return FALSE;
3352         }
3353
3354         if ((rp = find_rule(src, lineno)) == NULL) {
3355                 d_error(_("invalid source line %d in file `%s'"), lineno, src);
3356                 return FALSE;
3357         }
3358
3359         for (ip = rp->nexti; ip; ip = ip->nexti) {
3360                 if (ip->opcode != Op_breakpoint && ip->source_line >= lineno) {
3361                         stop.pc = ip;
3362                         stop.fcall_count = fcall_count - cur_frame;
3363                         stop.check_func = check_until;
3364                         stop.command = cmd;
3365                         return TRUE;
3366                 }
3367                 if (ip == (rp + 1)->lasti)
3368                         break;
3369         }
3370         fprintf(out_fp, _("Can't find specified location %d in file `%s'\n"),
3371                                 lineno, src);
3372         return FALSE;
3373 }
3374
3375 /* print_watch_item --- print watched item name, old and current values */
3376
3377 static void
3378 print_watch_item(struct list_item *w)
3379 {
3380         NODE *symbol, *sub;
3381         int i;
3382
3383         symbol = w->symbol;
3384         if (IS_SUBSCRIPT(w)) {
3385                 fprintf(out_fp, "%s", w->sname);
3386                 for (i = 0; i < w->num_subs; i++) {
3387                         sub = w->subs[i];
3388                         fprintf(out_fp, "[\"%s\"]", sub->stptr);
3389                 }
3390                 fprintf(out_fp, "\n");  
3391         } else if (IS_FIELD(w))
3392                 fprintf(out_fp, "$%ld\n", (long) symbol->numbr);
3393         else
3394                 fprintf(out_fp, "%s\n", w->sname);
3395
3396
3397 #define print_value(X, S, V)                                        \
3398 if (X)                                                              \
3399         fprintf(out_fp, "array, %ld elements\n", w->S);                 \
3400 else if (! w->V)                                                    \
3401         fprintf(out_fp, IS_SUBSCRIPT(w) ?                               \
3402                         _("element not in array\n") : _("untyped variable\n")); \
3403 else                                                                \
3404         valinfo(w->V, fprintf, out_fp);
3405
3406         fprintf(out_fp, "  Old value: ");
3407         print_value((w->flags & OLD_IS_ARRAY), old_size, old_value);
3408         fprintf(out_fp, "  New value: ");
3409         print_value((w->flags & CUR_IS_ARRAY), cur_size, cur_value);
3410
3411 #undef print_value
3412 }
3413
3414 /* next_command --- (optionally) print stoppage location and reason;
3415  *                  also fetch next debug command from the user.
3416  */
3417
3418 static void
3419 next_command()
3420 {
3421         static int last_rule = 0;
3422         struct list_item *d = NULL, *w = NULL;
3423         BREAKPOINT *b = NULL;
3424         SRCFILE *s;
3425
3426         if (source == NULL) {
3427                 stop.command = D_illegal;
3428                 stop.check_func = NULL;
3429                 return;
3430         }
3431
3432         if (stop.break_point) {
3433                 b = find_breakpoint(stop.break_point);
3434                 assert(b != NULL);
3435                 if (b->silent)
3436                         goto no_output;
3437         } else if (stop.watch_point) {
3438                 w = find_item(&watch_list, stop.watch_point);
3439                 if (w->silent)
3440                         goto no_output;
3441         }
3442
3443         if (cur_rule != last_rule) {
3444                 fprintf(out_fp, _("Stopping in %s ...\n"), ruletab[cur_rule]);
3445                 last_rule = cur_rule;
3446         }
3447
3448         if (b != NULL)
3449                 fprintf(out_fp, "Breakpoint %d, ", b->number);
3450         else if (w != NULL) {
3451                 fprintf(out_fp, "Watchpoint %d: ", w->number);
3452                 print_watch_item(w);
3453         }
3454
3455         /* frame info */        
3456         if (stop.print_frame) {
3457                 print_frame(frame_ptr->func_node, source, sourceline);
3458                 fprintf(out_fp, "\n");
3459                 stop.print_frame = FALSE;
3460         } 
3461
3462         (void) print_lines(source, sourceline, 1);
3463
3464         /* automatic display of variables */
3465         for (d = display_list.prev; d != &display_list; d = d->prev)
3466                 display(d);
3467
3468 no_output:
3469         /* update last_printed_line, so that  output of 'list' is
3470          * centered around current sourceline
3471          */
3472  
3473         last_printed_line = sourceline - list_size / 2;
3474         if (last_printed_line < 0)
3475                 last_printed_line = 0;
3476
3477         /* update current source file */        
3478         s = source_find(source);
3479         if (cur_srcfile != s) {
3480                 if (cur_srcfile->fd != INVALID_HANDLE) {
3481                         close(cur_srcfile->fd);
3482                         cur_srcfile->fd = INVALID_HANDLE;
3483                 }
3484                 cur_srcfile = s;
3485         }
3486
3487         stop.command = D_illegal;
3488         stop.check_func = NULL;
3489
3490         if (b != NULL) {
3491                 int ret;
3492                 ret = execute_commands(&b->commands);
3493                 if ((b->flags & BP_TEMP) != 0)
3494                         delete_breakpoint(b);
3495                 if (ret)        /* resume execution */
3496                         return;
3497         } else if (w != NULL && execute_commands(&w->commands))
3498                 return;
3499
3500         read_command();         /* zzparse */
3501 }
3502
3503 /* post_execute --- post_hook in the interpreter */ 
3504
3505 void
3506 post_execute(INSTRUCTION *pc)
3507 {
3508         if (! in_main_context())
3509                 return;
3510
3511         switch (pc->opcode) {
3512         case Op_K_next:
3513         case Op_K_nextfile:
3514         case Op_K_exit:
3515                 if (stop.command == D_finish) {
3516                         /* cancel finish command */
3517                         stop.print_ret = FALSE;
3518                         stop.print_frame = FALSE;
3519                         stop.command = D_illegal;
3520                         stop.check_func = NULL;
3521                         fprintf(out_fp, _("'finish' not meaningful with non-local jump '%s'\n"),
3522                                                         op2str(pc->opcode)); 
3523                 } else if (stop.command == D_until) {
3524                         /* cancel until command */
3525                         stop.print_frame = FALSE;
3526                         stop.command = D_illegal;
3527                         stop.check_func = NULL;
3528                         fprintf(out_fp, _("'until' not meaningful with non-local jump '%s'\n"),
3529                                                         op2str(pc->opcode)); 
3530                 }
3531                 break;
3532
3533         case Op_K_return:
3534                 if (stop.command == D_finish
3535                                 && fcall_count == stop.fcall_count
3536                                 && stop.print_ret
3537                 ) {
3538                         NODE *r;
3539                         /* print the returned value before it disappears. */
3540                         r = TOP();
3541                         fprintf(out_fp, "Returned value = ");
3542                         valinfo(r, fprintf, out_fp);
3543                         stop.print_ret = FALSE;
3544                 }
3545                 break;
3546
3547         case Op_newfile:
3548         case Op_get_record:
3549                 return;
3550
3551         default:
3552                 break;
3553         }
3554 }
3555
3556 /* pre_execute --- pre_hook, called by the interpreter before execution; 
3557  *                 checks if execution needs to be suspended and control
3558  *                 transferred to the debugger.
3559  */
3560
3561 int
3562 pre_execute(INSTRUCTION **pi)
3563 {
3564         static int cant_stop = FALSE;
3565         NODE *m;
3566
3567         if (! in_main_context())
3568                 return pre_execute_code(pi);
3569
3570         cur_pc = *pi;
3571         stop.break_point = 0;
3572         stop.watch_point = 0;
3573         cur_frame = 0;
3574
3575         if (do_trace
3576                 && cur_pc->opcode != Op_breakpoint
3577                 && stop.command != D_return
3578         )
3579                 print_instruction(cur_pc, fprintf, out_fp, FALSE);
3580
3581 /* N.B.: For Op_field_spec_lhs must execute instructions upto Op_field_assign
3582  * as a group before stopping. Otherwise, watch/print of field variables
3583  * yield surprising results. Ditto for Op_push_lhs for special variables
3584  * (upto Op_var_assign, the set_FOO routine).
3585  */
3586  
3587         switch (cur_pc->opcode) {
3588         case Op_field_spec_lhs:
3589                 cant_stop = TRUE;
3590                 break;
3591
3592         case Op_field_assign:
3593                 cant_stop = FALSE;
3594                 return TRUE; /* may stop at next instruction */ 
3595
3596         case Op_push_lhs:
3597                 m = cur_pc->memory;
3598                 if (m->type == Node_var && m->var_assign)
3599                         cant_stop = TRUE;
3600                 break;
3601
3602         case Op_arrayfor_incr:  /* can have special var as array variable !!! */
3603                 m = cur_pc->array_var;
3604                 if (m->type == Node_var && m->var_assign)
3605                         cant_stop = TRUE;
3606                 break;
3607
3608         case Op_var_assign:
3609                 cant_stop = FALSE;
3610                 return TRUE; /* may stop at next instruction */
3611
3612         case Op_rule:
3613                 cur_rule = cur_pc->in_rule;
3614                 return TRUE;
3615
3616         case Op_func:
3617         case Op_ext_func:
3618         case Op_var_update:
3619                 return TRUE;
3620
3621         case Op_breakpoint:
3622                 break;  /* processed later in check_breakpoint() */
3623
3624         default:
3625                 if (cur_pc->source_line <= 0) 
3626                         return TRUE;
3627                 break;
3628         }
3629
3630         if (cant_stop)
3631                 return TRUE;
3632
3633         assert(sourceline > 0);
3634
3635         if (check_breakpoint(pi)
3636                         || check_watchpoint()
3637                         || (stop.check_func && stop.check_func(pi))) {
3638                 next_command(); /* return to debugger interface */
3639                 if (stop.command == D_return)
3640                         *pi = stop.pc;  /* jump to this instruction */
3641         }
3642
3643         /* if cur_pc == *pi, interpreter executes cur_pc;
3644          * Otherwise, jumps to instruction *pi.
3645          */
3646         return (cur_pc == *pi);
3647 }
3648
3649 /* print_memory --- print a scalar value */
3650
3651 static void 
3652 print_memory(NODE *m, char **fparms, Func_print print_func, FILE *fp)
3653 {
3654         switch (m->type) {
3655                 case Node_val:
3656                         if (m == Nnull_string)
3657                                 print_func(fp, "Nnull_string");
3658                         else if ((m->flags & NUMBER) != 0)
3659                                 print_func(fp, "%g", m->numbr);
3660                         else if ((m->flags & STRING) != 0)
3661                                 pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', FALSE);
3662                         else if ((m->flags & NUMCUR) != 0)
3663                                 print_func(fp, "%g", m->numbr);
3664                         else if ((m->flags & STRCUR) != 0)
3665                                 pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', FALSE);
3666                         else
3667                                 print_func(fp, "-?-");
3668                         print_func(fp, " [%s]", flags2str(m->flags));
3669                         break;
3670
3671                 case Node_regex:
3672                         pp_string_fp(print_func, fp, m->re_exp->stptr, m->re_exp->stlen, '/', FALSE);
3673                         break;
3674
3675                 case Node_dynregex:
3676                         break;
3677                         
3678                 case Node_param_list:
3679                         assert(fparms != NULL);
3680                         print_func(fp, "%s", fparms[m->param_cnt]);
3681                         break;
3682
3683                 case Node_var:
3684                 case Node_var_new:
3685                 case Node_var_array:
3686                         print_func(fp, "%s", m->vname);
3687                         break;
3688
3689                 default:
3690                         print_func(fp, "?");  /* can't happen */
3691         }
3692 }
3693
3694 /* print_instruction --- print a bytecode */
3695
3696 static void
3697 print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
3698 {
3699         static char **fparms = NULL;
3700         int pcount = 0;
3701         NODE *func = NULL;
3702         static int noffset = 0;
3703
3704         if (noffset == 0) {
3705                 static char buf[50];
3706                 /* offset for 2nd to last lines in a multi-line output */
3707                 noffset = sprintf(buf, "[      :%p] %-20.20s: ", pc, opcode2str(pc->opcode));
3708         }
3709
3710         if (pc->opcode == Op_func) {
3711                 func = pc->func_body;
3712                 fparms = get_params(func);
3713                 pcount = get_param_count(func);
3714                 if (in_dump) {
3715                         int j;
3716                         print_func(fp, "\n\t# Function: %s (", func->lnode->param);
3717                         for (j = 0; j < pcount; j++) {
3718                                 print_func(fp, "%s", fparms[j]);
3719                                 if (j < pcount - 1)
3720                                         print_func(fp, ", ");
3721                         }
3722                         print_func(fp, ")\n\n");
3723                 }
3724         } else if (pc->opcode == Op_ext_func) {
3725                 func = pc->func_body;
3726                 fparms = get_params(func);
3727                 pcount = get_param_count(func);
3728                 if (in_dump)
3729                         print_func(fp, "\n\t# Extension function: %s (... %d params ...)\n\n",
3730                                                 func->lnode->param, pcount);
3731         } else if (pc->opcode == Op_rule) {
3732                 if (in_dump)
3733                         print_func(fp, "\n\t# %s\n\n", ruletab[pc->in_rule]);
3734         }
3735
3736         if (pc->opcode == Op_newfile)
3737                 print_func(fp, "\n");
3738
3739         if (pc->source_line <= 0)
3740                 print_func(fp, "[      :%p] %-20.20s: ", pc, opcode2str(pc->opcode));
3741         else
3742                 print_func(fp, "[%6d:%p] %-20.20s: ",
3743                                 pc->source_line, pc, opcode2str(pc->opcode));
3744
3745         if (prog_running && ! in_dump) {
3746                 /* find params in the current frame */
3747                 func = find_frame(0)->func_node;
3748                 if (func != NULL)
3749                         fparms = get_params(func);
3750                 /* else
3751                         fparms = NULL; */
3752         }
3753
3754                         
3755         switch (pc->opcode) {
3756         case Op_var_update:
3757                 print_func(fp, "[update_%s()]\n", get_spec_varname(pc->update_var));
3758                 break;
3759
3760         case Op_var_assign:
3761                 print_func(fp, "[set_%s()]", get_spec_varname(pc->assign_var));
3762                 if (pc->assign_ctxt != 0)
3763                         print_func(fp, " [assign_ctxt = %s]", opcode2str(pc->assign_ctxt));
3764                 print_func(fp, "\n");
3765                 break;
3766
3767         case Op_field_assign:
3768                 print_func(fp, "[%s]\n", pc->field_assign == reset_record ?
3769                                         "reset_record()" : "invalidate_field0()");
3770                 break;
3771
3772         case Op_field_spec_lhs:
3773                 print_func(fp, "[target_assign = %p] [do_reference = %s]\n",
3774                                 pc->target_assign, pc->do_reference ? "TRUE" : "FALSE");
3775                 break;
3776
3777         case Op_ext_func:
3778                 print_func(fp, "[param_cnt = %d]\n", pcount);
3779                 break; 
3780
3781         case Op_func:
3782                 print_func(fp, "[param_cnt = %d] [source_file = %s]\n", pcount,
3783                                 pc->source_file ? pc->source_file : "cmd. line");
3784                 break;
3785
3786         case Op_K_getline_redir:
3787                 print_func(fp, "[into_var = %s] [redir_type = \"%s\"]\n",
3788                                 pc->into_var ? "TRUE" : "FALSE",
3789                                 redir2str(pc->redir_type));
3790                 break;
3791
3792         case Op_K_getline:
3793                 print_func(fp, "[into_var = %s]\n", pc->into_var ? "TRUE" : "FALSE");
3794                 print_func(fp, "%*s[target_beginfile = %p] [target_endfile = %p]\n",
3795                                 noffset, "",
3796                                 (pc + 1)->target_beginfile, (pc + 1)->target_endfile);
3797                 break;
3798
3799         case Op_K_print_rec:
3800                 print_func(fp, "[redir_type = \"%s\"]\n", redir2str(pc->redir_type));
3801                 break;
3802
3803         case Op_K_print:
3804         case Op_K_printf:
3805                 print_func(fp, "[expr_count = %ld] [redir_type = \"%s\"]\n",
3806                                 pc->expr_count, redir2str(pc->redir_type));
3807                 break;
3808
3809         case Op_indirect_func_call:
3810         case Op_func_call:
3811                 print_func(fp, "[func_name = %s] [arg_count = %ld]\n",
3812                                 pc->func_name, (pc + 1)->expr_count);
3813                 break;
3814
3815         case Op_K_nextfile:
3816                 print_func(fp, "[target_newfile = %p] [target_endfile = %p]\n",
3817                                 pc->target_newfile, pc->target_endfile);
3818                 break;
3819
3820         case Op_newfile:
3821                 print_func(fp, "[target_jmp = %p] [target_endfile = %p]\n",
3822                                 pc->target_jmp, pc->target_endfile);
3823                 print_func(fp, "%*s[target_get_record = %p]\n",
3824                                 noffset, "", (pc + 1)->target_get_record);
3825                 break;
3826
3827         case Op_get_record:
3828                 print_func(fp, "[target_newfile = %p]\n", pc->target_newfile);
3829                 break;
3830
3831         case Op_jmp:
3832         case Op_jmp_false:
3833         case Op_jmp_true:
3834         case Op_and:
3835         case Op_or:
3836         case Op_K_next:
3837         case Op_arrayfor_init:
3838         case Op_K_break:
3839         case Op_K_continue:
3840                 print_func(fp, "[target_jmp = %p]\n", pc->target_jmp);
3841                 break;
3842         case Op_K_exit:
3843                 print_func(fp, "[target_end = %p] [target_atexit = %p]\n",
3844                                                 pc->target_end, pc->target_atexit);
3845                 break;
3846
3847         case Op_K_case:
3848                 print_func(fp, "[target_jmp = %p] [match_exp = %s]\n",
3849                                                 pc->target_jmp, (pc + 1)->match_exp ? "TRUE" : "FALSE");
3850                 break;
3851
3852         case Op_arrayfor_incr:
3853                 print_func(fp, "[array_var = %s] [target_jmp = %p]\n",
3854                                 pc->array_var->type == Node_param_list ?
3855                                    fparms[pc->array_var->param_cnt] : pc->array_var->vname,
3856                                 pc->target_jmp);
3857                 break;
3858
3859         case Op_line_range:
3860                 print_func(fp, "[triggered = %ld] [target_jmp = %p]\n",
3861                                 pc->triggered, pc->target_jmp);
3862                 break;
3863
3864         case Op_cond_pair:
3865                 print_func(fp, "[line_range = %p] [target_jmp = %p]\n",
3866                                 pc->line_range, pc->target_jmp);
3867                 break;
3868
3869         case Op_sub_builtin:
3870         {
3871                 const char *fname = "sub";
3872                 static const struct flagtab values[] = {
3873                         { GSUB, "GSUB" },
3874                         { GENSUB, "GENSUB" },
3875                         { LITERAL, "LITERAL" },
3876                         { 0, NULL }
3877                 };
3878
3879                 if (pc->sub_flags & GSUB)
3880                         fname = "gsub";
3881                 else if (pc->sub_flags & GENSUB)
3882                         fname = "gensub";
3883                 print_func(fp, "%s [arg_count = %ld] [sub_flags = %s]\n",
3884                                 fname, pc->expr_count,
3885                                 genflags2str(pc->sub_flags, values));
3886         }
3887                 break;
3888         
3889         case Op_builtin:
3890         {
3891                 const char *fname = getfname(pc->builtin);
3892                 if (fname == NULL)
3893                         print_func(fp, "(extension func) [arg_count = %ld]\n", pc->expr_count);
3894                 else
3895                         print_func(fp, "%s [arg_count = %ld]\n", fname, pc->expr_count);
3896         }
3897                 break;
3898
3899         case Op_subscript:
3900         case Op_sub_array:
3901                 print_func(fp, "[sub_count = %ld]\n", pc->sub_count);
3902                 break;
3903
3904         case Op_store_sub:
3905                 print_memory(pc->memory, fparms, print_func, fp);
3906                 print_func(fp, " [sub_count = %ld]\n", pc->expr_count);
3907                 break;
3908
3909         case Op_subscript_lhs:
3910                 print_func(fp, "[sub_count = %ld] [do_reference = %s]\n",
3911                                 pc->sub_count,
3912                                 pc->do_reference ? "TRUE" : "FALSE");
3913                 break;
3914
3915         case Op_K_delete:
3916         case Op_in_array:
3917                 print_func(fp, "[expr_count = %ld]\n", pc->expr_count);
3918                 break;
3919
3920         case Op_concat:
3921                 /* NB: concat_flag CSVAR only used in grammar, don't display it */ 
3922                 print_func(fp, "[expr_count = %ld] [concat_flag = %s]\n",
3923                                                 pc->expr_count,
3924                                                 (pc->concat_flag & CSUBSEP) ? "CSUBSEP" : "0");
3925                 break;
3926
3927         case Op_rule:
3928                 print_func(fp, "[in_rule = %s] [source_file = %s]\n",
3929                                 ruletab[pc->in_rule],
3930                                 pc->source_file ? pc->source_file : "cmd. line");
3931                 break;
3932
3933         case Op_lint:
3934         {
3935                 static const char *const linttypetab[] = {
3936                         "LINT_illegal",
3937                         "LINT_assign_in_cond",
3938                         "LINT_no_effect"
3939                 };
3940                 print_func(fp, "[lint_type = %s]\n", linttypetab[pc->lint_type]);
3941         }
3942                 break;
3943
3944         case Op_exec_count:
3945                 print_func(fp, "[exec_count = %ld]\n", pc->exec_count);
3946                 break;
3947
3948         case Op_store_var:
3949         case Op_push_lhs:
3950                 print_memory(pc->memory, fparms, print_func, fp);
3951                 print_func(fp, " [do_reference = %s]\n",
3952                                 pc->do_reference ? "TRUE" : "FALSE");
3953                 break;
3954                                 
3955         case Op_push_i:
3956         case Op_push:
3957         case Op_push_arg:
3958         case Op_push_param:
3959         case Op_push_array:
3960         case Op_push_re:
3961         case Op_match_rec:
3962         case Op_match:
3963         case Op_nomatch:
3964         case Op_plus_i:
3965         case Op_minus_i:
3966         case Op_times_i:
3967         case Op_exp_i:
3968         case Op_quotient_i:
3969         case Op_mod_i:
3970         case Op_assign_concat:
3971                 print_memory(pc->memory, fparms, print_func, fp);
3972                 /* fall through */
3973         default:
3974                 print_func(fp, "\n");
3975                 break;
3976         }
3977 }
3978
3979 /* do_trace_instruction --- trace command */
3980
3981 int
3982 do_trace_instruction(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
3983 {
3984         if (arg != NULL && arg->type == D_argument
3985                         && arg->a_argument == A_TRACE_ON)
3986                 do_trace = TRUE;
3987         else
3988                 do_trace = FALSE;
3989         return FALSE;
3990
3991
3992 /* print_code --- print a list of instructions */
3993
3994 static int
3995 print_code(INSTRUCTION *pc, void *x)
3996 {
3997         struct pf_data *data = (struct pf_data *) x;
3998         for (; pc != NULL; pc = pc->nexti)
3999                 print_instruction(pc, data->print_func, data->fp, data->defn /* in_dump */);
4000         return 0;
4001 }
4002
4003 /* do_dump_instructions --- dump command */
4004
4005 int
4006 do_dump_instructions(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4007 {
4008         FILE *fp;
4009   
4010         if (arg != NULL && arg->type == D_string) {
4011                 /* dump to a file */
4012                 if ((fp = fopen(arg->a_string, "w")) == NULL) {
4013                         d_error(_("could not open `%s' for writing (%s)"),
4014                                         arg->a_string, strerror(errno));
4015                         return FALSE;
4016                 }
4017                 pf_data.print_func = fprintf;
4018                 pf_data.fp = fp;
4019                 pf_data.defn = TRUE;    /* in_dump = TRUE */
4020                 (void) print_code(code_block, &pf_data);
4021                 (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_code,
4022                                      FALSE, /* sort */
4023                                      &pf_data /* data */
4024                                    );
4025                 fclose(fp);
4026                 return FALSE;
4027         }
4028
4029         initialize_pager(out_fp);
4030         if (setjmp(pager_quit_tag) == 0) {
4031                 pf_data.print_func = gprintf;
4032                 pf_data.fp = out_fp;
4033                 pf_data.defn = TRUE;    /* in_dump = TRUE */
4034                 (void) print_code(code_block, &pf_data);
4035                 (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_code,
4036                                      FALSE,     /* sort */
4037                                      &pf_data   /* data */
4038                                    );
4039         }
4040         return FALSE;
4041 }
4042
4043 /* do_save --- save command */
4044
4045 int
4046 do_save(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4047 {
4048 #ifdef HAVE_LIBREADLINE
4049         FILE *fp;
4050         HIST_ENTRY **hist_list;
4051         int i;
4052
4053         if ((fp = fopen(arg->a_string, "w")) == NULL) {
4054                 d_error(_("could not open `%s' for writing (%s)"),
4055                                 arg->a_string, strerror(errno));
4056                 return FALSE;
4057         }
4058
4059         hist_list = history_list();
4060         if (hist_list && history_length > sess_history_base) {
4061                 for (i = sess_history_base; hist_list[i] != NULL; i++) {
4062                         char *line;
4063                         line = hist_list[i]->line;
4064
4065                         /* exclude save commands;
4066                          * N.B.: this test may fail if there is another
4067                          * command with the same first 2 letters.
4068                          */
4069
4070                         if (strlen(line) > 1
4071                             && strncmp(line, "sa", 2) == 0)     
4072                                 continue;
4073
4074                         fprintf(fp, "%s\n", line);
4075                 }
4076         }
4077         fclose(fp);
4078 #endif
4079         return FALSE;
4080 }
4081
4082 /* do_option --- option command */
4083
4084 int
4085 do_option(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4086 {
4087         const struct dbg_option *opt;   
4088         char *name, *value;
4089         
4090         if (arg == NULL) {      /* display all available options and corresponding values */
4091                 for (opt = option_list; opt->name; opt++) {
4092                         if (opt->str_val != NULL)
4093                                 fprintf(out_fp, "%s = \"%s\"\n", opt->name, *(opt->str_val));
4094                         else
4095                                 fprintf(out_fp, "%s = %d\n", opt->name, *(opt->num_val));
4096                 }
4097                 return FALSE;
4098         }
4099
4100         name = arg->a_string;
4101         arg = arg->next;
4102         value = arg ? arg->a_string : NULL;
4103
4104         for (opt = option_list; opt->name; opt++) {     /* linear search */
4105                 if (strcmp(name, opt->name) == 0)
4106                         break;
4107         }
4108         if (! opt->name)
4109                 return FALSE;
4110
4111         if (value == NULL) {    /* display current setting */
4112                 if (opt->str_val != NULL)
4113                         fprintf(out_fp, "%s = \"%s\"\n", opt->name, *(opt->str_val));
4114                 else
4115                         fprintf(out_fp, "%s = %d\n", opt->name, *(opt->num_val));
4116         } else
4117                 (*(opt->assign))(value);
4118         return FALSE;
4119 }
4120
4121
4122 #ifdef HAVE_LIBREADLINE
4123
4124 /* initialize_pager --- initialize our idea of the terminal size */ 
4125
4126 void
4127 initialize_pager(FILE *fp)
4128 {
4129         if (! os_isatty(fileno(fp)) || ! input_from_tty || input_fd != 0) {
4130                 screen_width = INT_MAX;
4131                 screen_height = INT_MAX;
4132         } else {
4133                 /* get the terminal size from readline. */
4134
4135                 rl_reset_terminal(NULL); /* N.B.: NULL argument means
4136                                           * "use TERM env variable for terminal name".
4137                                           */
4138                 rl_get_screen_size(&screen_height, &screen_width);
4139                 if (screen_height <= 1)
4140                         screen_height = INT_MAX;
4141                 if (screen_width <= 1)
4142                         screen_width = INT_MAX;
4143         }
4144         pager_lines_printed = 0;
4145 }
4146 #endif
4147
4148 static void
4149 prompt_continue(FILE *fp)
4150 {
4151         int quit_pager = FALSE;
4152
4153         if (os_isatty(fileno(fp)) && input_fd == 0)
4154                 quit_pager = prompt_yes_no(
4155                         _("\t------[Enter] to continue or q [Enter] to quit------"),
4156                         _("q")[0], FALSE, fp);
4157         if (quit_pager)
4158                 longjmp(pager_quit_tag, 1);
4159         pager_lines_printed = 0;
4160 }    
4161
4162 /* gprintf --- like fprintf but allows paging */ 
4163
4164 int
4165 gprintf(FILE *fp, const char *format, ...)
4166 {
4167         va_list args;
4168         static char *buf = NULL;
4169         static size_t buflen = 0;
4170         static int bl = 0;
4171         char *p, *q;
4172         int nchar;
4173
4174 #define GPRINTF_BUFSIZ 512
4175         if (buf == NULL) {
4176                 buflen = GPRINTF_BUFSIZ;
4177                 emalloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
4178         } else if (buflen - bl < GPRINTF_BUFSIZ/2) {
4179                 buflen += GPRINTF_BUFSIZ;
4180                 erealloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
4181         }        
4182 #undef GPRINTF_BUFSIZ
4183         
4184         while (TRUE) {
4185                 va_start(args, format);
4186                 nchar = vsnprintf(buf + bl, buflen - bl, format, args);
4187                 va_end(args);
4188                 if (nchar == 0)
4189                         return 0;
4190                 if (nchar > 0 && nchar < buflen - bl) {
4191                         bl += nchar;
4192                         if (buf[bl-1] != '\n') /* buffer output until see a newline at end */
4193                                 return nchar;
4194                         break;
4195                 }
4196
4197                 /* enlarge buffer, and try again */ 
4198                 buflen *= 2;
4199                 erealloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
4200         }
4201
4202         bl = 0;
4203         for (p = buf; (q = strchr(p, '\n')) != NULL; p = q + 1) {
4204                 int sz = (int) (q - p); 
4205
4206                 while (sz > 0) {
4207                         int cnt;
4208                         cnt = sz > screen_width ? screen_width : sz;
4209
4210                         /* do not print partial line before scrolling */
4211                         if (cnt < sz && (pager_lines_printed == (screen_height - 2)))
4212                                 prompt_continue(fp);
4213
4214                         if (fwrite(p, sizeof(char), cnt, fp) != cnt)
4215                                 return -1;
4216                         if (cnt == sz)
4217                                 break;
4218                         else {
4219                                 if (++pager_lines_printed == (screen_height - 1))
4220                                         prompt_continue(fp);
4221                                 sz -= screen_width;
4222                                 assert(sz > 0);
4223                                 p += cnt;
4224                         }                       
4225                 }
4226
4227                 fprintf(fp, "\n");
4228                 if (++pager_lines_printed == (screen_height - 1))
4229                         prompt_continue(fp);
4230                 p++;
4231         }
4232         return nchar;
4233 }
4234
4235
4236 static int
4237 serialize_subscript(char *buf, int buflen, struct list_item *item)
4238 {
4239         int bl = 0, nchar, i;
4240         NODE *sub;
4241
4242         nchar = snprintf(buf, buflen, "%d%c%d%c%s%c%d%c",
4243                                 item->number, FSEP, D_subscript, FSEP, item->sname, FSEP,
4244                                 item->num_subs, FSEP);
4245         if (nchar <= 0)
4246                 return 0;
4247         else if (nchar >= buflen)       /* need larger buffer */
4248                 return nchar;
4249         bl += nchar;
4250         for (i = 0; i < item->num_subs; i++) {
4251                 sub = item->subs[i];
4252                 nchar = snprintf(buf + bl, buflen - bl, "%lu%c%s%c",
4253                                         (unsigned long) sub->stlen, FSEP, sub->stptr, FSEP);
4254                 if (nchar <= 0)
4255                         return 0;
4256                 bl += nchar;
4257                 if (bl >= buflen)       /* need larger buffer */
4258                         return bl;
4259         }
4260         return bl;
4261 }
4262
4263
4264
4265 /* serialize --- convert a list structure to a byte stream and
4266  *               save in environment.
4267  */
4268
4269 static void
4270 serialize(int type)
4271 {
4272 #ifndef HAVE_LIBREADLINE
4273 #define HIST_ENTRY void
4274 #define history_list()  NULL
4275 #endif
4276
4277         static char *buf = NULL;
4278         static int buflen = 0;
4279         int bl;
4280         BREAKPOINT *b = NULL;
4281         struct list_item *wd = NULL;
4282         HIST_ENTRY **hist_list = NULL;
4283         int hist_index = 0;
4284         struct dbg_option *opt = NULL;
4285         struct commands_item *commands = NULL, *c;
4286         int cnum = 0;
4287         struct condition *cndn = NULL;
4288         void *ptr, *end_ptr;
4289 #ifdef HAVE_LIBREADLINE
4290         HIST_ENTRY *h = NULL;
4291 #endif
4292
4293         switch (type) {
4294         case BREAK:
4295                 end_ptr = (void *) &breakpoints;
4296                 ptr = (void *) breakpoints.prev;
4297                 break;
4298         case WATCH:
4299                 end_ptr = (void *) &watch_list;
4300                 ptr = (void *) watch_list.prev;
4301                 break;
4302         case DISPLAY:
4303                 end_ptr = (void *) &display_list;
4304                 ptr = (void *) display_list.prev;
4305                 break;
4306         case HISTORY:
4307                 hist_list = history_list();
4308                 if (hist_list == NULL) /* empty history list */
4309                         return;
4310                 end_ptr = NULL;
4311                 ptr = (void *) hist_list[0];
4312                 break;
4313         case OPTION:
4314         {
4315                 int n;
4316                 n = sizeof(option_list)/sizeof(option_list[0]);
4317                 end_ptr = (void *) &option_list[n - 1];
4318                 ptr = (void *) option_list;
4319         }
4320                 break;
4321
4322         default:
4323                 return;
4324         }
4325
4326         if (type != HISTORY && ptr == end_ptr)          /* empty list */
4327                 return;
4328
4329 #define SERIALIZE_BUFSIZ 512
4330
4331         if (buf == NULL) {      /* first time */
4332                 buflen = SERIALIZE_BUFSIZ;
4333                 emalloc(buf, char *, buflen + 2, "serialize");
4334         }
4335         bl = 0;
4336
4337         while (ptr != end_ptr) {
4338                 int nchar = 0;
4339                 if (buflen - bl < SERIALIZE_BUFSIZ/2) {
4340 enlarge_buffer:
4341                         buflen *= 2;
4342                         erealloc(buf, char *, buflen + 2, "serialize");
4343                 }
4344
4345 #undef SERIALIZE_BUFSIZ
4346
4347                 /* field seperator is FSEP ('\037'), and the record separator is RSEP ('\036') */
4348
4349                 switch (type) {
4350                 case BREAK:
4351                         b = (BREAKPOINT *) ptr;
4352
4353                         /* src source_line flags ignore_count hit_count number;
4354                          * commands and condition processed later in the end switch
4355                          */
4356
4357                         nchar = snprintf(buf + bl, buflen - bl,
4358                                          "%s%c%d%c%d%c%d%c%d%c%d%c",
4359                                          b->src, FSEP, b->bpi->source_line, FSEP, b->flags, FSEP,
4360                                          (int) b->ignore_count, FSEP,
4361                                          (int) b->hit_count, FSEP, b->number, FSEP);
4362                         cnum = b->number;
4363                         commands = &b->commands;
4364                         cndn = &b->cndn;
4365                         break;
4366                 case DISPLAY:
4367                 case WATCH:
4368                         wd = (struct list_item *) ptr;
4369
4370                         /* subscript    -- number type sname num_subs subs(stlen + stptr) [commands [condition]]
4371                          * variable     -- number type sname [commands [condition]]
4372                          * field        -- number type symbol(numbr) [commands [condition]]
4373                          */
4374
4375                         if (IS_PARAM(wd))       /* exclude parameters */
4376                                 nchar = 0;
4377                         else if (IS_SUBSCRIPT(wd))
4378                                 nchar = serialize_subscript(buf + bl, buflen - bl, wd);
4379                         else if (IS_FIELD(wd))
4380                                 nchar = snprintf(buf + bl, buflen - bl, "%d%c%d%c%d%c",
4381                                             wd->number, FSEP, D_field, FSEP, (int) wd->symbol->numbr, FSEP);
4382                         else
4383                                 nchar = snprintf(buf + bl, buflen - bl, "%d%c%d%c%s%c",
4384                                             wd->number, FSEP, D_variable, FSEP, wd->sname, FSEP);
4385                         cnum = wd->number;      
4386                         commands = &wd->commands;
4387                         cndn = &wd->cndn;
4388                         break;
4389                 case HISTORY:
4390 #ifdef HAVE_LIBREADLINE
4391                         h = (HIST_ENTRY *) ptr;
4392                         nchar = strlen(h->line);
4393                         if (nchar >= buflen - bl)
4394                                 goto enlarge_buffer;
4395                         strcpy(buf + bl, h->line);
4396 #endif
4397                         break;
4398                 case OPTION:
4399                         opt = (struct dbg_option *) ptr;
4400                         if (opt->num_val != NULL)
4401                                 nchar = snprintf(buf + bl, buflen - bl,
4402                                                                 "%s%c%d%c", opt->name, FSEP, *(opt->num_val), FSEP);
4403                         else
4404                                 nchar = snprintf(buf + bl, buflen - bl,
4405                                                                 "%s%c%s%c", opt->name, FSEP, *(opt->str_val), FSEP);
4406                         break;
4407                 default:
4408                         break;
4409                 }
4410
4411                 if (nchar == 0) /* skip empty history lines etc.*/
4412                         ;
4413                 else if (nchar > 0 && nchar  < buflen - bl) {
4414                         bl += nchar;
4415                         buf[bl] = RSEP; /* record */
4416                         buf[++bl] = '\0';
4417                 } else
4418                         goto enlarge_buffer;
4419
4420                 switch (type) {
4421                 case BREAK:
4422                 case WATCH:
4423                         /* recreate the `commands' command strings including the `commands'
4424                          * and `end' commands; command seperator is '\034'.
4425                          * re-parsed in unserialize to recover the commands list.
4426                          * Alternatively, one could encode(serialize) each command and it's arguments.
4427                          */
4428
4429                         bl--;   /* undo RSEP from above */
4430
4431                         /* compute required room in buffer */
4432                         nchar = 0;
4433                         for (c = commands->next; c != commands; c = c->next) {
4434                                 nchar += (strlen(c->cmd_string) + 1);
4435                                 if (c->cmd == D_eval) {
4436                                         CMDARG *a = c->arg;
4437                                         nchar += (strlen(a->a_string) + 1);     /* awk statements */
4438                                         nchar += (strlen("end") + 1);
4439                                 }
4440                         }
4441
4442                         if (nchar > 0) {        /* non-empty commands list */
4443                                 nchar += (strlen("commands ") + 20 + strlen("end") + 2); /* 20 for cnum (an int) */
4444                                 if (nchar > buflen - bl) {
4445                                         buflen = bl + nchar;
4446                                         erealloc(buf, char *, buflen + 3, "serialize");
4447                                 }
4448                                 nchar = sprintf(buf + bl, "commands %d", cnum);
4449                                 bl += nchar;
4450                                 buf[bl++] = CSEP;
4451                                 for (c = commands->next; c != commands; c = c->next) {
4452                                         nchar = strlen(c->cmd_string);
4453                                         memcpy(buf + bl, c->cmd_string, nchar);
4454                                         bl += nchar;
4455                                         buf[bl++] = CSEP;
4456
4457                                         if (c->cmd == D_eval) {
4458                                                 CMDARG *a = c->arg;
4459                                                 nchar = strlen(a->a_string);    /* statements */
4460                                                 memcpy(buf + bl, a->a_string, nchar);
4461                                                 bl += nchar;
4462                                                 buf[bl++] = CSEP;
4463                                                 nchar = strlen("end");  /* end of 'eval' */
4464                                                 memcpy(buf + bl, "end", nchar);
4465                                                 bl += nchar;
4466                                                 buf[bl++] = CSEP;
4467                                         }
4468                                 }
4469                                 nchar = strlen("end");  /* end of 'commands' */
4470                                 memcpy(buf + bl, "end", nchar);
4471                                 bl += nchar;
4472                         }
4473                         buf[bl++] = FSEP;               /* field */
4474                         buf[bl++] = RSEP;               /* record */
4475                         buf[bl] = '\0';
4476         
4477                         /* condition expression */      
4478                         if (cndn->expr) {
4479                                 bl--;   /* undo RSEP from above */
4480                                 nchar = strlen(cndn->expr);
4481                                 if (nchar > buflen - bl) {
4482                                         buflen = bl + nchar;
4483                                         erealloc(buf, char *, buflen + 3, "serialize");
4484                                 }
4485                                 memcpy(buf + bl, cndn->expr, nchar);
4486                                 bl += nchar;
4487                                 buf[bl++] = FSEP;               /* field */
4488                                 buf[bl++] = RSEP;               /* record */
4489                                 buf[bl] = '\0';
4490                         }
4491
4492                         ptr = (type == BREAK) ? (void *) b->prev : (void *) wd->prev;
4493                         break;
4494                 case DISPLAY:
4495                         ptr = (void *) wd->prev;
4496                         break;
4497                 case HISTORY:
4498                         ptr = (void *) hist_list[++hist_index];
4499                         break;
4500                 case OPTION:
4501                         ptr = (void *) (++opt);
4502                         break;
4503                 default:
4504                         break;
4505                 }  
4506         }
4507
4508         if (bl > 0)     /* non-empty list */
4509                 setenv(env_variable[type], buf, 1);
4510 }
4511
4512
4513 static void
4514 unserialize_commands(char *str, int str_len)
4515 {
4516         if (str_len <= 0 || str == NULL)
4517                 return;
4518         commands_string = str;
4519         commands_string_len = str_len;
4520         push_cmd_src(INVALID_HANDLE, FALSE, read_commands_string, 0, 0, EXIT_FATAL);
4521         line_sep = CSEP;
4522         read_command();         /* forced to return in do_commands */
4523         pop_cmd_src();
4524 }
4525
4526
4527 /* unserialize_list_item --- create a list_item structure from unserialized data */
4528  
4529 static struct list_item *
4530 unserialize_list_item(struct list_item *list, char **pstr, int *pstr_len, int field_cnt)
4531 {
4532         int num, type, i;
4533         struct list_item *l;
4534         NODE *symbol = NULL;
4535         int sub_cnt = 0, cnt;
4536         NODE **subs = NULL;
4537
4538         /* subscript    -- number type sname num_subs subs [commands [condition]]
4539          * variable             -- number type sname [commands [condition]]
4540          * field                -- number type symbol(numbr) commands [commands [condition]]
4541          */
4542
4543         num = strtol(pstr[0], NULL, 0);
4544         type = strtol(pstr[1], NULL, 0);
4545
4546         if (type == D_field) {
4547                 int field_num;
4548                 field_num = strtol(pstr[2], NULL, 0);
4549                 symbol = make_number((AWKNUM) field_num);
4550                 cnt = 3;
4551         } else {
4552                 char *name;
4553                 name = estrdup(pstr[2], pstr_len[2]);
4554                 symbol = find_symbol(name, NULL);
4555                 efree(name);
4556                 if (symbol == NULL)
4557                         return NULL;
4558                 cnt = 3;
4559                 if (type == D_subscript) {
4560                         int sub_len;
4561                         sub_cnt = strtol(pstr[3], NULL, 0);
4562                         emalloc(subs, NODE **, sub_cnt * sizeof(NODE *), "unserialize_list_item");
4563                         cnt++;
4564                         for (i = 0; i < sub_cnt; i++) {
4565                                 sub_len = strtol(pstr[cnt], NULL, 0);
4566                                 subs[i] = make_string(pstr[cnt + 1], sub_len);
4567                                 cnt += 2;
4568                         }
4569                 }
4570         }
4571
4572         l = add_item(list, type, symbol, NULL);
4573         if (type == D_subscript) {
4574                 l->num_subs = sub_cnt;
4575                 l->subs = subs;
4576         }
4577         l->number = num;        /* keep same item number across executions */
4578         
4579         if (list == &watch_list) {
4580                 initialize_watch_item(l);
4581                 /* unserialize watchpoint `commands' */
4582                 unserialize_commands(pstr[cnt], pstr_len[cnt]);
4583                 cnt++;
4584                 if (field_cnt > cnt) {
4585                         char *expr;
4586                         expr = estrdup(pstr[cnt], pstr_len[cnt]);
4587                         if (parse_condition(D_watch, l->number, expr) != 0)
4588                                 efree(expr);
4589                 }
4590                 if (num > list->number)   /* update list number counter */
4591                         list->number = num;
4592         } else
4593                 list->number = num;
4594
4595         return l;       
4596 }
4597
4598 /* unserialize_breakpoint --- create a breakpoint structure from unserialized data */
4599  
4600 static BREAKPOINT *
4601 unserialize_breakpoint(char **pstr, int *pstr_len, int field_cnt)
4602 {
4603         char *src;
4604         int lineno;
4605         BREAKPOINT *b = NULL;
4606         INSTRUCTION *rp;
4607         SRCFILE *s;
4608
4609         /* src source_line flags ignore_count hit_count number commands [condition] */
4610
4611         src = estrdup(pstr[0], pstr_len[0]);
4612         s = source_find(src);
4613         efree(src);
4614         if (s == NULL)
4615                 return NULL;
4616         src = s->src;
4617         lineno = strtol(pstr[1], NULL, 0);
4618         if (lineno <= 0 || lineno > s->srclines)
4619                 return NULL;
4620         rp = find_rule(src, lineno);
4621         if (rp == NULL
4622                         ||  (b = set_breakpoint_at(rp, lineno, TRUE)) == NULL
4623         )
4624                 return NULL;
4625
4626         b->flags =  strtol(pstr[2], NULL, 0);
4627         b->ignore_count = strtol(pstr[3], NULL, 0);
4628         b->hit_count = strtol(pstr[4], NULL, 0);
4629         b->number =  strtol(pstr[5], NULL, 0);  /* same number as previous run */
4630
4631         if (field_cnt > 6)      /* unserialize breakpoint `commands' */
4632                 unserialize_commands(pstr[6], pstr_len[6]);
4633
4634         if (field_cnt > 7) {    /* condition expression */ 
4635                 char *expr;
4636                 expr = estrdup(pstr[7], pstr_len[7]);
4637                 if (parse_condition(D_break, b->number, expr) != 0)
4638                         efree(expr);
4639         }
4640
4641         if (b->number > watch_list.number)  /* watch and break has same number counter */
4642                 watch_list.number = b->number;  /* update counter */
4643         return b;
4644 }
4645
4646 /* unserialize_option --- set a debugger option from unserialized data. */
4647
4648 static struct dbg_option *
4649 unserialize_option(char **pstr, int *pstr_len, int field_cnt ATTRIBUTE_UNUSED)
4650 {
4651         const struct dbg_option *opt;
4652
4653         for (opt = option_list; opt->name; opt++) {
4654                 if (strncmp(pstr[0], opt->name, pstr_len[0]) == 0) {
4655                         char *value;
4656
4657                         value = estrdup(pstr[1], pstr_len[1]);
4658                         (*(opt->assign))(value);
4659                         efree(value);
4660                         return ((struct dbg_option *) opt);
4661                 }
4662         }
4663         return NULL;
4664 }
4665
4666 /* unserialize -- reconstruct list from serialized data stored in
4667  *                environment variable.
4668  */
4669
4670 static void
4671 unserialize(int type)
4672 {
4673         char *val;
4674         char *p, *q, *r, *s;
4675 #define MAX_FIELD 30
4676         static char *pstr[MAX_FIELD];
4677         static int pstr_len[MAX_FIELD];
4678
4679         val = getenv(env_variable[type]);
4680         if (val == NULL)
4681                 return;
4682
4683         for (p = val; (q = strchr(p, RSEP)) != NULL; p = q + 1) {
4684                 int field_cnt = 0;
4685                 if (type == HISTORY) {
4686                         *q = '\0';
4687                         add_history(p);
4688                         *q = RSEP;
4689                         continue;
4690                 }
4691
4692                 r = p;
4693                 while ((s = strchr(r, FSEP)) != NULL && s < q) {
4694                         pstr[field_cnt] = r;
4695                         pstr_len[field_cnt] = (int) (s - r);
4696                         r = s + 1;
4697                         field_cnt++;
4698                         if (field_cnt == MAX_FIELD)
4699 #ifdef GAWKDEBUG
4700                                 fatal("Increase MAX_FIELD and recompile.\n");
4701 #else
4702                                 return; 
4703 #endif
4704                 }
4705
4706                 switch (type) {
4707                 case BREAK:
4708                         (void) unserialize_breakpoint(pstr, pstr_len, field_cnt);
4709                         break;
4710                 case DISPLAY:
4711                         (void) unserialize_list_item(&display_list, pstr, pstr_len, field_cnt);
4712                         break;
4713                 case WATCH:
4714                         (void) unserialize_list_item(&watch_list, pstr, pstr_len, field_cnt);
4715                         break;
4716                 case OPTION:
4717                         (void) unserialize_option(pstr, pstr_len, field_cnt);
4718                         break;
4719                 case HISTORY:
4720                         /* processed at the beginning of for loop */
4721                         break;
4722                 default:
4723                         break;
4724                 }
4725         }
4726
4727 #ifdef HAVE_LIBREADLINE
4728         if (type == HISTORY)
4729                 sess_history_base = history_length;
4730 #endif
4731
4732         unsetenv(env_variable[type]);
4733 #undef MAX_FIELD
4734 }
4735
4736 static int
4737 prompt_yes_no(const char *mesg, char res_true, int res_default, FILE *fp)
4738 {
4739         char *in_str;
4740         int ret = res_default; /* default */
4741
4742         if (input_from_tty) {
4743                 fprintf(fp, "%s", _(mesg));
4744                 in_str = read_a_line(NULL);
4745                 if (in_str == NULL)     /* EOF */
4746                         exit(EXIT_FAILURE);
4747                 ret = (*in_str == res_true);
4748                 efree(in_str);
4749         }
4750         return ret;
4751 }
4752
4753 /* has_break_or_watch_point --- check if given breakpoint or watchpoint
4754  *                              number exists. When flag any is TRUE,
4755  *                              check if any breakpoint/watchpoint
4756  *                              has been set (ignores num). Returns
4757  *                              type (breakpoint or watchpoint) or 0.
4758  */
4759
4760 int
4761 has_break_or_watch_point(int *pnum, int any)
4762 {
4763         BREAKPOINT *b = NULL;
4764         struct list_item *w = NULL;
4765
4766         if (any) {
4767                 if (breakpoints.next != &breakpoints)
4768                         b = breakpoints.next;
4769                 if (watch_list.next != &watch_list)
4770                         w = watch_list.next;
4771
4772                 if (! b && ! w)
4773                         return 0;
4774                 if (b && ! w) {
4775                         *pnum = b->number;
4776                         return D_break;
4777                 }
4778                 if (w && ! b) {
4779                         *pnum = w->number;
4780                         return D_watch;
4781                 }
4782                 if (w->number > b->number) {
4783                         *pnum = w->number;
4784                         return D_watch;
4785                 }
4786                 *pnum = b->number;
4787                 return D_break;
4788         }
4789
4790         /* N.B: breakpoints and watchpoints get numbers from a single
4791          * counter/sequencer watch_list.number.
4792          */ 
4793
4794         for (b = breakpoints.next; b != &breakpoints; b = b->next) {
4795                 if (b->number == *pnum)
4796                         return D_break;
4797         }
4798         for (w = watch_list.next; w != &watch_list; w = w->next) {
4799                 if (w->number == *pnum)
4800                         return D_watch;
4801         }
4802
4803         return 0;
4804 }
4805
4806 /* delete_commands_item --- delete item(command) from `commands' list. */
4807
4808 static void
4809 delete_commands_item(struct commands_item *c)
4810 {
4811         efree(c->cmd_string);
4812         free_cmdarg(c->arg);
4813         c->next->prev = c->prev;
4814         c->prev->next = c->next;
4815         efree(c);
4816 }
4817
4818 /* do_commands --- commands command */
4819
4820 int
4821 do_commands(CMDARG *arg, int cmd)
4822 {
4823         static BREAKPOINT *b;
4824         static struct list_item *w;
4825         static struct commands_item *commands;
4826         struct commands_item *c;
4827         
4828         if (cmd == D_commands) {
4829                 int num, type;
4830                 if (arg == NULL)
4831                         type = has_break_or_watch_point(&num, TRUE);
4832                 else {
4833                         num = arg->a_int;
4834                         type = has_break_or_watch_point(&num, FALSE);
4835                 }
4836                 b = NULL;
4837                 w = NULL;
4838                 if (type == D_break)
4839                         b = find_breakpoint(num);
4840                 else if (type == D_watch)
4841                         w = find_item(&watch_list, num);
4842                 assert((b != NULL) || (w != NULL));
4843                 commands = (b != NULL) ? &b->commands : &w->commands;
4844
4845                 /* delete current commands */
4846                 for (c = commands->next; c != commands; c = c->next) {
4847                         c = c->prev;
4848                         delete_commands_item(c->next);
4849                 }
4850                 return FALSE;
4851
4852         } else if (cmd == D_end) {
4853                 commands = NULL;
4854                 if (read_a_line == read_commands_string) /* unserializig commands */
4855                         return TRUE;    /* done unserializing, terminate zzparse() */
4856                 return FALSE;
4857
4858         } else if (cmd == D_silent) {
4859                 if (b != NULL)
4860                         b->silent = TRUE;
4861                 else if (w != NULL)
4862                         w->silent = TRUE;
4863                 /* we also append silent command to the list for use
4864                  * in `info break(watch)', and to simplify
4865                  * serialization/unserialization of commands.
4866                  */
4867         }
4868
4869         assert(commands != NULL);
4870
4871         emalloc(c, struct commands_item *, sizeof(struct commands_item), "do_commands");
4872         c->next = NULL;
4873         c->cmd = cmd;
4874
4875         /* N.B.: first arg is the command string, see command.y */ 
4876         c->cmd_string = arg->a_string;
4877         c->arg = arg->next; /* actual arguments to the command */
4878         efree(arg);
4879
4880         /* append to the list */
4881         c->prev = commands->prev;
4882         c->next = commands;
4883         commands->prev = c;
4884         c->prev->next = c;
4885         return FALSE;
4886 }
4887
4888 /* execute_commands --- execute breakpoint/watchpoint commands, the first
4889  *                      command that resumes execution terminates
4890  *                      commands processing.
4891  */
4892
4893 static int
4894 execute_commands(struct commands_item *commands)
4895 {
4896         struct commands_item *c;
4897         Func_cmd cmd_ptr;
4898         int ret = FALSE;
4899
4900         for (c = commands->next; c != commands; c = c->next) {
4901                 if (c->cmd == D_silent)
4902                         continue;
4903                 cmd_ptr = get_command(c->cmd);          /* command handler */
4904                 ret = (*cmd_ptr)(c->arg, c->cmd);
4905                 if (ret)        /* resume execution (continue, next etc.) */
4906                         break;
4907         }
4908         return ret;
4909 }
4910
4911 /* do_print_f --- printf command */
4912
4913 int
4914 do_print_f(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4915 {
4916         int count = 0;
4917         int i;
4918         CMDARG *a;
4919         NODE **tmp;
4920         char *name;
4921         NODE *r;
4922         volatile jmp_buf fatal_tag_stack;
4923
4924         /* count maximum required size for tmp */
4925         for (a = arg; a != NULL ; a = a->next)
4926                 count++;
4927         emalloc(tmp, NODE **, count * sizeof(NODE *), "do_print_f");
4928
4929         for (i = 0, a = arg; a != NULL ; i++, a = a->next) {
4930                 switch (a->type) {
4931                 case D_variable:
4932                         name = a->a_string;
4933                         r = find_symbol(name, NULL);
4934                         if (r == NULL)
4935                                 goto done;
4936                         if (r->type == Node_var_new)
4937                                 tmp[i] = Nnull_string;
4938                         else if (r->type != Node_var) {
4939                                 d_error(_("`%s' is not a scalar variable"), name);
4940                                 goto done;
4941                         } else
4942                                 tmp[i] = r->var_value;
4943                         break;
4944                 case D_field:
4945                 {
4946                         long field_num;
4947                         r = a->a_node;
4948                         field_num = (long) r->numbr;
4949                         tmp[i] = *get_field(field_num, NULL);
4950                 }
4951                         break;
4952                 case D_subscript:
4953                 {
4954                         int cnt = a->a_count;
4955                         name = a->a_string;
4956                         r = find_array(name);
4957                         if (r == NULL)
4958                                 goto done;
4959
4960                         for (; cnt > 0; cnt--) {
4961                                 NODE *value, *subs; 
4962                                 a = a->next;
4963                                 subs = a->a_node;
4964                                 value = in_array(r, subs);
4965                                 if (cnt == 1) {
4966                                         if (value == NULL)
4967                                                 tmp[i] = Nnull_string;          /* FIXME: goto done ? */
4968                                         else if (value->type == Node_var_array) {
4969                                                 d_error(_("attempt to use array `%s[\"%s\"]' in a scalar context"),
4970                                                                         name, subs->stptr);
4971                                                 goto done;
4972                                         } else 
4973                                                 tmp[i] = value;
4974                                 } else {
4975                                         if (value == NULL) {
4976                                                 d_error(_("[\"%s\"] not in array `%s'"),
4977                                                                         subs->stptr, name);
4978                                                 goto done;
4979                                         } else if (value->type != Node_var_array) {
4980                                                 d_error(_("attempt to use scalar `%s[\"%s\"]' as array"),
4981                                                                         name, subs->stptr);
4982                                                 goto done;
4983                                         } else {
4984                                                 r = value;
4985                                                 name = r->vname;
4986                                         }
4987                                 }
4988                         }
4989                 }
4990                         break;                   
4991                 case D_node:
4992                         tmp[i] = a->a_node;
4993                         break;
4994                 default:
4995                         break;
4996                 }
4997         }
4998
4999         force_string(tmp[0]);
5000
5001         PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5002         if (setjmp(fatal_tag) == 0)
5003                 r = format_tree(tmp[0]->stptr, tmp[0]->stlen, tmp, i);
5004         else {
5005                 /* fatal error, restore exit_val of program */
5006                 exit_val = EXIT_SUCCESS;
5007                 r = NULL;
5008         }
5009         POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5010
5011         if (r != NULL) {
5012                 (void) fwrite(r->stptr, sizeof(char), r->stlen, out_fp);
5013                 unref(r);
5014         }
5015 done:
5016         efree(tmp);
5017         return FALSE;
5018 }
5019
5020 /* do_source --- source command */
5021
5022 int
5023 do_source(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
5024 {
5025         int fd;
5026         char *file = arg->a_string;
5027
5028         fd = open_readfd(file);
5029         if (fd <= INVALID_HANDLE) {
5030                 d_error(_("can't open source file `%s' for reading (%s)"),
5031                                         file, strerror(errno));
5032                 return FALSE;
5033         }
5034
5035         push_cmd_src(fd, FALSE, g_readline, close, D_source, EXIT_SUCCESS);
5036         cmd_src->str = estrdup(file, strlen(file));
5037         return FALSE;
5038 }
5039
5040 /* open_readfd --- open a file for reading */
5041
5042 static int
5043 open_readfd(const char *file)
5044 {
5045         int fd;
5046         
5047         fd = open(file, O_RDONLY);
5048         if (fd <= INVALID_HANDLE)
5049                 return INVALID_HANDLE;
5050         else if (os_isdir(fd)) {
5051                 (void) close(fd);
5052                 errno = EISDIR;
5053                 return INVALID_HANDLE;
5054         }
5055         return fd;
5056 }
5057
5058 /* find_option --- check if option name is valid */
5059
5060 int
5061 find_option(char *name)
5062 {
5063         const char *p;
5064         int idx;
5065
5066         for (idx = 0; (p = option_list[idx].name); idx++) {
5067                 if (strcmp(p, name) == 0)
5068                         return idx;
5069         }
5070         return -1;
5071 }
5072
5073 /* option_help --- display help text for debugger options */
5074
5075 void
5076 option_help()
5077 {
5078         const struct dbg_option *opt;   
5079
5080         for (opt = option_list; opt->name; opt++)
5081                 fprintf(out_fp, "\t%-15.15s - %s\n", opt->name, _(opt->help_txt));
5082 }
5083
5084 #ifdef HAVE_LIBREADLINE
5085         
5086 /* option_generator --- generator function for option name completion */
5087
5088 char *
5089 option_generator(const char *text, int state)
5090 {
5091         static size_t textlen;
5092         static int idx;
5093         const char *name;
5094
5095         if (! state) {  /* first time */
5096                 textlen = strlen(text);
5097                 idx = 0;
5098         }
5099
5100         while ((name = option_list[idx++].name)) {
5101                 if (strncmp(name, text, textlen) == 0)
5102                         return estrdup(name, strlen(name));
5103         }
5104         return NULL;
5105 }
5106
5107 #endif
5108
5109 /* set_gawk_output --- redirect gawk (normal) output */
5110
5111 static void
5112 set_gawk_output(const char *file)
5113 {
5114         int fd = INVALID_HANDLE;
5115         FILE *fp = NULL;
5116
5117         if (output_fp != stdout) {
5118                 if (output_fp != stderr) {
5119                         fclose(output_fp);
5120                         efree(output_file);
5121                 }
5122                 output_fp = stdout;
5123                 output_is_tty = os_isatty(fileno(stdout));
5124                 output_file = "/dev/stdout";
5125         }
5126
5127         if (file == NULL || file[0] == '\0')
5128                 return;
5129
5130         errno = 0;
5131         if ((fd = os_devopen(file, O_WRONLY)) != INVALID_HANDLE) {
5132                 fp = fdopen(fd, "w");
5133                 if (fp == NULL)
5134                         close(fd);
5135
5136         } else if (strncmp(file, "/dev/", 5) == 0) {
5137                 char *cp = (char *) file + 5;
5138
5139                 if (strcmp(cp, "stdout") == 0)
5140                         return;
5141                 if (strcmp(cp, "stderr") == 0) {
5142                         output_fp = stderr;
5143                         output_file = "/dev/stderr";
5144                         output_is_tty = os_isatty(fileno(stderr));
5145                         return;
5146                 }
5147                 
5148                 if (strncmp(cp, "fd/", 3) == 0) {
5149                         cp += 3;
5150                         fd = (int) strtoul(cp, NULL, 10);
5151                         if (errno == 0 && fd > INVALID_HANDLE) {
5152                                 fp = fdopen(fd, "w");
5153                                 if (fp == NULL)
5154                                         fd = INVALID_HANDLE;
5155                         } else
5156                                 fd = INVALID_HANDLE;
5157                 } else {
5158                         /* /dev/ttyN, /dev/pts/N, /dev/null etc. */
5159                         fd = open(file, O_WRONLY);
5160                 }
5161
5162                 if (fd > INVALID_HANDLE && fp == NULL) {
5163                         fp = fdopen(fd, "w");
5164                         if (fp == NULL)
5165                                 close(fd); 
5166                 }
5167
5168         } else {
5169                 /* regular file */
5170                 fp = fopen(file, "w");
5171         }
5172
5173         if (fp != NULL) {
5174                 output_fp = fp;
5175                 output_file = estrdup(file, strlen(file));
5176                 setbuf(fp, (char *) NULL);
5177                 output_is_tty = os_isatty(fileno(fp));
5178         } else {
5179                 d_error(_("could not open `%s' for writing (%s)"),
5180                                         file,
5181                                         errno != 0 ? strerror(errno) : _("reason unknown"));
5182                 fprintf(out_fp, _("sending output to stdout\n"));
5183         }
5184 }
5185
5186 /* set_prompt --- set debugger prompt */
5187
5188 static void
5189 set_prompt(const char *value)
5190 {
5191         efree(dgawk_Prompt);
5192         dgawk_Prompt = estrdup(value, strlen(value));
5193         dPrompt = dgawk_Prompt;
5194 }
5195
5196 /* set_option_flag --- convert option string to flag value */ 
5197
5198 static int
5199 set_option_flag(const char *value)
5200 {
5201         long n;
5202         if (strcmp(value, "on") == 0)
5203                 return TRUE;
5204         if (strcmp(value, "off") == 0)
5205                 return FALSE;
5206         errno = 0;
5207         n = strtol(value, NULL, 0);
5208         return (errno == 0 && n != 0);
5209 }
5210
5211 /* set_option_num --- set integer option value from string */
5212
5213 static void
5214 set_option_num(int *pnum, const char *value)
5215 {
5216         long n;
5217         errno = 0;
5218         n = strtol(value, NULL, 0);
5219         if (errno == 0 && n > 0)
5220                 *pnum = n;
5221         else
5222                 d_error(_("invalid number"));
5223 }
5224
5225 /* set_listsize --- set list output window size */
5226
5227 static void
5228 set_listsize(const char *value)
5229 {
5230         set_option_num(&list_size, value);
5231 }
5232
5233 /* set_trace --- set instruction tracing on or off */
5234
5235 static void
5236 set_trace(const char *value)
5237 {
5238         do_trace = set_option_flag(value);
5239 }
5240
5241 /* set_save_history --- save history on exit */
5242
5243 static void
5244 set_save_history(const char *value)
5245 {
5246         do_save_history = set_option_flag(value);
5247 }
5248
5249 /* set_save_options --- save options on exit */
5250
5251 static void
5252 set_save_options(const char *value)
5253 {
5254         do_save_options = set_option_flag(value);
5255 }
5256
5257 /* set_history_size --- maximum entries in history file */
5258
5259 static void
5260 set_history_size(const char *value)
5261 {
5262         set_option_num(&history_size, value);
5263 }
5264
5265
5266 /* read_commands_string --- one of the many ways zzlex fetches a line to parse;
5267  *                          this one is used to parse `commands' string during
5268  *                          unserialization.
5269  */
5270
5271 char *
5272 read_commands_string(const char *prompt ATTRIBUTE_UNUSED)
5273 {
5274         char *p, *end, *line;
5275
5276         if (commands_string == NULL)
5277                 return NULL;
5278
5279         p = (char *) commands_string;
5280         end = (char *) commands_string + commands_string_len; 
5281         for (; p < end; p++) {
5282                 if (*p == line_sep) {
5283                         line = estrdup(commands_string, p - commands_string);
5284                         commands_string = p + 1;
5285                         commands_string_len = end - commands_string;
5286                         return line;
5287                 }
5288         }
5289
5290         line = estrdup(commands_string, commands_string_len);
5291         commands_string = NULL;
5292         commands_string_len = 0;
5293         return line;
5294 }
5295
5296 /* save_options --- save current options to file */
5297
5298 static void
5299 save_options(const char *file)
5300 {
5301         FILE *fp;
5302         const struct dbg_option *opt;   
5303
5304         fp = fopen(file, "w");
5305         if (fp == NULL)
5306                 return;
5307
5308         for (opt = option_list; opt->name; opt++) {
5309                 if (opt->str_val != NULL)
5310                         fprintf(fp, "option %s = \"%s\"\n", opt->name, *(opt->str_val));
5311                 else
5312                         fprintf(fp, "option %s = %d\n", opt->name, *(opt->num_val));
5313         }
5314         fclose(fp);
5315         chmod(file, 0600);
5316 }
5317
5318 /* close_all --- close all open files */
5319
5320 static void
5321 close_all()
5322 {
5323         int stdio_problem;
5324         struct command_source *cs;
5325
5326         (void) nextfile(&curfile, TRUE);        /* close input data file */
5327         (void) close_io(&stdio_problem);
5328         if (cur_srcfile->fd != INVALID_HANDLE) {
5329                 close(cur_srcfile->fd);
5330                 cur_srcfile->fd = INVALID_HANDLE;
5331         }
5332         for (cs = cmd_src; cs != NULL; cs = cs->next) {
5333                 if (cs->close_func && cs->fd != INVALID_HANDLE) {
5334                         cs->close_func(cs->fd);
5335                         cs->fd = INVALID_HANDLE;
5336                 }
5337         }
5338
5339         set_gawk_output(NULL);  /* closes output_fp if not stdout */ 
5340 }
5341
5342 /* install_params --- install function parameters into the symbol table */
5343
5344 static void
5345 install_params(NODE *func)
5346 {
5347         NODE *np;
5348
5349         if (func == NULL)
5350                 return;
5351         /* function parameters of type Node_param_list */
5352         np = func->lnode;                               
5353         for (np = np->rnode; np != NULL; np = np->rnode) 
5354                 install_symbol(np->param, np);          
5355 }
5356
5357 /* remove_params --- remove function parameters out of the symbol table */
5358
5359 static void
5360 remove_params(NODE *func)
5361 {
5362         NODE *np;
5363
5364         if (func == NULL)
5365                 return;
5366         np = func->lnode;                               
5367         for (np = np->rnode; np != NULL; np = np->rnode)
5368                 remove_symbol(np->param);
5369 }
5370
5371 /* pre_execute_code --- pre_hook for execute_code, called by pre_execute */
5372
5373 static int
5374 pre_execute_code(INSTRUCTION **pi)
5375 {
5376         INSTRUCTION *ei = *pi;
5377
5378         switch (ei->opcode) {
5379         case Op_K_exit:
5380         case Op_K_next:
5381         case Op_K_nextfile:
5382         case Op_K_getline:      /* getline without redirection */
5383                 d_error(_("`%s' not allowed in current context;"
5384                                 " statement ignored"),
5385                                 op2str(ei->opcode));
5386                 *pi = ei->nexti;
5387                 break;
5388         case Op_K_return:
5389                 if (ei->nexti != NULL) {        /* not an implicit return */
5390                         NODE *r;
5391                         d_error(_("`return' not allowed in current context;"
5392                                         " statement ignored"));
5393                         /* throw away return value already pushed onto stack */
5394                         r = POP_SCALAR();
5395                         DEREF(r);
5396                         *pi = ei->nexti;
5397                 }
5398                 break;
5399         default:
5400                 break;
5401         }
5402         return (ei == *pi);
5403 }
5404
5405 extern INSTRUCTION *unwind_stack(long n);
5406
5407 static NODE *
5408 execute_code(volatile INSTRUCTION *code)
5409 {
5410         volatile NODE *r = NULL;
5411         volatile jmp_buf fatal_tag_stack;
5412         long save_stack_size;
5413
5414         /* We use one global stack for all contexts.
5415          * Save # of items in stack; in case of
5416          * a fatal error, pop stack until it has that many items.
5417          */ 
5418         save_stack_size = (stack_ptr  - stack_bottom) + 1;
5419
5420         PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5421         if (setjmp(fatal_tag) == 0) {
5422                 (void) r_interpret((INSTRUCTION *) code);
5423                 r = POP_SCALAR();
5424         } else  /* fatal error */
5425                 (void) unwind_stack(save_stack_size);
5426
5427         POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5428
5429         if (exit_val != EXIT_SUCCESS) { /* must be EXIT_FATAL? */
5430                 exit_val = EXIT_SUCCESS;
5431                 return NULL;
5432         }
5433         return (NODE *) r;
5434 }
5435
5436 /* do_eval --- eval command */
5437
5438 int
5439 do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
5440 {
5441         NODE *r, *ret_val;
5442         NODE *f = NULL;
5443         NODE *this_frame = NULL, *this_func = NULL;
5444         NODE **sp;
5445         INSTRUCTION *eval, *code = NULL;
5446         AWK_CONTEXT *ctxt;
5447         char **save_parmlist = NULL;
5448         int ecount = 0, pcount = 0;
5449         int ret;
5450         
5451         if (prog_running) {
5452                 this_frame = find_frame(0);
5453                 this_func = this_frame->func_node;
5454         }
5455
5456         install_params(this_func);      /* expose current function parameters to eval */ 
5457         ctxt = new_context();
5458         ctxt->install_func = append_symbol;     /* keep track of newly installed globals */
5459         push_context(ctxt);
5460         (void) add_srcfile(SRC_CMDLINE, arg->a_string, srcfiles, NULL, NULL);
5461         ret = parse_program(&code);
5462         remove_params(this_func);
5463         if (ret != 0) {
5464                 pop_context();  /* switch to prev context */
5465                 free_context(ctxt, FALSE /* keep_globals */);
5466                 return FALSE;
5467         }
5468
5469         f = lookup("@eval");
5470         assert(f != NULL);
5471         if (this_func == NULL) {        /* in main */
5472                 /* do a function call */
5473                 eval = bcalloc(Op_func_call, 2, 0);
5474                 eval->source_file = cur_srcfile->src;
5475                 eval->func_body = f;
5476                 eval->func_name = NULL; /* not needed, func_body already assigned */
5477                 (eval + 1)->expr_count = 0;
5478                 eval->nexti = bcalloc(Op_stop, 1, 0);
5479                 
5480         } else {
5481                 /* execute as a part of the current function */ 
5482                 int i;
5483                 char **varnames;
5484                 INSTRUCTION *t;
5485                 NODE *np;
5486
5487                 eval = f->code_ptr;     /* Op_func */
5488                 eval->source_file = cur_srcfile->src;
5489                 /* turn implicit Op_K_return into Op_stop */
5490                 t = (eval + 1)->lasti;  /* Op_K_return */
5491                 t->opcode = Op_stop;
5492
5493                 /* add or append eval locals to the current frame stack */
5494                 ecount = f->lnode->param_cnt;   /* eval local count */
5495                 pcount = this_func->lnode->param_cnt;
5496                 save_parmlist = this_func->parmlist;
5497                 
5498                 if (ecount > 0) {
5499                         if (pcount == 0)
5500                                 emalloc(this_frame->stack, NODE **, ecount * sizeof(NODE *), "do_eval");
5501                         else
5502                                 erealloc(this_frame->stack, NODE **, (pcount + ecount) * sizeof(NODE *), "do_eval");
5503
5504                         emalloc(varnames, char **, (pcount + ecount + 1) * sizeof(char *), "do_eval");
5505                         if (pcount > 0) 
5506                                 memcpy(varnames, save_parmlist, pcount * sizeof(char *));
5507                         for (np = f->lnode->rnode, i = 0; np != NULL; np = np->rnode, i++) {
5508                                 varnames[pcount + i] = np->param;
5509                                 np->param_cnt += pcount;        /* appending eval locals: fixup param_cnt */
5510                         }
5511                         varnames[pcount + ecount] = NULL;
5512                         sp = this_frame->stack + pcount;
5513                         for (i = 0; i < ecount; i++) {
5514                                 getnode(r);
5515                                 memset(r, 0, sizeof(NODE));
5516                                 *sp++ = r;
5517                                 /* local variable */
5518                                 r->type = Node_var_new;
5519                                 r->vname = varnames[pcount + i];
5520                         }
5521
5522                         this_func->parmlist = varnames;
5523                         this_func->lnode->param_cnt += ecount;
5524                 }
5525         }
5526
5527 #if 0
5528         pf_data.print_func = fprintf;
5529         pf_data.fp = out_fp;
5530         pf_data.defn = FALSE;   /* in_dump = FALSE */
5531         (void) print_code(f->code_ptr, &pf_data);
5532 #endif
5533
5534         ret_val = execute_code((volatile INSTRUCTION *) eval);
5535
5536         if (ret_val != NULL)
5537                 DEREF(ret_val); /* throw away return value */
5538         /* else
5539                 fatal error */
5540
5541         if (this_func != NULL && ecount > 0) { 
5542                 int i;
5543
5544                 /* undo frame manipulation from above */
5545
5546                 /* free eval locals */
5547                 sp = this_frame->stack + pcount;
5548                 for (i = ecount; i > 0; i--) {
5549                         r = *sp;
5550                         if (r->type == Node_var)     /* eval local variable */
5551                                 DEREF(r->var_value);
5552                         else if (r->type == Node_var_array)     /* eval local array */
5553                                 assoc_clear(r);
5554                         freenode(r);
5555                         *sp++ = (NODE *) 0;
5556                 }
5557                 if (pcount == 0) {
5558                         efree(this_frame->stack);
5559                         this_frame->stack = NULL;
5560                 } /* else
5561                                 restore_frame() will free it */
5562
5563                 efree(this_func->parmlist);
5564                 this_func->parmlist = save_parmlist;
5565                 this_func->lnode->param_cnt -= ecount;
5566         }
5567
5568         /* always destroy symbol "@eval", however destroy all newly installed
5569          * globals only if fatal error in r_interpret (r == NULL).
5570          */
5571
5572         pop_context();  /* switch to prev context */
5573         free_context(ctxt, (ret_val != NULL));   /* free all instructions and optionally symbols */
5574         if (ret_val != NULL)
5575                 destroy_symbol("@eval");        /* destroy "@eval" */
5576         return FALSE;
5577 }
5578
5579 /*
5580 GDB Documentation:
5581         ... When you use condition, GDB checks expression
5582 immediately for syntactic correctness, and to determine whether symbols
5583 in it have referents in the context of your breakpoint. If expression
5584 uses symbols not referenced in the context of the breakpoint, GDB prints
5585 an error message:       
5586
5587     No symbol "foo" in current context.
5588 */
5589
5590 static int invalid_symbol = 0;
5591
5592 void
5593 check_symbol(char *name)
5594 {
5595         invalid_symbol++;
5596         d_error(_("No symbol `%s' in current context"), name);
5597         /* install anyway, but keep track of it */
5598         append_symbol(name);
5599 }
5600
5601 /* parse_condition --- compile a condition expression */
5602
5603 static int
5604 parse_condition(int type, int num, char *expr)
5605 {
5606         INSTRUCTION *code = NULL;
5607         AWK_CONTEXT *ctxt = NULL;
5608         int ret;
5609         BREAKPOINT *b;
5610         struct list_item *w;
5611         NODE *this_func = NULL;
5612         INSTRUCTION *it, *stop, *rule;
5613         struct condition *cndn = NULL;
5614
5615         if (type == D_break && (b = find_breakpoint(num)) != NULL) {
5616                 INSTRUCTION *rp;
5617                 cndn = &b->cndn;
5618                 rp = find_rule(b->src, b->bpi->source_line);
5619                 if (rp != NULL && rp->opcode == Op_func)
5620                         this_func = rp->func_body; 
5621         } else if (type == D_watch && (w = find_item(&watch_list, num)) != NULL) {
5622                 cndn = &w->cndn;
5623                 this_func = find_frame(cur_frame)->func_node;
5624         }
5625
5626         if (cndn == NULL)
5627                 return -1;
5628         if (expr == NULL)
5629                 goto out;       /* delete condition */
5630
5631         install_params(this_func);
5632         ctxt = new_context();
5633         invalid_symbol = 0;
5634         ctxt->install_func = check_symbol;
5635         push_context(ctxt);
5636         (void) add_srcfile(SRC_CMDLINE, expr, srcfiles, NULL, NULL);
5637         ret = parse_program(&code);
5638         remove_params(this_func); 
5639         pop_context();
5640
5641         if (ret != 0 || invalid_symbol) {
5642                 free_context(ctxt, FALSE /* keep_globals */);
5643                 return -1;
5644         }
5645
5646         /* condition expression is parsed as awk pattern without
5647          * any action. The code is then modified to end up with 
5648          * a `1.0' on stack when the expression is true, `0.0' otherwise.
5649          */
5650
5651         assert(code != NULL);
5652         rule = ctxt->rule_list.nexti;
5653         stop = bcalloc(Op_stop, 1, 0);
5654
5655         it = rule->firsti;      /* Op_K_print_rec */
5656         assert(it->opcode == Op_K_print_rec);
5657         it->opcode = Op_push_i; 
5658         it->memory = mk_number((AWKNUM) 1.0, PERM|NUMBER|NUMCUR);
5659         it->nexti = bcalloc(Op_jmp, 1, 0);
5660         it->nexti->target_jmp = stop;
5661         it->nexti->nexti = rule->lasti;
5662  
5663         it = rule->lasti;               /* Op_no_op, target for Op_jmp_false */
5664         assert(it->opcode == Op_no_op);
5665         it->opcode = Op_push_i;
5666         it->memory = mk_number((AWKNUM) 0.0, PERM|NUMBER|NUMCUR);
5667         it->nexti = stop;
5668
5669 out:
5670         if (cndn->expr != NULL)
5671                 efree(cndn->expr);
5672         free_context(cndn->ctxt, FALSE);
5673         cndn->code = code;
5674         cndn->expr = expr;
5675         cndn->ctxt = ctxt;
5676
5677         return 0;
5678 }
5679
5680 /* do_condition --- condition command */
5681
5682 int
5683 do_condition(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
5684 {
5685         int type, num;
5686         char *expr = NULL;
5687
5688         num = arg->a_int;
5689         type = has_break_or_watch_point(&num, FALSE);
5690         if (! type)
5691                 return FALSE;
5692         arg = arg->next;        /* condition expression */
5693         if (arg != NULL)
5694                 expr = arg->a_string;
5695         if (parse_condition(type, num, expr) == 0 && arg != NULL)
5696                 arg->a_string = NULL;   /* don't let free_cmdarg free it */
5697         return FALSE;
5698 }
5699
5700 /* in_cmd_src --- check if filename already in cmd_src */
5701
5702 int
5703 in_cmd_src(const char *filename)
5704 {
5705         struct command_source *cs;
5706         for (cs = cmd_src; cs != NULL; cs = cs->next) {
5707                 if (cs->str != NULL && strcmp(cs->str, filename) == 0)
5708                         return TRUE;
5709         }
5710         return FALSE;
5711 }
5712
5713 int
5714 get_eof_status()
5715 {
5716         if (cmd_src == NULL)
5717                 return EXIT_FATAL;
5718         return cmd_src->eof_status;
5719 }
5720
5721 void
5722 push_cmd_src(
5723         int fd,
5724         int istty,
5725         char * (*readfunc)(const char *),
5726         int (*closefunc)(int),
5727         int ctype,
5728         int eofstatus)
5729 {
5730         struct command_source *cs;
5731         emalloc(cs, struct command_source *, sizeof(struct command_source), "push_cmd_src");
5732         cs->fd = fd;
5733         cs->is_tty = istty;
5734         cs->read_func = readfunc;
5735         cs->close_func = closefunc;
5736         cs->cmd = ctype;
5737
5738         /* eof_status = EXIT_FATAL     - exit with status EXIT_FATAL on EOF or error.
5739          *            = EXIT_FAILURE   - exit status EXIT_FAILURE on error.
5740          *            = EXIT_SUCCESS   - don't exit on EOF or error. 
5741          */
5742         cs->eof_status = eofstatus;
5743         cs->str = NULL;
5744         cs->next = cmd_src;
5745         cmd_src = cs;
5746
5747         input_fd = fd;
5748         input_from_tty = istty;
5749         read_a_line = readfunc;
5750 }
5751
5752 int
5753 pop_cmd_src()
5754 {
5755         struct command_source *cs;
5756
5757         if (cmd_src->next == NULL)
5758                 return -1;
5759
5760         cs = cmd_src;
5761         cmd_src = cs->next;
5762         if (cs->close_func && cs->fd != INVALID_HANDLE)
5763                 cs->close_func(cs->fd);
5764         if (cs->str != NULL)
5765                 efree(cs->str);
5766         efree(cs);
5767
5768         input_fd = cmd_src->fd;
5769         input_from_tty = cmd_src->is_tty;
5770         read_a_line = cmd_src->read_func;
5771         return 0;
5772 }