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