/* G C M D L I N -- gkermit command line parser */ /* Author: Frank da Cruz The Kermit Project Columbia University 612 West 115th Street New York NY 10025-7799 USA http://www.columbia.edu/kermit/ kermit@columbia.edu Copyright (C) 1999, The Trustees of Columbia University in the City of New York. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "gkermit.h" /* Externals */ extern int nfils, parity, text, backup, rpsiz, urpsiz, timint; extern int literal, quiet, keep, streamok, nomodes, manual, xonxoff, noxonxoff; extern char ttname[], *cmerrp, *cmarg, *cmarg2; extern FILE * db; /* Variables exported from this module */ extern char **cmlist; /* Pointer to file list in argv */ extern char **xargv; /* Global copies of argv */ extern int xargc; /* and argc */ /* Variables and symbols local to this module */ static int action = 0; /* Action selected on command line */ _MYPROTOTYPE( static int doarg, (char) ); _MYPROTOTYPE( VOID fatal, (char *) ); _MYPROTOTYPE( VOID usage, (void) ); #ifndef NOGETENV _MYPROTOTYPE( char * getenv, (char *) ); #define GARGC 32 #define GBUFSIZ 256 static char gbuf[GBUFSIZ], *gargs[GARGC], *gptr = NULL; static int gargc; #endif /* NOGETENV */ int /* Command-line parser */ cmdlin() { char c; int x; #ifndef NOGETENV char * p = NULL; #endif /* NOGETENV */ cmarg = ""; /* Initialize results */ cmlist = NULL; action = 0; #ifndef NOGETENV if ((p = getenv("GKERMIT"))) { int i, xc, flag = 0; char **xv = NULL; strncpy(gbuf,p,GBUFSIZ-1); /* Make a pokeable copy */ gbuf[GBUFSIZ-1] = NUL; gptr = p; p = gbuf; /* Turn it into an argument vector */ for (i = 0; gbuf[i] && i < GBUFSIZ && gargc < GARGC; i++) { if (!flag) { if (gbuf[i] <= SP) continue; flag = 1; gargs[gargc++] = &gbuf[i]; } else if (flag && gbuf[i] <= SP) { gbuf[i] = NUL; flag = 0; continue; } } xv = xargv; /* Save original argument vector */ xc = xargc; xargv = gargs; /* Redirect it to the one we made */ xargc = gargc; while (xargc-- > 0) { /* Go through the words */ if (**xargv == '-') { /* Got an option (begins with dash) */ c = *(*xargv+1); /* Get the option letter */ x = doarg(c); /* Go handle the option */ if (x < 0) doexit(1); } else { /* No dash where expected */ fprintf(stderr, "?GKERMIT variable option error: \"%s\"\n", *xargv ); usage(); /* Give usage message */ doexit(0); } xargv++; } xargv = xv; /* Restore original argument vector */ xargc = xc; } #endif /* NOGETENV */ while (--xargc > 0) { /* Go through command line words */ xargv++; if (**xargv == '-') { /* Got an option (begins with dash) */ c = *(*xargv+1); /* Get the option letter */ x = doarg(c); /* Go handle the option */ if (x < 0) doexit(1); } else { /* No dash where expected */ fprintf(stderr,"?Command-line option error: \"%s\"\n", *xargv); usage(); /* Give usage message */ doexit(1); } } return(action); /* Then do any requested protocol */ } /* D O A R G -- Do a command-line argument. */ static int #ifdef __STDC__ doarg(char x) #else doarg(x) char x; #endif /* __STDC__ */ { int z; char *xp, **p; xp = *xargv+1; /* Pointer for bundled args */ while (x) { switch (x) { case 'r': /* Receive */ if (action) fatal("conflicting actions"); action = 'v'; break; case 's': /* Send */ if (action) fatal("conflicting actions"); if (*(xp+1)) fatal("invalid argument bundling after -s"); nfils = 0; /* Initialize file counter, flag */ cmlist = xargv+1; /* Remember this pointer */ if (zchki(*cmlist) < 0) fatal("file not found or not accessible"); while (--xargc > 0) { /* Traverse the list */ *xargv++; if (**xargv == '-') break; nfils++; } xargc++, *xargv--; /* Adjust argv/argc */ if (nfils < 1) fatal("missing filename for -s"); action = 's'; break; case 'g': /* get */ if (action) fatal("conflicting actions"); if (*(xp+1)) fatal("invalid argument bundling after -g"); *xargv++, xargc--; if ((xargc == 0) || (**xargv == '-')) fatal("missing filename for -g"); cmarg = *xargv; action = 'r'; break; case 'h': /* Help */ case '?': usage(); doexit(0); case 'i': /* Binary (image) file transfer */ manual = 1; text = 0; break; case 'T': /* Text file transfer */ manual = 1; text = 1; break; case 'p': /* Parity */ if (*(xp+1)) fatal("invalid argument bundling"); *xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) fatal("missing parity"); switch(x = **xargv) { case 'e': /* Even */ case 'o': /* Odd */ case 'm': /* Mark */ case 's': parity = x; break; /* Space */ case 'n': parity = 0; break; /* None */ default: fatal("invalid parity"); } break; case 'w': /* Writeover */ backup = 0; /* Don't back up existing files */ break; case 'd': /* Debug */ p = xargv; *p++; if ((xargc < 2) || (**p == '-')) { db = fopen("debug.log","w"); } else { *xargv++, xargc--; db = fopen(*xargv,"w"); } if (db) { extern char * versio, * build; if (!versio) versio = ""; if (!build) build = ""; debug = 1; setbuf(db,NULL); fprintf(db,"%s: %s\n", (*versio ? versio : "GKERMIT VERSION UNKNOWN"), (*build ? build : "BUILD UNKNOWN") ); fprintf(db,"MAXPATHLEN = %d\n",MAXPATHLEN); if (gptr) fprintf(db,"GKERMIT=\"%s\"\n",gptr); } break; case 'a': /* As-name */ if (*(xp+1)) fatal("invalid argument bundling after -a"); *xargv++, xargc--; if ((xargc == 0) || (**xargv == '-')) fatal("missing name for -a"); cmarg2 = *xargv; if (debug) fprintf(db,"as-name: %s\n",cmarg2); break; case 'e': if (*(xp+1)) fatal("invalid argument bundling after -e"); xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) fatal("missing length"); z = atoi(*xargv); /* Convert to number. */ if (z >= 40 && z <= MAXRP) { rpsiz = urpsiz = z; if (z > 94) rpsiz = 94; /* Fallback if other Kermit can't */ } else { /* do long packets. */ fatal("Unsupported packet length"); } break; case 'b': /* Timeout */ if (*(xp+1)) fatal("invalid argument bundling after -b"); xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) fatal("missing value"); z = atoi(*xargv); /* Convert to number */ if (z < 0) z = 0; if (z > 90) z = 90; timint = z; break; case 'P': /* Path (file) names literal */ literal = 1; break; case 'q': /* Quiet */ quiet = 1; break; case 'K': /* Keep incompletely received files */ keep = 1; break; case 'S': /* Disable streaming */ streamok = -1; break; case 'X': /* gkermit is an external protocol */ quiet = 1; /* No messages */ nomodes = 1; /* Don't set tty modes */ break; case 'x': /* Force Xon/Xoff */ xonxoff = 1; noxonxoff = 0; break; case '-': /* Don't force Xon/Xoff */ if (*(xp+1) == 'x') { xonxoff = 0; noxonxoff = 1; } else { fatal("invalid argument, type 'gkermit -h' for help"); } xp++; break; default: /* Anything else */ fatal("invalid argument, type 'gkermit -h' for help"); } x = *++xp; /* See if options are bundled */ } if (debug) { if (action) fprintf(db,"cmdlin action = %c\n",action); else fprintf(db,"cmdlin action = (none)\n"); } return(action); } VOID fatal(msg) char *msg; { /* Fatal error message */ fprintf(stderr,"\r\nFatal: %s",msg); /* doexit supplies crlf.. */ doexit(1); /* Exit indicating failure */ } VOID usage() { extern char * versio, * build, * url, * email; if (!versio) versio = ""; if (!*versio) versio = "gkermit UNKNOWN VERSION"; if (!build) build = "UNKNOWN BUILD"; if (!url) url = ""; if (!email) email = ""; fprintf(stderr,"%s: %s.\n",versio,build); fprintf(stderr,"Usage: gkermit [ options ]\n"); fprintf(stderr,"Options:\n"); fprintf(stderr," -r Receive files\n"); fprintf(stderr," -s fn Send files\n"); fprintf(stderr," -g fn Get files from server\n"); fprintf(stderr," -a fn As-name for single file\n"); fprintf(stderr," -i Image (binary) mode transfer\n"); fprintf(stderr," -T Text mode transfer\n"); fprintf(stderr," -P Path/filename conversion disabled\n"); fprintf(stderr," -w Write over existing files with same name\n"); fprintf(stderr," -K Keep incompletely received files\n"); fprintf(stderr," -p x Parity: x = o[dd],e[ven],m[ark],s[pace],n[one]\n") ; fprintf(stderr," -e n Receive packet-length (40-%d)\n",MAXRP); fprintf(stderr," -b n Timeout (sec, 0 = none)\n"); fprintf(stderr," -x Force Xon/Xoff (--x = Don't force Xon/Xoff)\n"); fprintf(stderr," -S Disable streaming\n"); fprintf(stderr," -X External protocol\n"); fprintf(stderr," -q Quiet (suppress messages)\n"); fprintf(stderr," -d [fn] Debug to ./debug.log [or specified file]\n"); fprintf(stderr," -h Help (this message)\n"); if (*url || *email) fprintf(stderr,"More info: %s <%s>",url,email); }