|
|
1.1 root 1: /* Library for reading command lines and decoding commands.
2: Copyright (C) 1986 Free Software Foundation, Inc.
3:
4: NO WARRANTY
5:
6: BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
7: NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
8: WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
9: RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
10: WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
11: BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
12: FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
13: AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
14: DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
15: CORRECTION.
16:
17: IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
18: STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
19: WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
20: LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
21: OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
22: USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
23: DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
24: A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
25: PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
26: DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
27:
28: GENERAL PUBLIC LICENSE TO COPY
29:
30: 1. You may copy and distribute verbatim copies of this source file
31: as you receive it, in any medium, provided that you conspicuously and
32: appropriately publish on each copy a valid copyright notice "Copyright
33: (C) 1986 Free Software Foundation, Inc."; and include following the
34: copyright notice a verbatim copy of the above disclaimer of warranty
35: and of this License. You may charge a distribution fee for the
36: physical act of transferring a copy.
37:
38: 2. You may modify your copy or copies of this source file or
39: any portion of it, and copy and distribute such modifications under
40: the terms of Paragraph 1 above, provided that you also do the following:
41:
42: a) cause the modified files to carry prominent notices stating
43: that you changed the files and the date of any change; and
44:
45: b) cause the whole of any work that you distribute or publish,
46: that in whole or in part contains or is a derivative of this
47: program or any part thereof, to be licensed at no charge to all
48: third parties on terms identical to those contained in this
49: License Agreement (except that you may choose to grant more extensive
50: warranty protection to some or all third parties, at your option).
51:
52: c) You may charge a distribution fee for the physical act of
53: transferring a copy, and you may at your option offer warranty
54: protection in exchange for a fee.
55:
56: Mere aggregation of another unrelated program with this program (or its
57: derivative) on a volume of a storage or distribution medium does not bring
58: the other program under the scope of these terms.
59:
60: 3. You may copy and distribute this program (or a portion or derivative
61: of it, under Paragraph 2) in object code or executable form under the terms
62: of Paragraphs 1 and 2 above provided that you also do one of the following:
63:
64: a) accompany it with the complete corresponding machine-readable
65: source code, which must be distributed under the terms of
66: Paragraphs 1 and 2 above; or,
67:
68: b) accompany it with a written offer, valid for at least three
69: years, to give any third party free (except for a nominal
70: shipping charge) a complete machine-readable copy of the
71: corresponding source code, to be distributed under the terms of
72: Paragraphs 1 and 2 above; or,
73:
74: c) accompany it with the information you received as to where the
75: corresponding source code may be obtained. (This alternative is
76: allowed only for noncommercial distribution and only if you
77: received the program in object code or executable form alone.)
78:
79: For an executable file, complete source code means all the source code for
80: all modules it contains; but, as a special exception, it need not include
81: source code for modules which are standard libraries that accompany the
82: operating system on which the executable file runs.
83:
84: 4. You may not copy, sublicense, distribute or transfer this program
85: except as expressly provided under this License Agreement. Any attempt
86: otherwise to copy, sublicense, distribute or transfer this program is void and
87: your rights to use the program under this License agreement shall be
88: automatically terminated. However, parties who have received computer
89: software programs from you with this License Agreement will not have
90: their licenses terminated so long as such parties remain in full compliance.
91:
92: 5. If you wish to incorporate parts of this program into other free
93: programs whose distribution conditions are different, write to the Free
94: Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
95: worked out a simple rule that can be stated here, but we will often permit
96: this. We will be guided by the two goals of preserving the free status of
97: all derivatives of our free software and of promoting the sharing and reuse of
98: software.
99:
100:
101: In other words, you are welcome to use, share and improve this program.
102: You are forbidden to forbid anyone else to use, share and improve
103: what you give them. Help stamp out software-hoarding! */
104:
105:
106: #include "command.h"
107: #include <stdio.h>
108:
109: extern char *xmalloc ();
110:
111: static char *savestring ();
112:
113: /* Add element named NAME to command list *LIST.
114: FUN should be the function to execute the command;
115: it will get a character string as argument, with leading
116: and trailing blanks already eliminated.
117:
118: DOC is a documentation string for the command.
119: Its first line should be a complete sentence.
120: It should start with ? for a command that is an abbreviation
121: or with * for a command that most users don't need to know about. */
122:
123: struct cmd_list_element *
124: add_cmd (name, class, fun, doc, list)
125: char *name;
126: int class;
127: void (*fun) ();
128: char *doc;
129: struct cmd_list_element **list;
130: {
131: register struct cmd_list_element *c
132: = (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element));
133:
134: delete_cmd (name, list);
135: c->next = *list;
136: c->name = savestring (name, strlen (name));
137: c->class = class;
138: c->function = fun;
139: c->doc = doc;
140: c->prefixlist = 0;
141: c->allow_unknown = 0;
142: c->abbrev_flag = 0;
143: c->aux = 0;
144: *list = c;
145: return c;
146: }
147:
148: struct cmd_list_element *
149: add_alias_cmd (name, oldname, class, abbrev_flag, list)
150: char *name;
151: char *oldname;
152: int class;
153: int abbrev_flag;
154: struct cmd_list_element **list;
155: {
156: /* Must do this since lookup_cmd tries to side-effect its first arg */
157: char *copied_name;
158: register struct cmd_list_element *old;
159: register struct cmd_list_element *c;
160: copied_name = (char *) alloca (strlen (oldname) + 1);
161: strcpy (copied_name, oldname);
162: old = lookup_cmd (&copied_name, *list, 0, 1);
163:
164: if (old == 0)
165: {
166: delete_cmd (name, list);
167: return 0;
168: }
169:
170: c = add_cmd (name, class, old->function, old->doc, list);
171: c->prefixlist = old->prefixlist;
172: c->prefixname = old->prefixname;
173: c->allow_unknown = old->allow_unknown;
174: c->abbrev_flag = abbrev_flag;
175: c->aux = old->aux;
176: return c;
177: }
178:
179: /* Like add_prefix_cmd but adds an element for a command prefix:
180: a name that should be followed by a subcommand to be looked up
181: in another command list. PREFIXLIST should be the address
182: of the variable containing that list. */
183:
184: struct cmd_list_element *
185: add_prefix_cmd (name, class, fun, doc, prefixlist, prefixname,
186: allow_unknown, list)
187: char *name;
188: int class;
189: void (*fun) ();
190: char *doc;
191: struct cmd_list_element **prefixlist;
192: char *prefixname;
193: int allow_unknown;
194: struct cmd_list_element **list;
195: {
196: register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list);
197: c->prefixlist = prefixlist;
198: c->prefixname = prefixname;
199: c->allow_unknown = allow_unknown;
200: return c;
201: }
202:
203: /* Remove the command named NAME from the command list. */
204:
205: void
206: delete_cmd (name, list)
207: char *name;
208: struct cmd_list_element **list;
209: {
210: register struct cmd_list_element *c;
211:
212: while (*list && !strcmp ((*list)->name, name))
213: {
214: *list = (*list)->next;
215: }
216:
217: if (*list)
218: for (c = *list; c->next;)
219: {
220: if (!strcmp (c->next->name, name))
221: c->next = c->next->next;
222: else
223: c = c->next;
224: }
225: }
226:
227: /* Implement a help command on command list LIST.
228: COMMAND is the argument given (a command from the list to document)
229: or zero for no arg (describe briefly all the commands in the list).
230: CMDTYPE is a string to use in the error message if command COMMAND
231: is not found in the list. */
232:
233: /* CLASS should be -1 to list all commands in LIST,
234: or a nonnegative class number value to list just commands in that class,
235: or -2 to list the classes themselves. */
236:
237: void
238: help_cmd (command, list, cmdtype, class, stream)
239: char *command;
240: struct cmd_list_element *list;
241: char *cmdtype;
242: int class;
243: FILE *stream;
244: {
245: register struct cmd_list_element *c;
246: register char *p;
247: register int ncmds;
248: struct cmdvec { struct cmd_list_element *cmd; int class; };
249: register struct cmdvec *cmdvec;
250: char *cmdtype1, *cmdtype2;
251: int len;
252:
253: if (command)
254: {
255: c = lookup_cmd (&command, list, cmdtype, 0);
256: if (c == 0)
257: return;
258:
259: /* There are three cases here.
260: If c->prefixlist is nonzer, we have a prefix command.
261: Print its documentation, then list its subcommands.
262:
263: If c->function is nonzero, we really have a command.
264: Print its documentation and return.
265:
266: If c->function is zero, we have a class name.
267: Print its documentation (as if it were a command)
268: and then set class to he number of this class
269: so that the commands in the class will be listed. */
270:
271: p = c->doc;
272: fprintf (stream, "%s\n", p);
273: if (c->function != 0 && c->prefixlist == 0)
274: return;
275: fputc ('\n', stream);
276: if (c->prefixlist)
277: {
278: list = *c->prefixlist;
279: class = 0;
280: cmdtype = c->prefixname;
281: }
282: else
283: class = c->class;
284: }
285:
286: /* If CMDTYPE is "foo ", CMDTYPE1 gets " foo" and CMDTYPE2 gets "foo sub" */
287: len = strlen (cmdtype);
288: cmdtype1 = (char *) alloca (len + 1);
289: cmdtype1[0] = 0;
290: cmdtype2 = (char *) alloca (len + 4);
291: cmdtype2[0] = 0;
292: if (len)
293: {
294: cmdtype1[0] = ' ';
295: strncpy (cmdtype1 + 1, cmdtype, len - 1);
296: cmdtype1[len] = 0;
297: strncpy (cmdtype2, cmdtype, len - 1);
298: strcpy (cmdtype2 + len - 1, " sub");
299: }
300:
301: if (class == -2)
302: fprintf (stream, "List of classes of %scommands:\n\n", cmdtype2);
303: else
304: fprintf (stream, "List of %scommands:\n\n", cmdtype2);
305:
306: for (c = list; c; c = c->next)
307: {
308: if (c->abbrev_flag == 0
309: && (class == -1 /* Listing all */
310: || (c->class == class && c->function != 0) /* Listing one class */
311: || (class == -2 && c->function == 0))) /* Listing the classes */
312: {
313: fprintf (stream, "%s -- ", c->name);
314: /* Print just first line of documentation. */
315: p = c->doc;
316: while (*p && *p != '\n') p++;
317: fwrite (c->doc, 1, p - c->doc, stream);
318: fputc ('\n', stream);
319: }
320: }
321:
322: if (class == -2)
323: fprintf (stream, "\n\
324: Type \"help%s\" followed by a class name for a list of commands in that class.",
325: cmdtype1);
326:
327: fprintf (stream, "\n\
328: Type \"help%s\" followed by %scommand name for full documentation.\n\
329: Command name abbreviations are allowed if unambiguous.\n",
330: cmdtype1, cmdtype2);
331: }
332:
333: /* Look up the contents of *LINE as a command in the command list LIST.
334: LIST is a chain of struct cmd_list_element's.
335: If it is found, return the struct cmd_list_element for that command
336: and update *LINE to point after the command name, at the first argument.
337: If not found, call error if ALLOW_UNKNOWN is zero
338: otherwise (or if error returns) return zero.
339: Call error if specified command is ambiguous,
340: unless ALLOW_UNKNOWN is negative.
341: CMDTYPE precedes the word "command" in the error message. */
342:
343: struct cmd_list_element *
344: lookup_cmd (line, list, cmdtype, allow_unknown)
345: char **line;
346: struct cmd_list_element *list;
347: char *cmdtype;
348: int allow_unknown;
349: {
350: register char *p;
351: register struct cmd_list_element *c, *found;
352: int nfound;
353: char ambbuf[100];
354:
355: /* Skip leading whitespace. */
356:
357: while (**line == ' ' || **line == '\t')
358: (*line)++;
359:
360: /* Clear out trailing whitespace. */
361:
362: p = *line + strlen (*line);
363: while (p != *line && (p[-1] == ' ' || p[-1] == '\t'))
364: p--;
365: *p = 0;
366:
367: /* Find end of command name. */
368:
369: p = *line;
370: while (*p == '-'
371: || (*p >= 'a' && *p <= 'z')
372: || (*p >= 'A' && *p <= 'Z')
373: || (*p >= '0' && *p <= '9'))
374: {
375: if (*p >= 'A' && *p <= 'Z')
376: *p += 'a' - 'A';
377: p++;
378: }
379:
380: /* Look up the command name.
381: If exact match, keep that.
382: Otherwise, take command abbreviated, if unique. */
383:
384: found = 0;
385: nfound = 0;
386: for (c = list; c; c = c->next)
387: {
388: if (!strncmp (*line, c->name, p - *line))
389: {
390: found = c;
391: nfound++;
392: if (c->name[p - *line] == 0)
393: {
394: nfound = 1;
395: break;
396: }
397: }
398: }
399:
400: /* Report error for undefined command name. */
401:
402: if (nfound != 1)
403: {
404: if (nfound > 1 && allow_unknown >= 0)
405: {
406: *p = 0;
407: ambbuf[0] = 0;
408: for (c = list; c; c = c->next)
409: if (!strncmp (*line, c->name, p - *line))
410: {
411: if (strlen (ambbuf) + strlen (c->name) + 6 < sizeof ambbuf)
412: {
413: if (strlen (ambbuf))
414: strcat (ambbuf, ", ");
415: strcat (ambbuf, c->name);
416: }
417: else
418: {
419: strcat (ambbuf, "..");
420: break;
421: }
422: }
423: error ("Ambiguous %scommand \"%s\": %s.", cmdtype, *line, ambbuf);
424: }
425: else if (!allow_unknown)
426: {
427: *p = 0;
428: error ("Undefined %scommand: \"%s\".", cmdtype, *line);
429: }
430: return 0;
431: }
432:
433: /* Skip whitespace before the argument. */
434:
435: while (*p == ' ' || *p == '\t') p++;
436: *line = p;
437:
438: if (found->prefixlist && *p)
439: {
440: c = lookup_cmd (line, *found->prefixlist, found->prefixname,
441: found->allow_unknown);
442: if (c)
443: return c;
444: }
445:
446: return found;
447: }
448:
449: /* Make a copy of the string at PTR with SIZE characters
450: (and add a null character at the end in the copy).
451: Uses malloc to get the space. Returns the address of the copy. */
452:
453: static char *
454: savestring (ptr, size)
455: char *ptr;
456: int size;
457: {
458: register char *p = (char *) xmalloc (size + 1);
459: bcopy (ptr, p, size);
460: p[size] = 0;
461: return p;
462: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.