summaryrefslogtreecommitdiffabout
path: root/src
Unidiff
Diffstat (limited to 'src') (more/less context) (ignore whitespace changes)
-rw-r--r--src/Makefile.am12
-rw-r--r--src/gdbmtool.c102
-rw-r--r--src/gdbmtool.h31
-rw-r--r--src/gram.y7
-rw-r--r--src/input-rl.c235
-rw-r--r--src/input-std.c43
-rw-r--r--src/lex.l134
7 files changed, 483 insertions, 81 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 6a05634..b55deb6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -79,7 +79,11 @@ libgdbmapp_a_SOURCES =\
79# Programs 79# Programs
80bin_PROGRAMS = gdbmtool gdbm_load gdbm_dump 80bin_PROGRAMS = gdbmtool gdbm_load gdbm_dump
81 81
82gdbmtool_LDADD = ./libgdbmapp.a ./libgdbm.la 82gdbmtool_LDADD = \
83 ./libgdbmapp.a\
84 ./libgdbm.la\
85 @READLINE_LIBS@
86
83gdbmtool_SOURCES = \ 87gdbmtool_SOURCES = \
84 datconv.c\ 88 datconv.c\
85 gram.y\ 89 gram.y\
@@ -89,6 +93,12 @@ gdbmtool_SOURCES = \
89 var.c\ 93 var.c\
90 util.c 94 util.c
91 95
96if GDBM_COND_READLINE
97 gdbmtool_SOURCES += input-rl.c
98else
99 gdbmtool_SOURCES += input-std.c
100endif
101
92AM_YFLAGS = -dtv 102AM_YFLAGS = -dtv
93#AM_LFLAGS = -d 103#AM_LFLAGS = -d
94 104
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index 65b6740..2d57cbc 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -323,20 +323,6 @@ get_screen_lines ()
323#endif 323#endif
324 return -1; 324 return -1;
325} 325}
326
327
328#define ARG_UNUSED __attribute__ ((__unused__))
329
330#define NARGS 5
331
332struct handler_param
333{
334 int argc;
335 struct gdbmarg **argv;
336 FILE *fp;
337 void *data;
338};
339
340 326
341/* Open database */ 327/* Open database */
342void 328void
@@ -751,7 +737,7 @@ quit_handler (struct handler_param *param ARG_UNUSED)
751{ 737{
752 if (gdbm_file != NULL) 738 if (gdbm_file != NULL)
753 gdbm_close (gdbm_file); 739 gdbm_close (gdbm_file);
754 740 input_done ();
755 exit (EXIT_OK); 741 exit (EXIT_OK);
756} 742}
757 743
@@ -891,6 +877,8 @@ struct argdef
891 int ds; 877 int ds;
892}; 878};
893 879
880#define NARGS 5
881
894struct command 882struct command
895{ 883{
896 char *name; /* Command name */ 884 char *name; /* Command name */
@@ -902,7 +890,6 @@ struct command
902 struct argdef args[NARGS]; 890 struct argdef args[NARGS];
903 char *doc; 891 char *doc;
904}; 892};
905
906 893
907struct command command_tab[] = { 894struct command command_tab[] = {
908#define S(s) #s, sizeof (#s) - 1 895#define S(s) #s, sizeof (#s) - 1
@@ -1007,6 +994,13 @@ struct command command_tab[] = {
1007 NULL, open_handler, NULL, 994 NULL, open_handler, NULL,
1008 { { "FILE", GDBM_ARG_STRING }, { NULL } }, 995 { { "FILE", GDBM_ARG_STRING }, { NULL } },
1009 N_("open new database") }, 996 N_("open new database") },
997#ifdef WITH_READLINE
998 { S(history), T_CMD,
999 input_history_begin, input_history_handler, NULL,
1000 { { N_("[FROM]"), GDBM_ARG_STRING },
1001 { N_("[COUNT]"), GDBM_ARG_STRING },
1002 { NULL } }, N_("show input history") },
1003#endif
1010#undef S 1004#undef S
1011 { 0 } 1005 { 0 }
1012}; 1006};
@@ -1026,6 +1020,39 @@ sort_commands ()
1026 sizeof (command_tab[0]), cmdcmp); 1020 sizeof (command_tab[0]), cmdcmp);
1027} 1021}
1028 1022
1023/* Generator function for command completion. STATE lets us know whether
1024 to start from scratch; without any state (i.e. STATE == 0), then we
1025 start at the top of the list. */
1026char *
1027command_generator (const char *text, int state)
1028{
1029 const char *name;
1030 static int len;
1031 static struct command *cmd;
1032
1033 /* If this is a new word to complete, initialize now. This includes
1034 saving the length of TEXT for efficiency, and initializing the index
1035 variable to 0. */
1036 if (!state)
1037 {
1038 cmd = command_tab;
1039 len = strlen (text);
1040 }
1041
1042 if (!cmd->name)
1043 return NULL;
1044
1045 /* Return the next name which partially matches from the command list. */
1046 while ((name = cmd->name))
1047 {
1048 cmd++;
1049 if (strncmp (name, text, len) == 0)
1050 return strdup (name);
1051 }
1052
1053 /* If no names matched, then return NULL. */
1054 return NULL;
1055}
1029 1056
1030/* ? - help handler */ 1057/* ? - help handler */
1031#define CMDCOLS 30 1058#define CMDCOLS 30
@@ -1174,7 +1201,7 @@ gdbmarg_kvpair (struct kvpair *kvp, struct locus *loc)
1174} 1201}
1175 1202
1176struct slist * 1203struct slist *
1177slist_new (char *s) 1204slist_new_s (char *s)
1178{ 1205{
1179 struct slist *lp = emalloc (sizeof (*lp)); 1206 struct slist *lp = emalloc (sizeof (*lp));
1180 lp->next = NULL; 1207 lp->next = NULL;
@@ -1182,6 +1209,21 @@ slist_new (char *s)
1182 return lp; 1209 return lp;
1183} 1210}
1184 1211
1212struct slist *
1213slist_new (char const *s)
1214{
1215 return slist_new_s (estrdup (s));
1216}
1217
1218struct slist *
1219slist_new_l (char const *s, size_t l)
1220{
1221 char *copy = emalloc (l + 1);
1222 memcpy (copy, s, l);
1223 copy[l] = 0;
1224 return slist_new_s (copy);
1225}
1226
1185void 1227void
1186slist_free (struct slist *lp) 1228slist_free (struct slist *lp)
1187{ 1229{
@@ -1193,6 +1235,21 @@ slist_free (struct slist *lp)
1193 lp = next; 1235 lp = next;
1194 } 1236 }
1195} 1237}
1238
1239void
1240slist_insert (struct slist **where, struct slist *what)
1241{
1242 if (*where)
1243 {
1244 while (what->next)
1245 what = what->next;
1246 what->next = (*where)->next;
1247 (*where)->next = what;
1248 }
1249 else
1250 what->next = NULL;
1251 *where = what;
1252}
1196 1253
1197struct kvpair * 1254struct kvpair *
1198kvpair_string (struct locus *loc, char *val) 1255kvpair_string (struct locus *loc, char *val)
@@ -1216,7 +1273,6 @@ kvpair_list (struct locus *loc, struct slist *s)
1216 return p; 1273 return p;
1217} 1274}
1218 1275
1219
1220static void 1276static void
1221kvlist_free (struct kvpair *kvp) 1277kvlist_free (struct kvpair *kvp)
1222{ 1278{
@@ -1534,6 +1590,7 @@ main (int argc, char *argv[])
1534 int opt; 1590 int opt;
1535 int bv; 1591 int bv;
1536 int norc = 0; 1592 int norc = 0;
1593 int res;
1537 char *source = "-"; 1594 char *source = "-";
1538 1595
1539 set_progname (argv[0]); 1596 set_progname (argv[0]);
@@ -1545,15 +1602,18 @@ main (int argc, char *argv[])
1545 textdomain (PACKAGE); 1602 textdomain (PACKAGE);
1546 1603
1547 sort_commands (); 1604 sort_commands ();
1548 1605
1549 /* Initialize variables. */ 1606 /* Initialize variables. */
1550 intr = isatty (0); 1607 intr = isatty (0);
1608 interactive = intr; /* Used early by input_init */
1551 dsdef[DS_KEY] = dsegm_new_field (datadef_lookup ("string"), NULL, 1); 1609 dsdef[DS_KEY] = dsegm_new_field (datadef_lookup ("string"), NULL, 1);
1552 dsdef[DS_CONTENT] = dsegm_new_field (datadef_lookup ("string"), NULL, 1); 1610 dsdef[DS_CONTENT] = dsegm_new_field (datadef_lookup ("string"), NULL, 1);
1553 1611
1554 variable_set ("open", VART_STRING, "wrcreat"); 1612 variable_set ("open", VART_STRING, "wrcreat");
1555 variable_set ("pager", VART_STRING, getenv ("PAGER")); 1613 variable_set ("pager", VART_STRING, getenv ("PAGER"));
1556 1614
1615 input_init ();
1616
1557 for (opt = parseopt_first (argc, argv, optab); 1617 for (opt = parseopt_first (argc, argv, optab);
1558 opt != EOF; 1618 opt != EOF;
1559 opt = parseopt_next ()) 1619 opt = parseopt_next ())
@@ -1640,5 +1700,7 @@ main (int argc, char *argv[])
1640 1700
1641 if (setsource (source, intr)) 1701 if (setsource (source, intr))
1642 exit (EXIT_FATAL); 1702 exit (EXIT_FATAL);
1643 return yyparse (); 1703 res = yyparse ();
1704 input_done ();
1705 return res;
1644} 1706}
diff --git a/src/gdbmtool.h b/src/gdbmtool.h
index 84f1409..d0e9aa0 100644
--- a/src/gdbmtool.h
+++ b/src/gdbmtool.h
@@ -24,6 +24,8 @@
24#include <stdarg.h> 24#include <stdarg.h>
25#include <ctype.h> 25#include <ctype.h>
26 26
27#define ARG_UNUSED __attribute__ ((__unused__))
28
27/* Position in input file */ 29/* Position in input file */
28struct point 30struct point
29{ 31{
@@ -94,7 +96,7 @@ void lerror (struct locus *loc, const char *fmt, ...);
94 96
95void terror (const char *fmt, ...); 97void terror (const char *fmt, ...);
96 98
97void print_prompt (void); 99char *make_prompt (void);
98 100
99int setsource (const char *filename, int intr); 101int setsource (const char *filename, int intr);
100 102
@@ -104,6 +106,17 @@ extern int open_mode;
104 106
105#define GDBMTOOLRC ".gdbmtoolrc" 107#define GDBMTOOLRC ".gdbmtoolrc"
106#define GDBMTOOL_DEFFILE "junk.gdbm" 108#define GDBMTOOL_DEFFILE "junk.gdbm"
109
110ssize_t input_read (FILE *fp, char *buf, size_t size);
111void input_init (void);
112void input_done (void);
113
114struct handler_param;
115void input_history_handler (struct handler_param *param);
116int input_history_begin (struct handler_param *param, size_t *exp_count);
117
118void print_prompt_at_bol (void);
119char *command_generator (const char *text, int state);
107 120
108 121
109struct slist 122struct slist
@@ -112,8 +125,11 @@ struct slist
112 char *str; 125 char *str;
113}; 126};
114 127
115struct slist *slist_new (char *s); 128struct slist *slist_new (char const *s);
129struct slist *slist_new_s (char *s);
130struct slist *slist_new_l (char const *s, size_t l);
116void slist_free (struct slist *); 131void slist_free (struct slist *);
132void slist_insert (struct slist **where, struct slist *what);
117 133
118#define KV_STRING 0 134#define KV_STRING 0
119#define KV_LIST 1 135#define KV_LIST 1
@@ -161,6 +177,14 @@ struct gdbmarglist
161 struct gdbmarg *head, *tail; 177 struct gdbmarg *head, *tail;
162}; 178};
163 179
180struct handler_param
181{
182 int argc;
183 struct gdbmarg **argv;
184 FILE *fp;
185 void *data;
186};
187
164void gdbmarglist_init (struct gdbmarglist *, struct gdbmarg *); 188void gdbmarglist_init (struct gdbmarglist *, struct gdbmarg *);
165void gdbmarglist_add (struct gdbmarglist *, struct gdbmarg *); 189void gdbmarglist_add (struct gdbmarglist *, struct gdbmarg *);
166void gdbmarglist_free (struct gdbmarglist *lst); 190void gdbmarglist_free (struct gdbmarglist *lst);
@@ -262,3 +286,6 @@ char *mkfilename (const char *dir, const char *file, const char *suf);
262char *tildexpand (char *s); 286char *tildexpand (char *s);
263int vgetyn (const char *prompt, va_list ap); 287int vgetyn (const char *prompt, va_list ap);
264int getyn (const char *prompt, ...); 288int getyn (const char *prompt, ...);
289
290int getnum (int *pnum, char *arg, char **endp);
291int get_screen_lines (void);
diff --git a/src/gram.y b/src/gram.y
index 9a6e3c2..2f6d7c0 100644
--- a/src/gram.y
+++ b/src/gram.y
@@ -168,13 +168,12 @@ value : string
168 168
169slist : string 169slist : string
170 { 170 {
171 $$.head = $$.tail = slist_new ($1); 171 $$.head = $$.tail = slist_new_s ($1);
172 } 172 }
173 | slist ',' string 173 | slist ',' string
174 { 174 {
175 struct slist *s = slist_new ($3); 175 struct slist *s = slist_new_s ($3);
176 $1.tail->next = s; 176 slist_insert (&$1.tail, s);
177 $1.tail = s;
178 $$ = $1; 177 $$ = $1;
179 } 178 }
180 ; 179 ;
diff --git a/src/input-rl.c b/src/input-rl.c
new file mode 100644
index 0000000..f435ed4
--- a/dev/null
+++ b/src/input-rl.c
@@ -0,0 +1,235 @@
1/* This file is part of GDBM, the GNU data base manager.
2 Copyright (C) 2016 Free Software Foundation, Inc.
3
4 GDBM is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GDBM is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
16
17#include "gdbmtool.h"
18#include <readline/readline.h>
19#include <readline/history.h>
20
21static char *pre_input_line;
22
23static int
24pre_input (void)
25{
26 if (pre_input_line)
27 {
28 rl_insert_text (pre_input_line);
29 free (pre_input_line);
30 pre_input_line = NULL;
31 rl_redisplay ();
32 }
33 return 0;
34}
35
36static int
37retrieve_history (char *str)
38{
39 char *out;
40 int rc;
41
42 rc = history_expand (str, &out);
43 switch (rc)
44 {
45 case -1:
46 yyerror (out);
47 free (out);
48 return 1;
49
50 case 0:
51 break;
52
53 case 1:
54 pre_input_line = out;
55 return 1;
56
57 case 2:
58 printf ("%s\n", out);
59 free (out);
60 return 1;
61 }
62 return 0;
63}
64
65ssize_t
66input_read (FILE *fp, char *buf, size_t size)
67{
68 static char *input_line;
69 static size_t input_length;
70 static size_t input_off;
71#define input_ptr() (input_line + input_off)
72#define input_size() (input_length - input_off)
73
74 if (interactive)
75 {
76 size_t len = input_size ();
77 if (!len)
78 {
79 if (input_line)
80 {
81 newline:
82 free (input_line);
83 input_line = NULL;
84 buf[0] = '\n';
85 return 1;
86 }
87 else
88 {
89 char *prompt;
90 again:
91 prompt = make_prompt ();
92 input_line = readline (prompt);
93 free (prompt);
94 if (!input_line)
95 return 0;
96 input_length = strlen (input_line);
97 input_off = 0;
98 if (input_length)
99 {
100 if (retrieve_history (input_line))
101 {
102 free (input_line);
103 goto again;
104 }
105 }
106 else
107 goto newline;
108 len = input_size ();
109 add_history (input_line);
110 }
111 }
112
113 if (len > size)
114 len = size;
115 memcpy (buf, input_ptr (), len);
116 input_off += len;
117
118 return len;
119 }
120 return fread (buf, 1, size, fp);
121}
122
123struct history_param
124{
125 int from;
126 int count;
127};
128
129int
130input_history_begin (struct handler_param *param, size_t *exp_count)
131{
132 struct history_param *p;
133 int from = 0, count = history_length;
134
135 switch (param->argc)
136 {
137 case 1:
138 if (getnum (&count, param->argv[0]->v.string, NULL))
139 return 1;
140 if (count > history_length)
141 count = history_length;
142 else
143 from = history_length - count;
144 break;
145
146 case 2:
147 if (getnum (&from, param->argv[0]->v.string, NULL))
148 return 1;
149 if (from)
150 --from;
151 if (getnum (&count, param->argv[1]->v.string, NULL))
152 return 1;
153
154 if (count > history_length)
155 count = history_length;
156 }
157 p = emalloc (sizeof *p);
158 p->from = from;
159 p->count = count;
160 param->data = p;
161 if (exp_count)
162 *exp_count = count;
163 return 0;
164}
165
166void
167input_history_handler (struct handler_param *param)
168{
169 struct history_param *p = param->data;
170 int i;
171 HIST_ENTRY **hlist;
172 FILE *fp = param->fp;
173
174 hlist = history_list ();
175 for (i = 0; i < p->count; i++)
176 fprintf (fp, "%4d) %s\n", p->from + i + 1, hlist[p->from + i]->line);
177}
178
179#define HISTFILE_PREFIX "~/."
180#define HISTFILE_SUFFIX "_history"
181
182static char *
183get_history_file_name ()
184{
185 static char *filename = NULL;
186
187 if (!filename)
188 {
189 char *hname;
190
191 hname = emalloc (sizeof HISTFILE_PREFIX + strlen (rl_readline_name) +
192 sizeof HISTFILE_SUFFIX - 1);
193 strcpy (hname, HISTFILE_PREFIX);
194 strcat (hname, rl_readline_name);
195 strcat (hname, HISTFILE_SUFFIX);
196 filename = tildexpand (hname);
197 free (hname);
198 }
199 return filename;
200}
201
202static char **
203shell_completion (const char *text, int start, int end)
204{
205 char **matches;
206
207 matches = (char **) NULL;
208
209 /* If this word is at the start of the line, then it is a command
210 to complete. Otherwise it is the name of a file in the current
211 directory. */
212 if (start == 0)
213 matches = rl_completion_matches (text, command_generator);
214
215 return (matches);
216}
217
218void
219input_init (void)
220{
221 /* Allow conditional parsing of the ~/.inputrc file. */
222 rl_readline_name = (char *) progname;
223 rl_attempted_completion_function = shell_completion;
224 rl_pre_input_hook = pre_input;
225 if (interactive)
226 read_history (get_history_file_name ());
227}
228
229void
230input_done (void)
231{
232 if (interactive)
233 write_history (get_history_file_name ());
234}
235
diff --git a/src/input-std.c b/src/input-std.c
new file mode 100644
index 0000000..4508368
--- a/dev/null
+++ b/src/input-std.c
@@ -0,0 +1,43 @@
1/* This file is part of GDBM, the GNU data base manager.
2 Copyright (C) 2016 Free Software Foundation, Inc.
3
4 GDBM is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GDBM is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
16
17#include "gdbmtool.h"
18
19ssize_t
20input_read (FILE *fp, char *buf, size_t size)
21{
22 if (interactive)
23 {
24 print_prompt_at_bol ();
25 if (fgets (buf, size, fp) == NULL)
26 return 0;
27 return strlen (buf);
28 }
29 return fread (buf, 1, size, fp);
30}
31
32void
33input_init (void)
34{
35 /* nothing */
36}
37
38void
39input_done (void)
40{
41 /* nothing */
42}
43
diff --git a/src/lex.l b/src/lex.l
index 9c2c5f8..236474d 100644
--- a/src/lex.l
+++ b/src/lex.l
@@ -46,7 +46,7 @@ advance_line ()
46#define YY_INPUT(buf,result,max_size) \ 46#define YY_INPUT(buf,result,max_size) \
47 do \ 47 do \
48 { \ 48 { \
49 result = read_input (buf, max_size); \ 49 result = input_read (yyin, buf, max_size); \
50 } \ 50 } \
51 while (0); 51 while (0);
52 52
@@ -56,8 +56,6 @@ void string_addc (int c);
56char *string_end (void); 56char *string_end (void);
57int unescape (int c); 57int unescape (int c);
58 58
59static ssize_t read_input (char *buf, size_t size);
60
61struct context /* Input context */ 59struct context /* Input context */
62{ 60{
63 struct context *parent; /* Pointer to the parent context */ 61 struct context *parent; /* Pointer to the parent context */
@@ -315,18 +313,16 @@ end_def (void)
315 BEGIN (INITIAL); 313 BEGIN (INITIAL);
316} 314}
317 315
318static ssize_t 316void
319read_input (char *buf, size_t size) 317print_prompt_at_bol (void)
320{ 318{
321 if (interactive) 319 if (YY_AT_BOL ())
322 { 320 {
323 if (YY_AT_BOL ()) 321 char *s = make_prompt ();
324 print_prompt (); 322 fputs (s, stdout);
325 if (fgets (buf, size, yyin) == NULL) 323 fflush (stdout);
326 return 0; 324 free (s);
327 return strlen (buf);
328 } 325 }
329 return fread (buf, 1, size, yyin);
330} 326}
331 327
332 328
@@ -453,44 +449,40 @@ lerror (struct locus *loc, const char *fmt, ...)
453} 449}
454 450
455 451
456struct prompt_exp; 452static struct slist *
457 453pe_file_name (void)
458void
459pe_file_name (struct prompt_exp *p)
460{ 454{
461 if (file_name) 455 return file_name ? slist_new (file_name) : NULL;
462 fwrite (file_name, strlen (file_name), 1, stdout);
463} 456}
464 457
465void 458static struct slist *
466pe_program_name (struct prompt_exp *p) 459pe_program_name (void)
467{ 460{
468 fwrite (progname, strlen (progname), 1, stdout); 461 return slist_new (progname);
469} 462}
470 463
471void 464static struct slist *
472pe_package_name (struct prompt_exp *p) 465pe_package_name (void)
473{ 466{
474 fwrite (PACKAGE_NAME, sizeof (PACKAGE_NAME) - 1, 1, stdout); 467 return slist_new (PACKAGE_NAME);
475} 468}
476 469
477void 470static struct slist *
478pe_program_version (struct prompt_exp *p) 471pe_program_version (void)
479{ 472{
480 fwrite (PACKAGE_VERSION, sizeof (PACKAGE_VERSION) - 1, 1, stdout); 473 return slist_new (PACKAGE_VERSION);
481} 474}
482 475
483void 476static struct slist *
484pe_space (struct prompt_exp *p) 477pe_space (void)
485{ 478{
486 fwrite (" ", 1, 1, stdout); 479 return slist_new (" ");
487} 480}
488 481
489struct prompt_exp 482struct prompt_exp
490{ 483{
491 int ch; 484 int ch;
492 void (*fun) (struct prompt_exp *); 485 struct slist *(*fun) (void);
493 char *cache;
494}; 486};
495 487
496struct prompt_exp prompt_exp[] = { 488struct prompt_exp prompt_exp[] = {
@@ -502,8 +494,8 @@ struct prompt_exp prompt_exp[] = {
502 { 0 } 494 { 0 }
503}; 495};
504 496
505static void 497static int
506expand_char (int c) 498expand_char (int c, struct slist **tailp)
507{ 499{
508 struct prompt_exp *p; 500 struct prompt_exp *p;
509 501
@@ -513,58 +505,92 @@ expand_char (int c)
513 { 505 {
514 if (c == p->ch) 506 if (c == p->ch)
515 { 507 {
516 if (p->cache) 508 struct slist *s = p->fun ();
517 free (p->cache); 509 if (s)
518 p->fun (p); 510 slist_insert (tailp, s);
519 return; 511 return 0;
520 } 512 }
521 } 513 }
522 } 514 }
523 putchar ('%'); 515 return 1;
524 putchar (c);
525} 516}
526 517
527char const * 518char const *
528psname () 519psname (void)
529{ 520{
530 if (YYSTATE == DEF || YYSTATE == MLSTR) 521 if (YYSTATE == DEF || YYSTATE == MLSTR)
531 return "ps2"; 522 return "ps2";
532 return "ps1"; 523 return "ps1";
533} 524}
534 525
535void 526char *
536print_prompt () 527make_prompt (void)
537{ 528{
538 const char *s; 529 const char *s;
539 const char *prompt; 530 const char *prompt;
540 531 struct slist *head = NULL, *tail = NULL, *p;
532 char *ret, *end;
533 size_t len;
534
541 switch (variable_get (psname (), VART_STRING, (void *) &prompt)) 535 switch (variable_get (psname (), VART_STRING, (void *) &prompt))
542 { 536 {
543 case VAR_OK: 537 case VAR_OK:
544 break; 538 break;
545 539
546 case VAR_ERR_NOTSET: 540 case VAR_ERR_NOTSET:
547 return; 541 return NULL;
548 542
549 default: 543 default:
550 abort (); 544 abort ();
551 } 545 }
552 546
553 for (s = prompt; *s; s++) 547 for (s = prompt; *s; )
554 { 548 {
555 if (*s == '%') 549 if (*s == '%' && s[1])
556 { 550 {
557 if (!*++s) 551 if (s > prompt)
552 {
553 slist_insert (&tail, slist_new_l (prompt, s - prompt));
554 if (!head)
555 head = tail;
556 }
557 if (expand_char (s[1], &tail) == 0)
558 { 558 {
559 putchar ('%'); 559 if (!head)
560 break; 560 head = tail;
561 prompt = s + 2;
561 } 562 }
562 expand_char (*s); 563 else
564 prompt = s;
565 s += 2;
563 } 566 }
564 else 567 else
565 putchar (*s); 568 ++s;
569 }
570
571 if (s > prompt)
572 {
573 slist_insert (&tail, slist_new_l (prompt, s - prompt));
574 if (!head)
575 head = tail;
566 } 576 }
567 577
568 fflush (stdout); 578 len = 0;
579 for (p = head; p; p = p->next)
580 len += strlen (p->str);
581
582 ret = emalloc (len + 1);
583 end = ret;
584 for (p = head; p; p = p->next)
585 {
586 s = p->str;
587 while (*s)
588 *end++ = *s++;
589 }
590 *end = 0;
591
592 slist_free (head);
593
594 return ret;
569} 595}
570 596

Return to:

Send suggestions and report system problems to the System administrator.