fixed a bug in multi-subscript calculation
[unix-history] / usr / src / usr.bin / ftp / main.c
CommitLineData
ba5bf9f5
SL
1#ifndef lint
2static char sccsid[] = "@(#)main.c 4.1 (Berkeley) %G%";
3#endif
4
5/*
6 * FTP User Program -- Command Interface.
7 */
8#include <sys/types.h>
9#include <sys/socket.h>
10#include <sys/ioctl.h>
11
12#include <signal.h>
13#include <stdio.h>
14#include <errno.h>
15#include <ctype.h>
16#include <netdb.h>
17
18#include "ftp.h"
19#include "ftp_var.h"
20
21int intr();
22int lostpeer();
23
24main(argc, argv)
25 char *argv[];
26{
27 register char *cp;
28 int top;
29
30 sp = getservbyname("ftp", "tcp");
31 if (sp == 0) {
32 fprintf(stderr, "ftp: ftp/tcp: unknown service\n");
33 exit(1);
34 }
35 argc--, argv++;
36 while (argc > 0 && **argv == '-') {
37 for (cp = *argv + 1; *cp; cp++)
38 switch (*cp) {
39
40 case 'd':
41 options |= SO_DEBUG;
42 debug++;
43 break;
44
45 case 'v':
46 verbose++;
47 break;
48
49 case 't':
50 trace++;
51 break;
52
53 case 'i':
54 interactive++;
55 break;
56
57 case 'n':
58 autologin = 0;
59 break;
60
61 default:
62 fprintf(stderr,
63 "ftp: %c: unknown option\n", *cp);
64 exit(1);
65 }
66 argc--, argv++;
67 }
68 fromatty = isatty(fileno(stdin));
69 /*
70 * Set up defaults for FTP.
71 */
72 strcpy(typename, "ascii"), type = TYPE_A;
73 strcpy(formname, "non-print"), form = FORM_N;
74 strcpy(modename, "stream"), mode = MODE_S;
75 strcpy(structname, "file"), stru = STRU_F;
76 if (fromatty)
77 verbose++;
78 if (argc > 0) {
79 if (setjmp(toplevel))
80 exit(0);
81 sigset(SIGINT, intr);
82 sigset(SIGPIPE, lostpeer);
83 setpeer(argc + 1, argv - 1);
84 }
85 top = setjmp(toplevel) == 0;
86 if (top) {
87 sigset(SIGINT, intr);
88 sigset(SIGPIPE, lostpeer);
89 }
90 for (;;) {
91 cmdscanner(top);
92 top = 1;
93 }
94}
95
96intr()
97{
98
99 longjmp(toplevel, 1);
100}
101
102lostpeer()
103{
104 extern FILE *cout;
105 extern int data;
106 int how = 1+1;
107
108 if (connected) {
109 if (cout != NULL) {
110 shutdown(fileno(cout), &how);
111 fclose(cout);
112 cout = NULL;
113 }
114 if (data >= 0) {
115 shutdown(data, &how);
116 (void) close(data);
117 data = -1;
118 }
119 connected = 0;
120 }
121 longjmp(toplevel, 1);
122}
123
124char *
125tail(filename)
126 char *filename;
127{
128 register char *s;
129
130 while (*filename) {
131 s = rindex(filename, '/');
132 if (s == NULL)
133 break;
134 if (s[1])
135 return (s + 1);
136 *s = '\0';
137 }
138 return (filename);
139}
140
141/*
142 * Command parser.
143 */
144cmdscanner(top)
145 int top;
146{
147 register struct cmd *c;
148 struct cmd *getcmd();
149 extern struct cmd cmdtab[];
150 extern int help();
151
152 if (!top)
153 putchar('\n');
154 for (;;) {
155 if (fromatty) {
156 printf("ftp> ");
157 fflush(stdout);
158 }
159 if (gets(line) == 0)
160 break;
161 if (line[0] == 0)
162 break;
163 makeargv();
164 c = getcmd(margv[0]);
165 if (c == (struct cmd *)-1) {
166 printf("?Ambiguous command\n");
167 continue;
168 }
169 if (c == 0) {
170 printf("?Invalid command\n");
171 continue;
172 }
173 (*c->c_handler)(margc, margv);
174 if (bell && c->c_bell)
175 putchar(CTRL(g));
176 if (c->c_handler != help)
177 break;
178 }
179 longjmp(toplevel, 0);
180}
181
182struct cmd *
183getcmd(name)
184 register char *name;
185{
186 register char *p, *q;
187 register struct cmd *c, *found;
188 register int nmatches, longest;
189
190 longest = 0;
191 nmatches = 0;
192 found = 0;
193 for (c = cmdtab; p = c->c_name; c++) {
194 for (q = name; *q == *p++; q++)
195 if (*q == 0) /* exact match? */
196 return (c);
197 if (!*q) { /* the name was a prefix */
198 if (q - name > longest) {
199 longest = q - name;
200 nmatches = 1;
201 found = c;
202 } else if (q - name == longest)
203 nmatches++;
204 }
205 }
206 if (nmatches > 1)
207 return ((struct cmd *)-1);
208 return (found);
209}
210
211/*
212 * Slice a string up into argc/argv.
213 */
214makeargv()
215{
216 char **argp;
217 char *slurpstring();
218
219 margc = 0;
220 argp = margv;
221 stringbase = line; /* scan from first of buffer */
222 argbase = argbuf; /* store from first of buffer */
223 while (*argp++ = slurpstring())
224 margc++;
225}
226
227/*
228 * Parse string into argbuf;
229 * implemented with FSM to
230 * handle quoting and strings
231 */
232char *
233slurpstring()
234{
235 int got_one = 0;
236 register char *sb = stringbase;
237 register char *ap = argbase;
238 char *tmp = argbase; /* will return this if token found */
239
240S0:
241 switch (*sb) {
242
243 case '\0':
244 goto OUT;
245
246 case ' ':
247 case '\t':
248 sb++; goto S0;
249
250 default:
251 goto S1;
252 }
253
254S1:
255 switch (*sb) {
256
257 case ' ':
258 case '\t':
259 case '\0':
260 goto OUT; /* end of token */
261
262 case '\\':
263 sb++; goto S2; /* slurp next character */
264
265 case '"':
266 sb++; goto S3; /* slurp quoted string */
267
268 default:
269 *ap++ = *sb++; /* add character to token */
270 got_one = 1;
271 goto S1;
272 }
273
274S2:
275 switch (*sb) {
276
277 case '\0':
278 goto OUT;
279
280 default:
281 *ap++ = *sb++;
282 got_one = 1;
283 goto S1;
284 }
285
286S3:
287 switch (*sb) {
288
289 case '\0':
290 goto OUT;
291
292 case '"':
293 sb++; goto S1;
294
295 default:
296 *ap++ = *sb++;
297 got_one = 1;
298 goto S3;
299 }
300
301OUT:
302 if (got_one)
303 *ap++ = '\0';
304 argbase = ap; /* update storage pointer */
305 stringbase = sb; /* update scan pointer */
306 if (got_one)
307 return(tmp);
308 return((char *)0);
309}
310
311#define HELPINDENT (sizeof ("directory"))
312
313/*
314 * Help command.
315 * Call each command handler with argc == 0 and argv[0] == name.
316 */
317help(argc, argv)
318 int argc;
319 char *argv[];
320{
321 register struct cmd *c;
322
323 if (argc == 1) {
324 register int i, j, w;
325 int columns, width = 0, lines;
326 extern int NCMDS;
327
328 printf("Commands may be abbreviated. Commands are:\n\n");
329 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
330 int len = strlen(c->c_name);
331
332 if (len > width)
333 width = len;
334 }
335 width = (width + 8) &~ 7;
336 columns = 80 / width;
337 if (columns == 0)
338 columns = 1;
339 lines = (NCMDS + columns - 1) / columns;
340 for (i = 0; i < lines; i++) {
341 for (j = 0; j < columns; j++) {
342 c = cmdtab + j * lines + i;
343 printf("%s", c->c_name);
344 if (c + lines >= &cmdtab[NCMDS]) {
345 printf("\n");
346 break;
347 }
348 w = strlen(c->c_name);
349 while (w < width) {
350 w = (w + 8) &~ 7;
351 putchar('\t');
352 }
353 }
354 }
355 return;
356 }
357 while (--argc > 0) {
358 register char *arg;
359 arg = *++argv;
360 c = getcmd(arg);
361 if (c == (struct cmd *)-1)
362 printf("?Ambiguous help command %s\n", arg);
363 else if (c == (struct cmd *)0)
364 printf("?Invalid help command %s\n", arg);
365 else
366 printf("%-*s\t%s\n", HELPINDENT,
367 c->c_name, c->c_help);
368 }
369}
370
371/*
372 * Call routine with argc, argv set from args (terminated by 0).
373 */
374/* VARARGS2 */
375call(routine, args)
376 int (*routine)();
377 int args;
378{
379 register int *argp;
380 register int argc;
381
382 for (argc = 0, argp = &args; *argp++ != 0; argc++)
383 ;
384 (*routine)(argc, &args);
385}