provide /bin/gawk
[platform/upstream/gawk.git] / command.y
1 /*
2  * command.y - yacc/bison parser for debugger commands.
3  */
4
5 /* 
6  * Copyright (C) 2004, 2010, 2011, 2014 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 %{
27 #include "awk.h"
28 #include "cmd.h"
29
30 #if 0
31 #define YYDEBUG 12
32 int yydebug = 2;
33 #endif
34
35 static int yylex(void);
36 static void yyerror(const char *mesg, ...);
37
38 static int find_command(const char *token, size_t toklen);
39
40 static bool want_nodeval = false;
41
42 static int cmd_idx = -1;                /* index of current command in cmd table */
43 static int repeat_idx = -1;             /* index of last repeatable command in command table */
44 static CMDARG *arg_list = NULL;         /* list of arguments */ 
45 static long errcount = 0;
46 static char *lexptr_begin = NULL;
47 static bool in_commands = false;
48 static int num_dim;
49
50 static bool in_eval = false;
51 static const char start_EVAL[] = "function @eval(){";
52 static const char end_EVAL[] = "}";     
53 static CMDARG *append_statement(CMDARG *stmt_list, char *stmt);
54 static NODE *concat_args(CMDARG *a, int count);
55
56 #ifdef HAVE_LIBREADLINE
57 static char *next_word(char *p, int len, char **endp);
58 static void history_expand_line(char **line);
59 static char *command_generator(const char *text, int state);
60 static char *srcfile_generator(const char *text, int state);
61 static char *argument_generator(const char *text, int state);
62 static char *variable_generator(const char *text, int state);
63 extern char *option_generator(const char *text, int state);
64 static int this_cmd = D_illegal;
65 #else
66 #define history_expand_line(p)  /* nothing */
67 static int rl_inhibit_completion;       /* dummy variable */
68 #endif
69
70 struct argtoken {
71         const char *name;
72         enum argtype cmd;
73         enum nametypeval value;
74 };
75
76 /*
77  * These two should be static, but there are some compilers that
78  * don't like the static keyword with an empty size. Therefore give
79  * them names that are less likely to conflict with the rest of gawk.
80  */
81 #define argtab zz_debug_argtab
82 #define cmdtab zz_debug_cmdtab
83
84 extern struct argtoken argtab[];
85 extern struct cmdtoken cmdtab[];
86
87 static CMDARG *mk_cmdarg(enum argtype type);
88 static void append_cmdarg(CMDARG *arg);
89 static int find_argument(CMDARG *arg);
90 #define YYSTYPE CMDARG *
91 %}
92
93 %token D_BACKTRACE D_BREAK D_CLEAR D_CONTINUE D_DELETE D_DISABLE D_DOWN
94 %token D_ENABLE D_FINISH D_FRAME D_HELP D_IGNORE D_INFO D_LIST
95 %token D_NEXT D_NEXTI D_PRINT D_PRINTF D_QUIT D_RETURN D_RUN D_SET
96 %token D_STEP D_STEPI D_TBREAK D_UP D_UNTIL
97 %token D_DISPLAY D_UNDISPLAY D_WATCH D_UNWATCH
98 %token D_DUMP D_TRACE
99 %token D_INT D_STRING D_NODE D_VARIABLE
100 %token D_OPTION D_COMMANDS D_END D_SILENT D_SOURCE
101 %token D_SAVE D_EVAL D_CONDITION
102 %token D_STATEMENT
103
104 %%
105
106 input
107         : /* empty */
108         | input line
109           {
110                 cmd_idx = -1;
111                 want_nodeval = false;
112                 if (lexptr_begin != NULL) {
113                         if (input_from_tty && lexptr_begin[0] != '\0')
114                                 add_history(lexptr_begin);
115                         efree(lexptr_begin);
116                         lexptr_begin = NULL;
117                 }
118                 if (arg_list != NULL) {
119                         free_cmdarg(arg_list);
120                         arg_list = NULL;
121                 }
122           }
123         ;
124
125 line
126         : nls
127         | command nls
128           {
129                 if (errcount == 0 && cmd_idx >= 0) {
130                         Func_cmd cmdfunc;
131                         bool terminate = false;
132                         CMDARG *args;
133                         int ctype = 0;
134                         
135                         ctype = cmdtab[cmd_idx].type;
136
137                         /* a blank line repeats previous command
138                          * (list, next, nexti, step, stepi and continue without arguments).
139                          * save the index in the command table; used in yylex
140                          */
141                         if ((ctype == D_list
142                                         || ctype == D_next
143                                         || ctype == D_step
144                                         || ctype == D_nexti
145                                         || ctype == D_stepi
146                                         || ctype == D_continue)
147                                 && arg_list == NULL
148                                 && ! in_commands
149                                 && input_from_tty
150                         )
151                                 repeat_idx = cmd_idx;
152                         else
153                                 repeat_idx = -1;
154
155                         /* call the command handler; reset the globals arg_list, cmd_idx,
156                          * since this handler could invoke yyparse again.
157                          * call do_commands for the list of commands in `commands';
158                          * arg_list isn't freed on return.
159                          */
160
161                         cmdfunc = cmdtab[cmd_idx].cf_ptr;
162                         if (in_commands)
163                                 cmdfunc = do_commands;
164                         cmd_idx = -1;
165                         want_nodeval = false;
166
167                         args = arg_list;
168                         arg_list = NULL;
169
170                         terminate = (*cmdfunc)(args, ctype);
171                         if (! in_commands || ctype == D_commands)
172                                 free_cmdarg(args);
173                         if (terminate)
174                                 YYACCEPT;
175                 }
176           }
177         | error nls
178           {
179                 yyerrok;
180           }
181         ;
182
183 control_cmd
184         : D_CONTINUE
185         | D_NEXT
186         | D_NEXTI
187         | D_STEP
188         | D_STEPI
189         ;
190
191 d_cmd
192         : D_UNDISPLAY
193         | D_UNWATCH
194         | D_DISABLE
195         | D_DELETE
196         ;
197
198 frame_cmd
199         : D_UP
200         | D_DOWN
201         | D_BACKTRACE
202         | D_FRAME
203         ;
204
205 break_cmd
206         : D_BREAK
207         | D_TBREAK
208         ;
209
210 /* mid-rule action buried in non-terminal to avoid conflict */
211 set_want_nodeval
212         : { want_nodeval = true; }
213         ;
214
215 eval_prologue
216         : D_EVAL set_want_nodeval opt_param_list nls
217           {
218                 if (errcount == 0) {
219                         /* don't free arg_list; passed on to statement_list
220                          * non-terminal (empty rule action). See below.
221                          */
222                         if (input_from_tty) {
223                                 dbg_prompt = eval_prompt;
224                                 fprintf(out_fp,
225                 _("Type (g)awk statement(s). End with the command \"end\"\n"));
226                                 rl_inhibit_completion = 1;
227                         }
228                         cmd_idx = -1;
229                         in_eval = true;
230                 }
231           }
232         ;
233
234 statement_list
235         : /* empty */
236           {
237                 $$ = append_statement(arg_list, (char *) start_EVAL);
238                 if (read_a_line == read_commands_string)        /* unserializing 'eval' in 'commands' */
239                         $$->a_string[0] = '\0';
240                 free_cmdarg(arg_list);
241                 arg_list = NULL;
242           }
243         | statement_list D_STATEMENT { $$ = append_statement($1, lexptr_begin); } nls
244           {
245                 $$ = $3;
246           }
247         ;
248
249 eval_cmd
250         : eval_prologue statement_list D_END
251           {
252                 arg_list = append_statement($2, (char *) end_EVAL);
253                 if (read_a_line == read_commands_string) {      /* unserializing 'eval' in 'commands' */
254                         char *str = arg_list->a_string;
255                         size_t len = strlen(str);
256                         assert(len > 2 && str[len - 2] == '}');
257                         str[len - 2] = '\0';
258                 }
259                 if (input_from_tty) {
260                         dbg_prompt = in_commands ? commands_prompt : dgawk_prompt;
261                         rl_inhibit_completion = 0;
262                 }
263                 cmd_idx = find_command("eval", 4);
264                 in_eval = false;
265           }
266         | D_EVAL set_want_nodeval string_node
267           {
268                 NODE *n;
269                 CMDARG *arg;
270                 n = $3->a_node;
271                 arg = append_statement(NULL, (char *) start_EVAL);
272                 (void) append_statement(arg, n->stptr);
273                 (void) append_statement(arg, (char *) end_EVAL);
274                 free_cmdarg(arg_list);
275                 arg_list = arg;
276           }
277         ;
278
279 command
280         : D_HELP help_args
281         | D_QUIT
282         | D_RUN
283         | D_FINISH
284         | control_cmd opt_plus_integer
285         | frame_cmd opt_integer
286           {
287                 if (cmdtab[cmd_idx].class == D_FRAME
288                                 && $2 != NULL && $2->a_int < 0)
289                         yyerror(_("invalid frame number: %d"), $2->a_int);
290           }
291         | D_INFO D_STRING
292           {
293                 int idx = find_argument($2);
294                 if (idx < 0)
295                         yyerror(_("info: invalid option - \"%s\""), $2->a_string);
296                 else {
297                         efree($2->a_string);
298                         $2->a_string = NULL;
299                         $2->type = D_argument;
300                         $2->a_argument = argtab[idx].value;
301                 }
302           }
303         | D_IGNORE plus_integer D_INT
304         | D_ENABLE enable_args
305         | D_PRINT { want_nodeval = true; } print_args
306         | D_PRINTF { want_nodeval = true; } printf_args
307         | D_LIST list_args
308         | D_UNTIL location
309         | D_CLEAR location
310         | break_cmd break_args 
311         | D_SET { want_nodeval = true; } variable '=' node
312         | D_OPTION option_args
313         | D_RETURN { want_nodeval = true; } opt_node
314         | D_DISPLAY { want_nodeval = true; } opt_variable
315         | D_WATCH { want_nodeval = true; } variable condition_exp
316         | d_cmd opt_integer_list
317         | D_DUMP opt_string
318         | D_SOURCE D_STRING
319           {
320                 if (in_cmd_src($2->a_string))
321                         yyerror(_("source \"%s\": already sourced."), $2->a_string);
322           }
323         | D_SAVE D_STRING
324           {
325                 if (! input_from_tty)
326                         yyerror(_("save \"%s\": command not permitted."), $2->a_string);
327           }
328         | D_COMMANDS commands_arg
329           {
330                 int type = 0;
331                 int num;
332
333                 if ($2 != NULL)
334                         num = $2->a_int;
335
336                 if (errcount != 0)
337                         ;
338                 else if (in_commands)
339                         yyerror(_("Can't use command `commands' for breakpoint/watchpoint commands"));
340                 else if ($2 == NULL &&  ! (type = has_break_or_watch_point(&num, true)))
341                         yyerror(_("no breakpoint/watchpoint has been set yet"));
342                 else if ($2 != NULL && ! (type = has_break_or_watch_point(&num, false)))
343                         yyerror(_("invalid breakpoint/watchpoint number"));
344                 if (type) {
345                         in_commands = true;
346                         if (input_from_tty) {
347                                 dbg_prompt = commands_prompt; 
348                                 fprintf(out_fp, _("Type commands for when %s %d is hit, one per line.\n"),
349                                                                 (type == D_break) ? "breakpoint" : "watchpoint", num);
350                                 fprintf(out_fp, _("End with the command \"end\"\n"));
351                         }
352                 }
353           }
354         | D_END
355           {
356                 if (! in_commands)
357                         yyerror(_("`end' valid only in command `commands' or `eval'"));
358                 else {
359                         if (input_from_tty)
360                                 dbg_prompt = dgawk_prompt;      
361                         in_commands = false;
362                 }
363           }
364         | D_SILENT
365           {
366                 if (! in_commands)
367                         yyerror(_("`silent' valid only in command `commands'"));
368           }
369         | D_TRACE D_STRING
370           {
371                 int idx = find_argument($2);
372                 if (idx < 0)
373                         yyerror(_("trace: invalid option - \"%s\""), $2->a_string);
374                 else {
375                         efree($2->a_string);
376                         $2->a_string = NULL;
377                         $2->type = D_argument;
378                         $2->a_argument = argtab[idx].value;
379                 }
380           }
381         | D_CONDITION plus_integer { want_nodeval = true; } condition_exp
382           {
383                 int type;
384                 int num = $2->a_int;
385                 type = has_break_or_watch_point(&num, false);
386                 if (! type)
387                         yyerror(_("condition: invalid breakpoint/watchpoint number"));
388           }
389         | eval_cmd
390           {
391                 if (in_commands) {
392                         /* Prepend command 'eval' to argument list */
393                         CMDARG *arg;
394                         arg = mk_cmdarg(D_string);
395                         arg->a_string = estrdup("eval", 4);
396                         arg->next = arg_list;
397                         arg_list = arg;
398                 }
399           }
400         ;
401
402 condition_exp
403         : opt_string_node
404           {
405                 if ($1 != NULL) {
406                         NODE *n = $1->a_node;
407                         $1->type = D_string;
408                         $1->a_string = n->stptr;
409                         freenode(n);
410                 }
411                 $$ = $1;
412           }
413         ;
414
415 commands_arg
416         : opt_plus_integer
417         | error
418           {     $$ = NULL; }
419         ;
420
421 opt_param_list
422         : /* empty */
423           { $$ = NULL; }
424         | param_list
425         ;
426
427 param_list
428         : D_VARIABLE
429         | param_list D_VARIABLE
430         | param_list ',' D_VARIABLE
431         | error
432           { $$ = NULL; }
433         ;
434
435 opt_string_node
436         : /* empty */
437           { $$ = NULL; }
438         | string_node
439         | error
440           { $$ = NULL; }
441         ;
442
443 string_node
444         : D_NODE
445           {
446                 NODE *n;
447                 n = $1->a_node;
448                 if ((n->flags & STRING) == 0)
449                         yyerror(_("argument not a string"));
450           }
451         ;
452
453 option_args
454         : /* empty */
455           { $$ = NULL; }
456         | D_STRING
457           {
458                 if (find_option($1->a_string) < 0)
459                         yyerror(_("option: invalid parameter - \"%s\""), $1->a_string);
460           }
461         | D_STRING '=' D_STRING
462           {
463                 if (find_option($1->a_string) < 0)
464                         yyerror(_("option: invalid parameter - \"%s\""), $1->a_string);
465           }
466         ;
467
468 func_name
469         : D_STRING
470           {
471                 NODE *n;
472                 n = lookup($1->a_string);
473                 if (n == NULL || n->type != Node_func)
474                         yyerror(_("no such function - \"%s\""), $1->a_string);
475                 else {
476                         $1->type = D_func;
477                         efree($1->a_string);
478                         $1->a_string = NULL;
479                         $1->a_node = n;
480                 }
481           }
482         ;
483
484 location
485         : /* empty */
486           { $$ = NULL; }
487         | plus_integer
488         | func_name
489         | D_STRING ':' plus_integer
490         | D_STRING ':' func_name
491         ;
492
493 break_args
494         : /* empty */
495           { $$ = NULL; }        
496         | plus_integer { want_nodeval = true; } condition_exp
497         | func_name 
498         | D_STRING ':' plus_integer { want_nodeval = true; } condition_exp
499         | D_STRING ':' func_name
500         ;
501
502 opt_variable
503         : /* empty */
504           { $$ = NULL; }
505         | variable
506         ;
507
508 opt_string
509         : /* empty */
510           { $$ = NULL; }
511         | D_STRING
512         ;
513
514 opt_node
515         : /* empty */
516           { $$ = NULL; }
517         | node
518         ;
519
520 help_args
521         : /* empty */
522         | D_STRING
523         ;
524
525 enable_args
526         : opt_integer_list
527         | D_STRING opt_integer_list
528           {
529                 int idx = find_argument($1);
530                 if (idx < 0)
531                         yyerror(_("enable: invalid option - \"%s\""), $1->a_string);
532                 else {
533                         efree($1->a_string);
534                         $1->a_string = NULL;
535                         $1->type = D_argument;
536                         $1->a_argument = argtab[idx].value;
537                 }
538           }
539         ;
540
541 print_exp
542         : variable
543         | '@' D_VARIABLE
544           {
545                 $2->type = D_array;     /* dump all items */
546                 $2->a_count = 0;
547           }
548         | '@' D_VARIABLE subscript_list /* dump sub-array items*/
549           {
550                 $2->type = D_array;
551                 $2->a_count = num_dim;
552           }
553         ;
554
555 print_args
556         : print_exp
557         | print_args print_exp
558         | print_args ',' print_exp
559         | error
560         ;
561
562 printf_exp
563         : D_NODE
564         | variable
565         ;
566
567 printf_args
568         : printf_exp
569         | printf_args ',' printf_exp
570         | error
571         ;
572
573 list_args
574         : /* empty */
575           { $$ = NULL; }
576         | '+'
577           { $$ = NULL; }
578         | '-'
579           {
580                 CMDARG *a;
581                 a = mk_cmdarg(D_int);
582                 a->a_int = -1;
583                 append_cmdarg(a);
584           }
585         | plus_integer
586         | func_name
587         | integer_range
588         | D_STRING ':' plus_integer
589         | D_STRING ':' func_name
590         | D_STRING ':' integer_range
591         ;
592
593 integer_range
594         : plus_integer '-' plus_integer
595           {
596                 if ($1->a_int > $3->a_int)
597                         yyerror(_("invalid range specification: %d - %d"),
598                                 $1->a_int, $3->a_int);
599                 else
600                         $1->type = D_range;
601                 $$ = $1;
602           }
603         ;
604
605 opt_integer_list
606         : /* empty */
607           { $$ = NULL; }
608         | integer_list
609         | error
610         ;
611
612 integer_list
613         : plus_integer
614         | integer_range
615         | integer_list plus_integer
616         | integer_list integer_range
617         ;
618
619 exp_list
620         : node
621           { $$ = $1; }
622         | exp_list ',' node
623           { $$ = $1; }
624         | error
625         ;
626
627 subscript
628         : '[' exp_list ']'
629           {
630                 CMDARG *a;
631                 NODE *subs;
632                 int count = 0;
633                 
634                 for (a = $2; a != NULL; a = a->next)
635                         count++;
636                 subs = concat_args($2, count);
637                 free_cmdarg($2->next);
638                 $2->next = NULL;
639                 $2->type = D_node;
640                 $2->a_node = subs;
641                 $$ = $2;
642           }
643         | '[' exp_list error 
644         ;
645
646 subscript_list
647         : subscript
648           { $$ = $1; num_dim = 1; }
649         | subscript_list subscript
650           {     $$ = $1; num_dim++; }
651         ;
652
653 variable
654         : D_VARIABLE
655         | '$' D_NODE
656           {
657                 NODE *n = $2->a_node;
658                 if ((n->flags & NUMBER) == 0)
659                         yyerror(_("non-numeric value for field number"));
660                 else
661                         $2->type = D_field;
662                 $$ = $2;
663           }
664         | D_VARIABLE subscript_list
665           {
666                 /* a_string is array name, a_count is dimension count */
667                 $1->type = D_subscript;
668                 $1->a_count = num_dim;
669                 $$ = $1;
670           }
671         ;
672
673 node
674         : D_NODE
675           { $$ = $1; }
676         | '+' D_NODE
677           { 
678                 NODE *n = $2->a_node;
679                 if ((n->flags & NUMBER) == 0)
680                         yyerror(_("non-numeric value found, numeric expected"));
681                 $$ = $2;
682           }
683         | '-' D_NODE
684           { 
685                 NODE *n = $2->a_node;
686                 if ((n->flags & NUMBER) == 0)
687                         yyerror(_("non-numeric value found, numeric expected"));
688                 else
689                         negate_num(n);
690                 $$ = $2;
691           }
692         ;
693
694 opt_plus_integer
695         : /* empty */
696           { $$ = NULL; }
697         | plus_integer
698           { $$ = $1; }
699         ;
700
701 opt_integer
702         : /* empty */
703           { $$ = NULL; }
704         | integer
705           { $$ = $1; }
706         ;
707                         
708 plus_integer
709         : D_INT
710           {
711                 if ($1->a_int == 0)
712                         yyerror(_("non-zero integer value"));
713                 $$ = $1;
714           }
715         | '+' D_INT
716           {
717                 if ($2->a_int == 0)
718                         yyerror(_("non-zero integer value"));
719                 $$ = $2;
720           }
721         ;
722         
723 integer
724         : D_INT
725           { $$ = $1; }
726         | '+' D_INT
727           { $$ = $2; }
728         | '-' D_INT
729           {
730                 $2->a_int = - $2->a_int;
731                 $$ = $2;
732           }
733         ;
734
735 nls
736         : '\n'
737           {
738                 if (lexptr_begin != NULL) {
739                         if (input_from_tty && lexptr_begin[0] != '\0')
740                                 add_history(lexptr_begin);
741                         efree(lexptr_begin);
742                         lexptr_begin = NULL;
743                 }
744           }
745         ;
746
747 %%
748
749
750 /* append_statement --- append 'stmt' to the list of eval awk statements */ 
751
752 static CMDARG *
753 append_statement(CMDARG *stmt_list, char *stmt) 
754 {
755         CMDARG *a, *arg; 
756         char *s;
757         int len, slen, ssize;
758
759 #define EVALSIZE        512
760
761         if (stmt == start_EVAL) {
762                 len = sizeof(start_EVAL);
763                 for (a = stmt_list; a != NULL; a = a->next)
764                         len += strlen(a->a_string) + 1; /* 1 for ',' */
765                 len += EVALSIZE;
766
767                 emalloc(s, char *, (len + 2) * sizeof(char), "append_statement");
768                 arg = mk_cmdarg(D_string);
769                 arg->a_string = s;
770                 arg->a_count = len;     /* kludge */
771
772                 slen = sizeof("function @eval(") - 1;
773                 memcpy(s, start_EVAL, slen);
774
775                 for (a = stmt_list; a != NULL; a = a->next) {
776                         len = strlen(a->a_string);
777                         memcpy(s + slen, a->a_string, len);
778                         slen += len;
779                         if (a->next != NULL)
780                                 s[slen++] = ',';
781                 }
782                 s[slen++] = ')';
783                 s[slen++] = '{';
784                 s[slen] = '\0';
785                 return arg;
786         }
787                  
788         len = strlen(stmt) + 1; /* 1 for newline */
789         s = stmt_list->a_string;
790         slen = strlen(s);
791         ssize = stmt_list->a_count;
792         if (len > ssize - slen) {
793                 ssize = slen + len + EVALSIZE;
794                 erealloc(s, char *, (ssize + 2) * sizeof(char), "append_statement");
795                 stmt_list->a_string = s;
796                 stmt_list->a_count = ssize;
797         }
798         memcpy(s + slen, stmt, len);
799         slen += len;
800         if (slen >= 2 && s[slen - 2] != '\n') {
801                 s[slen - 1] = '\n';
802                 s[slen] = '\0';
803         }
804
805         if (stmt == end_EVAL)
806                 erealloc(stmt_list->a_string, char *, slen + 2, "append_statement");
807         return stmt_list;
808
809 #undef EVALSIZE
810 }
811
812
813 /* command names sorted in ascending order */
814
815 struct cmdtoken cmdtab[] = {
816 { "backtrace", "bt", D_backtrace, D_BACKTRACE, do_backtrace,
817         gettext_noop("backtrace [N] - print trace of all or N innermost (outermost if N < 0) frames.") },
818 { "break", "b", D_break, D_BREAK, do_breakpoint,
819         gettext_noop("break [[filename:]N|function] - set breakpoint at the specified location.") },
820 { "clear", "", D_clear, D_CLEAR, do_clear,
821         gettext_noop("clear [[filename:]N|function] - delete breakpoints previously set.") },
822 { "commands", "", D_commands, D_COMMANDS, do_commands,
823         gettext_noop("commands [num] - starts a list of commands to be executed at a breakpoint(watchpoint) hit.") },
824 { "condition", "", D_condition, D_CONDITION, do_condition,
825         gettext_noop("condition num [expr] - set or clear breakpoint or watchpoint condition.") },
826 { "continue", "c", D_continue, D_CONTINUE, do_continue,
827         gettext_noop("continue [COUNT] - continue program being debugged.") },
828 { "delete", "d", D_delete, D_DELETE, do_delete_breakpoint,
829         gettext_noop("delete [breakpoints] [range] - delete specified breakpoints.") },
830 { "disable", "", D_disable, D_DISABLE, do_disable_breakpoint,
831         gettext_noop("disable [breakpoints] [range] - disable specified breakpoints.") },
832 { "display", "", D_display, D_DISPLAY, do_display,
833         gettext_noop("display [var] - print value of variable each time the program stops.") },
834 { "down", "", D_down, D_DOWN, do_down,
835         gettext_noop("down [N] - move N frames down the stack.") },
836 { "dump", "", D_dump, D_DUMP, do_dump_instructions,
837         gettext_noop("dump [filename] - dump instructions to file or stdout.") },
838 { "enable", "e", D_enable, D_ENABLE, do_enable_breakpoint,
839         gettext_noop("enable [once|del] [breakpoints] [range] - enable specified breakpoints.") },
840 { "end", "", D_end, D_END, do_commands,
841         gettext_noop("end - end a list of commands or awk statements.") },
842 { "eval", "", D_eval, D_EVAL, do_eval,
843         gettext_noop("eval stmt|[p1, p2, ...] - evaluate awk statement(s).") },
844 { "finish", "", D_finish, D_FINISH, do_finish,
845         gettext_noop("finish - execute until selected stack frame returns.") },
846 { "frame", "f", D_frame, D_FRAME, do_frame,
847         gettext_noop("frame [N] - select and print stack frame number N.") },
848 { "help", "h", D_help, D_HELP, do_help,
849         gettext_noop("help [command] - print list of commands or explanation of command.") },
850 { "ignore", "", D_ignore, D_IGNORE, do_ignore_breakpoint,
851         gettext_noop("ignore N COUNT - set ignore-count of breakpoint number N to COUNT.") },
852 { "info", "i", D_info, D_INFO, do_info,
853         gettext_noop("info topic - source|sources|variables|functions|break|frame|args|locals|display|watch.") },
854 { "list", "l", D_list, D_LIST, do_list,
855         gettext_noop("list [-|+|[filename:]lineno|function|range] - list specified line(s).") },
856 { "next", "n", D_next, D_NEXT, do_next,
857         gettext_noop("next [COUNT] - step program, proceeding through subroutine calls.") },
858 { "nexti", "ni", D_nexti, D_NEXTI, do_nexti,
859         gettext_noop("nexti [COUNT] - step one instruction, but proceed through subroutine calls.") },
860 { "option", "o", D_option, D_OPTION, do_option,
861         gettext_noop("option [name[=value]] - set or display debugger option(s).") },
862 { "print", "p", D_print, D_PRINT, do_print_var,
863         gettext_noop("print var [var] - print value of a variable or array.") },
864 { "printf", "", D_printf, D_PRINTF, do_print_f,
865         gettext_noop("printf format, [arg], ... - formatted output.") },
866 { "quit", "q", D_quit, D_QUIT, do_quit,
867         gettext_noop("quit - exit debugger.") },
868 { "return", "", D_return, D_RETURN, do_return,
869         gettext_noop("return [value] - make selected stack frame return to its caller.") },
870 { "run", "r", D_run, D_RUN, do_run,
871         gettext_noop("run - start or restart executing program.") },
872 #ifdef HAVE_LIBREADLINE
873 { "save", "", D_save, D_SAVE, do_save,
874         gettext_noop("save filename - save commands from the session to file.") },
875 #endif
876 { "set", "", D_set, D_SET, do_set_var,
877         gettext_noop("set var = value - assign value to a scalar variable.") },
878 { "silent", "", D_silent, D_SILENT, do_commands,
879         gettext_noop("silent - suspends usual message when stopped at a breakpoint/watchpoint.") },
880 { "source", "", D_source, D_SOURCE, do_source,
881         gettext_noop("source file - execute commands from file.") },
882 { "step", "s", D_step, D_STEP, do_step,
883         gettext_noop("step [COUNT] - step program until it reaches a different source line.") },
884 { "stepi", "si", D_stepi, D_STEPI, do_stepi,
885         gettext_noop("stepi [COUNT] - step one instruction exactly.") },
886 { "tbreak", "t", D_tbreak, D_TBREAK, do_tmp_breakpoint,
887         gettext_noop("tbreak [[filename:]N|function] - set a temporary breakpoint.") },
888 { "trace", "", D_trace, D_TRACE, do_trace_instruction,
889         gettext_noop("trace on|off - print instruction before executing.") },
890 { "undisplay",  "", D_undisplay, D_UNDISPLAY, do_undisplay,
891         gettext_noop("undisplay [N] - remove variable(s) from automatic display list.") },
892 { "until", "u", D_until, D_UNTIL, do_until,
893         gettext_noop("until [[filename:]N|function] - execute until program reaches a different line or line N within current frame.") },
894 { "unwatch", "", D_unwatch, D_UNWATCH, do_unwatch,
895         gettext_noop("unwatch [N] - remove variable(s) from watch list.") },
896 { "up", "", D_up, D_UP, do_up,
897         gettext_noop("up [N] - move N frames up the stack.") },
898 { "watch", "w", D_watch, D_WATCH, do_watch,
899         gettext_noop("watch var - set a watchpoint for a variable.") },
900 { NULL, NULL, D_illegal, 0, (Func_cmd) 0,
901          NULL },
902 };
903
904 struct argtoken argtab[] = {
905         { "args", D_info, A_ARGS },
906         { "break", D_info, A_BREAK },
907         { "del", D_enable, A_DEL },
908         { "display", D_info, A_DISPLAY },
909         { "frame", D_info, A_FRAME },
910         { "functions", D_info, A_FUNCTIONS },
911         { "locals", D_info, A_LOCALS },
912         { "off", D_trace, A_TRACE_OFF },
913         { "on", D_trace, A_TRACE_ON },
914         { "once", D_enable, A_ONCE },
915         { "source", D_info, A_SOURCE },
916         { "sources", D_info, A_SOURCES },
917         { "variables", D_info, A_VARIABLES },
918         { "watch", D_info, A_WATCH },
919         { NULL, D_illegal, A_NONE },
920 };
921
922
923 /* get_command --- return command handler function */
924
925 Func_cmd
926 get_command(int ctype)
927 {
928         int i;
929         for (i = 0; cmdtab[i].name != NULL; i++) {
930                 if (cmdtab[i].type == ctype)
931                         return cmdtab[i].cf_ptr;
932         }
933         return (Func_cmd) 0;
934 }
935
936 /* get_command_name --- return command name given it's type */
937
938 const char *
939 get_command_name(int ctype)
940 {
941         int i;
942         for (i = 0; cmdtab[i].name != NULL; i++) {
943                 if (cmdtab[i].type == ctype)
944                         return cmdtab[i].name;
945         }
946         return NULL;
947
948
949 /* mk_cmdarg --- make an argument for command */
950
951 static CMDARG *
952 mk_cmdarg(enum argtype type)
953 {
954         CMDARG *arg;
955         emalloc(arg, CMDARG *, sizeof(CMDARG), "mk_cmdarg");
956         memset(arg, 0, sizeof(CMDARG));
957         arg->type = type;
958         return arg;
959 }
960
961 /* append_cmdarg --- append ARG to the list of arguments for the current command */
962  
963 static void
964 append_cmdarg(CMDARG *arg)
965 {
966         static CMDARG *savetail;
967
968         if (arg_list == NULL)
969                 arg_list = arg;
970         else
971                 savetail->next = arg;
972         savetail = arg;
973 }
974
975 /* free_cmdarg --- free all arguments in LIST */
976
977 void
978 free_cmdarg(CMDARG *list)
979 {
980         CMDARG *arg, *nexta;
981
982         for (arg = list; arg != NULL; arg = nexta) {
983                 nexta = arg->next;
984
985                 switch (arg->type) {
986                 case D_variable:
987                 case D_subscript:
988                 case D_array:
989                 case D_string:
990                         if (arg->a_string != NULL)
991                                 efree(arg->a_string);
992                         break;
993                 case D_node:
994                 case D_field:
995                         unref(arg->a_node);
996                         break;
997                 default:
998                         break;
999                 }
1000                 efree(arg);
1001         }
1002 }
1003
1004 /* yyerror --- print a syntax error message */
1005
1006 static void
1007 yyerror(const char *mesg, ...)
1008 {
1009         va_list args;
1010         va_start(args, mesg);
1011         fprintf(out_fp, _("error: "));
1012         vfprintf(out_fp, mesg, args);
1013         fprintf(out_fp, "\n");
1014         va_end(args);
1015         errcount++;
1016         repeat_idx = -1;
1017 }
1018
1019
1020 /* yylex --- read a command and turn it into tokens */
1021
1022 static int
1023 yylex(void)
1024 {
1025         static char *lexptr = NULL;
1026         static char *lexend;
1027         int c;
1028         char *tokstart;
1029         size_t toklen; 
1030
1031         yylval = (CMDARG *) NULL;
1032
1033         if (errcount > 0 && lexptr_begin == NULL) {
1034                 /* fake a new line */
1035                 errcount = 0;
1036                 return '\n';
1037         }
1038
1039         if (lexptr_begin == NULL) {
1040 again:
1041                 lexptr_begin = read_a_line(dbg_prompt);
1042                 if (lexptr_begin == NULL) {     /* EOF or error */
1043                         if (get_eof_status() == EXIT_FATAL) 
1044                                 exit(EXIT_FATAL);
1045                         if (get_eof_status() == EXIT_FAILURE) {
1046                                 static int seen_eof = 0;
1047
1048                                 /* force a quit, and let do_quit (in debug.c) exit */
1049                                 if (! seen_eof) {
1050                                         if (errno != 0) {
1051                                                 fprintf(stderr, _("can't read command (%s)\n"), strerror(errno));
1052                                                 exit_val = EXIT_FAILURE;
1053                                         } /* else
1054                                                 exit_val = EXIT_SUCCESS; */
1055
1056                                         seen_eof = 1;
1057                                         return '\n';    /* end current command if any */
1058                                 } else if (seen_eof++ == 1) {
1059                                         cmd_idx = find_command("quit", 4);
1060                                         return D_QUIT;  /* 'quit' token */
1061                                 } else
1062                                         return '\n';    /* end command 'quit' */
1063                         }
1064                         if (errno != 0)
1065                                 d_error(_("can't read command (%s)"), strerror(errno));
1066                         if (pop_cmd_src() == 0)
1067                                 goto again;
1068                         exit(EXIT_FATAL);       /* shouldn't happen */
1069                 }
1070
1071                 if (! in_commands && ! in_eval  /* history expansion off in 'commands' and 'eval' */
1072                                 && input_from_tty
1073                 )
1074                         history_expand_line(&lexptr_begin);
1075         
1076                 lexptr = lexptr_begin;
1077                 lexend = lexptr + strlen(lexptr);
1078                 if (*lexptr == '\0'             /* blank line */
1079                                 && repeat_idx >= 0
1080                                 && input_from_tty
1081                                 && ! in_eval
1082                 ) {
1083 #ifdef HAVE_LIBREADLINE
1084                         HIST_ENTRY *h;
1085                         h = previous_history();
1086                         if (h != NULL)
1087                                 add_history(h->line);
1088 #endif
1089                         cmd_idx = repeat_idx;
1090                         return cmdtab[cmd_idx].class;   /* repeat last command */
1091                 }
1092                 repeat_idx = -1;
1093         }
1094         
1095         c = *lexptr;
1096
1097         while (c == ' ' || c == '\t')
1098                 c = *++lexptr;
1099
1100         if (! input_from_tty && c == '#')
1101                 return '\n'; 
1102
1103         tokstart = lexptr;
1104         if (lexptr >= lexend)
1105                 return '\n';
1106
1107         if (cmd_idx < 0) {      /* need a command */
1108                 if (c == '?' && tokstart[1] == '\0'     && ! in_eval) {
1109                         lexptr++;
1110                         cmd_idx = find_command("help", 4);
1111                         return D_HELP;
1112                 }
1113
1114                 while (c != '\0' && c != ' ' && c != '\t') {
1115                         if (! isalpha(c) && ! in_eval) {
1116                                 yyerror(_("invalid character in command"));
1117                                 return '\n';
1118                         }
1119                         c = *++lexptr;
1120                 }
1121
1122                 toklen = lexptr - tokstart;
1123
1124                 if (in_eval) {
1125                         if (toklen == 3
1126                                         && tokstart[3] == '\0'
1127                                         && tokstart[0] == 'e'
1128                                         && tokstart[1] == 'n'
1129                                         && tokstart[2] == 'd'
1130                         ) {
1131                                 cmd_idx = find_command(tokstart, toklen);
1132                                 return D_END;
1133                         }
1134                         lexptr = lexend;
1135                         return D_STATEMENT;
1136                 }
1137
1138                 cmd_idx = find_command(tokstart, toklen);
1139                 if (cmd_idx >= 0) {
1140                         if (in_commands && cmdtab[cmd_idx].type != D_eval) {
1141                                 /* add the actual command string (lexptr_begin) to
1142                                  * arg_list; command string for 'eval' prepended to the arg_list
1143                                  * in the grammer above (see eval_cmd non-terminal).
1144                                  */
1145                                 CMDARG *arg;
1146                                 arg = mk_cmdarg(D_string);
1147                                 arg->a_string = estrdup(lexptr_begin, lexend - lexptr_begin);
1148                                 append_cmdarg(arg);
1149                         }
1150                         return cmdtab[cmd_idx].class;
1151                 } else {
1152                         yyerror(_("unknown command - \"%.*s\", try help"), toklen, tokstart);
1153                         return '\n';
1154                 }
1155         }
1156
1157         c = *lexptr;
1158         
1159         if (cmdtab[cmd_idx].type == D_option) {
1160                 if (c == '=')
1161                         return *lexptr++;
1162         } else if (c == '-' || c == '+' || c == ':' || c == '|')
1163                 return *lexptr++;
1164
1165         if (c == '"') {
1166                 char *str, *p;
1167                 int flags = ALREADY_MALLOCED;
1168                 bool esc_seen = false;
1169
1170                 toklen = lexend - lexptr;
1171                 emalloc(str, char *, toklen + 2, "yylex");
1172                 p = str;
1173
1174                 while ((c = *++lexptr) != '"') {
1175                         if (lexptr == lexend) {
1176 err:
1177                                 efree(str);
1178                                 yyerror(_("unterminated string"));
1179                                 return '\n';
1180                         }
1181                         if (c == '\\') {
1182                                 c = *++lexptr;
1183                                 esc_seen = true;
1184                                 if (want_nodeval || c != '"')
1185                                         *p++ = '\\';
1186                         }
1187                         if (lexptr == lexend)
1188                                 goto err;
1189                         *p++ = c;
1190                 }
1191                 lexptr++;
1192                 *p = '\0';
1193
1194                 if (! want_nodeval) {
1195                         yylval = mk_cmdarg(D_string);
1196                         yylval->a_string = str;
1197                         append_cmdarg(yylval);
1198                         return D_STRING;
1199                 } else {        /* awk string */
1200                         if (esc_seen)
1201                                 flags |= SCAN;
1202                         yylval = mk_cmdarg(D_node);
1203                         yylval->a_node = make_str_node(str, p - str, flags);
1204                         append_cmdarg(yylval);
1205                         return D_NODE;
1206                 }
1207         }
1208
1209         if (! want_nodeval) {
1210                 while ((c = *++lexptr) != '\0' && c != ':' && c != '-'
1211                                         && c != ' ' && c != '\t' && c != '=')
1212                         ;
1213
1214                 /* Is it an integer? */
1215                 if (isdigit((unsigned char) tokstart[0]) && cmdtab[cmd_idx].type != D_option) {
1216                         char *end;
1217                         long l;
1218
1219                         errno = 0;
1220                         l = strtol(tokstart, &end, 0);
1221                         if (errno != 0) {
1222                                 yyerror(_("%s"), strerror(errno));
1223                                 errno = 0;
1224                                 return '\n';
1225                         }
1226
1227                         if (lexptr == end) {
1228                                 yylval = mk_cmdarg(D_int);
1229                                 yylval->a_int = l;
1230                                 append_cmdarg(yylval);
1231                                 return D_INT;
1232                         }
1233                 }
1234
1235                 /* Must be string */
1236                 yylval = mk_cmdarg(D_string);
1237                 yylval->a_string = estrdup(tokstart, lexptr - tokstart);
1238                 append_cmdarg(yylval);
1239                 return D_STRING;
1240         }
1241
1242         /* look for awk number */
1243
1244         if (isdigit((unsigned char) tokstart[0])) {
1245                 NODE *r = NULL;
1246
1247                 errno = 0;
1248 #ifdef HAVE_MPFR
1249                 if (do_mpfr) {
1250                         int tval;
1251                         r = mpg_float();
1252                         tval = mpfr_strtofr(r->mpg_numbr, tokstart, & lexptr, 0, ROUND_MODE);
1253                         IEEE_FMT(r->mpg_numbr, tval);
1254                         if (mpfr_integer_p(r->mpg_numbr)) {
1255                                 /* integral value, convert to a GMP type. */
1256                                 NODE *tmp = r;
1257                                 r = mpg_integer();
1258                                 mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
1259                                 unref(tmp);
1260                         }                       
1261                 } else 
1262 #endif
1263                         r = make_number(strtod(tokstart, & lexptr));
1264
1265                 if (errno != 0) {
1266                         yyerror(strerror(errno));
1267                         unref(r);
1268                         errno = 0;
1269                         return '\n';
1270                 }
1271                 yylval = mk_cmdarg(D_node);
1272                 yylval->a_node = r;
1273                 append_cmdarg(yylval);
1274                 return D_NODE;
1275         }
1276
1277         c = *lexptr;
1278         if (c == '$' || c == '@'
1279                         || c == '[' || c == ']'
1280                         || c == ',' || c == '=')
1281                 return *lexptr++;
1282
1283         if (c != '_' && ! isalpha(c)) {
1284                 yyerror(_("invalid character"));
1285                 return '\n';
1286         }
1287
1288         while (isalnum(c) || c == '_')
1289                 c = *++lexptr;
1290         toklen = lexptr - tokstart;
1291
1292         /* awk variable */
1293         yylval = mk_cmdarg(D_variable);
1294         yylval->a_string = estrdup(tokstart, toklen);
1295         append_cmdarg(yylval);
1296         return D_VARIABLE;
1297 }
1298
1299 /* find_argument --- find index in 'argtab' for a command option */
1300
1301 static int
1302 find_argument(CMDARG *arg)
1303 {
1304         /* non-number argument */
1305         int idx;
1306         char *name, *p;
1307         size_t len;
1308         assert(cmd_idx >= 0);
1309         name = arg->a_string;
1310         len = strlen(name);
1311         for (idx = 0; (p = (char *) argtab[idx].name) != NULL; idx++) {
1312                 if (cmdtab[cmd_idx].type == argtab[idx].cmd
1313                                 && *p == *name
1314                                 && strlen(p) == len
1315                                 && strncmp(p, name, len) == 0
1316                 )
1317                         return idx;
1318         }
1319         return -1;      /* invalid option */
1320 }
1321
1322 /* concat_args --- concatenate argument strings into a single string NODE */
1323
1324 static NODE *
1325 concat_args(CMDARG *arg, int count)
1326 {
1327         NODE *n;
1328         NODE **tmp;
1329         char *str, *subsep, *p;
1330         long len, subseplen;
1331         int i;
1332
1333         if (count == 1) {
1334                 n = force_string(arg->a_node);
1335                 return dupnode(n);
1336         }
1337         
1338         emalloc(tmp, NODE **, count * sizeof(NODE *), "concat_args");
1339         subseplen = SUBSEP_node->var_value->stlen;
1340         subsep = SUBSEP_node->var_value->stptr;
1341         len = -subseplen;
1342
1343         for (i = 0; i < count; i++) {
1344                 n = force_string(arg->a_node);
1345                 len += n->stlen + subseplen;
1346                 tmp[i] = n;
1347                 arg = arg->next;
1348         }
1349
1350         emalloc(str, char *, len + 2, "concat_args");
1351         n = tmp[0];
1352         memcpy(str, n->stptr, n->stlen);
1353         p = str + n->stlen;
1354         for (i = 1; i < count; i++) {
1355                 if (subseplen == 1)
1356                         *p++ = *subsep;
1357                 else if (subseplen > 0) {
1358                         memcpy(p, subsep, subseplen);
1359                         p += subseplen;
1360                 }
1361
1362                 n = tmp[i];
1363                 memcpy(p, n->stptr, n->stlen);
1364                 p += n->stlen;
1365         }
1366         str[len] = '\0';
1367         efree(tmp);
1368         return make_str_node(str, len, ALREADY_MALLOCED);
1369 }
1370
1371 /* find_command --- find the index in 'cmdtab' using exact,
1372  *                  abbreviation or unique partial match 
1373  */
1374
1375 static int
1376 find_command(const char *token, size_t toklen)
1377 {
1378         char *name, *abrv;
1379         int i, k;
1380         bool try_exact = true;
1381         int abrv_match = -1;
1382         int partial_match = -1;
1383
1384 #if 'a' == 0x81 /* it's EBCDIC */
1385         /* make sure all lower case characters in token (sorting
1386          * isn't the solution in this case)
1387          */
1388         for (i = 0; i < toklen; i++) {
1389                 if (token[i] != tolower(token[i]))
1390                         return -1;
1391         }
1392 #endif
1393
1394         k = sizeof(cmdtab)/sizeof(cmdtab[0]) - 1;
1395         for (i = 0; i < k; i++) {
1396                 name = (char *) cmdtab[i].name;
1397                 if (try_exact && *token == *name
1398                                 && toklen == strlen(name)
1399                                 && strncmp(name, token, toklen) == 0
1400                 )
1401                         return i;
1402
1403                 if (*name > *token || i == (k - 1))
1404                         try_exact = false;
1405
1406                 if (abrv_match < 0) {
1407                         abrv = cmdtab[i].abbrvn;
1408                         if (abrv[0] == token[0]) {
1409                                 if (toklen == 1 && ! abrv[1])
1410                                         abrv_match = i;
1411                                 else if (toklen == 2 && abrv[1] == token[1])
1412                                         abrv_match = i;
1413                         }
1414                 }
1415                 if (! try_exact && abrv_match >= 0)
1416                         return abrv_match;
1417                 if (partial_match < 0) {
1418                         if (*token == *name
1419                                         && toklen < strlen(name)
1420                                         && strncmp(name, token, toklen) == 0
1421                         ) {
1422                                 if ((i == k - 1 || strncmp(cmdtab[i + 1].name, token, toklen) != 0)
1423                                         && (i == 0 || strncmp(cmdtab[i - 1].name, token, toklen) != 0)
1424                                 )
1425                                         partial_match = i;
1426                         }
1427                 }
1428         }
1429         return partial_match;
1430 }
1431
1432 /* do_help -- help command */
1433
1434 int
1435 do_help(CMDARG *arg, int cmd)
1436 {
1437         int i;
1438         if (arg == NULL) {
1439                 initialize_pager(out_fp);
1440                 if (setjmp(pager_quit_tag) == 0) {
1441                         for (i = 0; cmdtab[i].name != NULL; i++) {
1442                                 gprintf(out_fp, "%s:\n", cmdtab[i].name);
1443                                 gprintf(out_fp, "\t%s\n", _(cmdtab[i].help_txt));
1444                         }
1445                 }
1446         } else if (arg->type == D_string) {
1447                 char *name;
1448                 name = arg->a_string;
1449                 i = find_command(name, strlen(name));
1450                 if (i >= 0) {
1451                         fprintf(out_fp, "%s\n", cmdtab[i].help_txt);
1452                         if (strcmp(cmdtab[i].name, "option") == 0)
1453                                 option_help();
1454                 } else
1455                         fprintf(out_fp, _("undefined command: %s\n"), name);
1456         }
1457
1458         return false;
1459 }
1460
1461
1462 #ifdef HAVE_LIBREADLINE
1463
1464 /* next_word --- find the next word in a line to complete 
1465  *               (word seperation characters are space and tab).
1466  */
1467    
1468 static char *
1469 next_word(char *p, int len, char **endp)
1470 {
1471         char *q;
1472         int i;
1473
1474         if (p == NULL || len <= 0)
1475                 return NULL;
1476         for (i = 0; i < len; i++, p++)
1477                 if (*p != ' ' && *p != '\t')
1478                         break;
1479         if (i == len)
1480                 return NULL;
1481         if (endp != NULL) {
1482                 for (i++, q = p + 1; i < len; i++, q++)
1483                         if (*q == ' ' || *q == '\t')
1484                                 break;
1485                 *endp = q;
1486         }
1487         return p;
1488 }
1489
1490 /* command_completion --- attempt to complete based on the word number in line;
1491  *    try to complete on command names if this is the first word; for the next
1492  *    word(s), the type of completion depends on the command name (first word).
1493  */
1494
1495 #ifndef RL_READLINE_VERSION             /* < 4.2a */
1496 #define rl_completion_matches(x, y) completion_matches((char *) (x), (y))
1497 #endif
1498
1499
1500 char **
1501 command_completion(const char *text, int start, int end)
1502 {
1503         char *cmdtok, *e;
1504         int idx;
1505         int len;
1506
1507         rl_attempted_completion_over = true;    /* no default filename completion please */
1508
1509         this_cmd = D_illegal;
1510         len = start;
1511         if ((cmdtok = next_word(rl_line_buffer, len, &e)) == NULL)      /* no first word yet */
1512                 return  rl_completion_matches(text, command_generator);
1513         len -= (e - rl_line_buffer);
1514
1515         idx = find_command(cmdtok, e - cmdtok);
1516         if (idx < 0)
1517                 return NULL;
1518         this_cmd = cmdtab[idx].type;
1519
1520         if (! next_word(e, len, NULL)) {
1521                 switch (this_cmd) {
1522                 case D_break:
1523                 case D_list:
1524                 case D_until:
1525                 case D_tbreak:
1526                 case D_clear:
1527                         return rl_completion_matches(text, srcfile_generator);
1528                 case D_info:
1529                 case D_enable:
1530                 case D_trace:
1531                 case D_help:
1532                         return rl_completion_matches(text, argument_generator);
1533                 case D_option:
1534                         return rl_completion_matches(text, option_generator);
1535                 case D_print:
1536                 case D_printf:
1537                 case D_set:
1538                 case D_display:
1539                 case D_watch:
1540                         return rl_completion_matches(text, variable_generator);
1541                 default:
1542                         return NULL;
1543                 }
1544         }
1545
1546         if (this_cmd == D_print || this_cmd == D_printf)
1547                 return rl_completion_matches(text, variable_generator);
1548         return NULL;
1549 }       
1550
1551 /* command_generator --- generator function for command completion */
1552  
1553 static char *
1554 command_generator(const char *text, int state)
1555 {
1556         static size_t textlen;
1557         static int idx = 0;
1558         char *name;
1559
1560         if (! state) {  /* first time */
1561                 textlen = strlen(text);
1562                 idx = 0;
1563         }
1564         while ((name = (char *) cmdtab[idx].name) != NULL) {
1565                 idx++;
1566                 if (strncmp(name, text, textlen) == 0)
1567                         return estrdup(name, strlen(name));
1568         }
1569         return NULL;
1570 }
1571
1572 /* srcfile_generator --- generator function for source file completion */
1573
1574 static char *
1575 srcfile_generator(const char *text, int state)
1576 {
1577         static size_t textlen;
1578         static SRCFILE *s;
1579         char *name;
1580         extern SRCFILE *srcfiles;
1581
1582         if (! state) {  /* first time */
1583                 textlen = strlen(text);
1584                 s = srcfiles->next;
1585         }
1586         while (s != srcfiles) {
1587                 if (s->stype != SRC_FILE && s->stype != SRC_INC) {
1588                         s = s->next;
1589                         continue;
1590                 }
1591                 name = s->src;
1592                 s = s->next;
1593                 if (strncmp(name, text, textlen) == 0)
1594                         return estrdup(name, strlen(name));
1595         }
1596         return NULL;
1597 }
1598
1599 /* argument_generator --- generator function for non-number argument completion */
1600
1601 static char *
1602 argument_generator(const char *text, int state)
1603 {
1604         static size_t textlen;
1605         static int idx;
1606         const char *name;
1607
1608         if (! state) {  /* first time */
1609                 textlen = strlen(text);
1610                 idx = 0;
1611         }
1612
1613         if (this_cmd == D_help) {
1614                 while ((name = cmdtab[idx++].name) != NULL) {
1615                         if (strncmp(name, text, textlen) == 0)
1616                                 return estrdup(name, strlen(name));
1617                 }
1618         } else {
1619                 while ((name = argtab[idx].name) != NULL) {
1620                         if (this_cmd != argtab[idx++].cmd)
1621                                 continue;
1622                         if (strncmp(name, text, textlen) == 0)
1623                                 return estrdup(name, strlen(name));
1624                 }
1625         }               
1626         return NULL;
1627 }
1628
1629 /* variable_generator --- generator function for variable name completion */
1630
1631 static char *
1632 variable_generator(const char *text, int state)
1633 {
1634         static size_t textlen;
1635         static int idx = 0;
1636         static NODE *func = NULL;
1637         static NODE **vars = NULL;
1638         const char *name;
1639         NODE *r;
1640
1641         if (! state) {  /* first time */
1642                 textlen = strlen(text);
1643                 if (vars != NULL)
1644                         efree(vars);
1645                 vars = variable_list();
1646                 idx = 0;
1647                 func = get_function();  /* function in current context */
1648         }
1649
1650         /* function params */
1651         while (func != NULL) {
1652                 if (idx >= func->param_cnt) {
1653                         func = NULL;    /* don't try to match params again */
1654                         idx = 0;
1655                         break;
1656                 }
1657                 name = func->fparms[idx++].param;
1658                 if (strncmp(name, text, textlen) == 0)
1659                         return estrdup(name, strlen(name));
1660         }
1661
1662         /* globals */
1663         while ((r = vars[idx++]) != NULL) {
1664                 name = r->vname;
1665                 if (strncmp(name, text, textlen) == 0)
1666                         return estrdup(name, strlen(name));
1667         }
1668
1669         return NULL;
1670 }
1671
1672 /* history_expand_line ---  history expand the LINE */
1673
1674 static void
1675 history_expand_line(char **line)
1676 {
1677         int ret;
1678         char *expansion;
1679
1680         if (! *line || input_fd != 0 || ! input_from_tty)
1681                 return;
1682         using_history();
1683         ret = history_expand(*line, &expansion);
1684         if (ret < 0 || ret == 2)
1685                 efree(expansion);
1686         else {
1687                 efree(*line);
1688                 *line = expansion;
1689         }
1690 }
1691
1692 #endif