1/* G C M D L I N -- gkermit command line parser */ 2 3/* 4 Author: 5 Frank da Cruz 6 The Kermit Project 7 Columbia University 8 612 West 115th Street 9 New York NY 10025-7799 USA 10 http://www.columbia.edu/kermit/ 11 kermit@columbia.edu 12 13 Copyright (C) 1999, 14 The Trustees of Columbia University in the City of New York. 15 16 This program is free software; you can redistribute it and/or modify 17 it under the terms of the GNU General Public License as published by 18 the Free Software Foundation; either version 2 of the License, or 19 (at your option) any later version. 20 21 This program is distributed in the hope that it will be useful, 22 but WITHOUT ANY WARRANTY; without even the implied warranty of 23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 GNU General Public License for more details. 25 26 You should have received a copy of the GNU General Public License 27 along with this program; if not, write to the Free Software 28 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 29*/ 30 31#include <stdio.h> 32#include <stdlib.h> 33#include <string.h> 34#include "gkermit.h" 35 36/* Externals */ 37 38extern int nfils, parity, text, backup, rpsiz, urpsiz, timint; 39extern int literal, quiet, keep, streamok, nomodes, manual, xonxoff, noxonxoff; 40extern char ttname[], *cmerrp, *cmarg, *cmarg2; 41extern FILE * db; 42 43/* Variables exported from this module */ 44 45extern char **cmlist; /* Pointer to file list in argv */ 46extern char **xargv; /* Global copies of argv */ 47extern int xargc; /* and argc */ 48 49/* Variables and symbols local to this module */ 50 51static int action = 0; /* Action selected on command line */ 52 53_MYPROTOTYPE( static int doarg, (char) ); 54_MYPROTOTYPE( VOID fatal, (char *) ); 55_MYPROTOTYPE( VOID usage, (void) ); 56 57#ifndef NOGETENV 58#define GARGC 32 59#define GBUFSIZ 256 60static char gbuf[GBUFSIZ], *gargs[GARGC], *gptr = NULL; 61static int gargc; 62#endif /* NOGETENV */ 63 64int /* Command-line parser */ 65cmdlin() { 66 char c; 67 int x; 68#ifndef NOGETENV 69 char * p = NULL; 70#endif /* NOGETENV */ 71 72 cmarg = ""; /* Initialize results */ 73 cmlist = NULL; 74 action = 0; 75 76#ifndef NOGETENV 77 if ((p = getenv("GKERMIT"))) { 78 int i, xc, flag = 0; 79 char **xv = NULL; 80 81 strncpy(gbuf,p,GBUFSIZ-1); /* Make a pokeable copy */ 82 gbuf[GBUFSIZ-1] = NUL; 83 gptr = p; 84 p = gbuf; 85 86 /* Turn it into an argument vector */ 87 88 for (i = 0; gbuf[i] && i < GBUFSIZ && gargc < GARGC; i++) { 89 if (!flag) { 90 if (gbuf[i] <= SP) 91 continue; 92 flag = 1; 93 gargs[gargc++] = &gbuf[i]; 94 } else if (flag && gbuf[i] <= SP) { 95 gbuf[i] = NUL; 96 flag = 0; 97 continue; 98 } 99 } 100 xv = xargv; /* Save original argument vector */ 101 xc = xargc; 102 xargv = gargs; /* Redirect it to the one we made */ 103 xargc = gargc; 104 105 while (xargc-- > 0) { /* Go through the words */ 106 if (**xargv == '-') { /* Got an option (begins with dash) */ 107 c = *(*xargv+1); /* Get the option letter */ 108 x = doarg(c); /* Go handle the option */ 109 if (x < 0) doexit(1); 110 } else { /* No dash where expected */ 111 fprintf(stderr, 112 "?GKERMIT variable option error: \"%s\"\n", 113 *xargv 114 ); 115 usage(); /* Give usage message */ 116 doexit(0); 117 } 118 xargv++; 119 } 120 xargv = xv; /* Restore original argument vector */ 121 xargc = xc; 122 } 123#endif /* NOGETENV */ 124 125 while (--xargc > 0) { /* Go through command line words */ 126 xargv++; 127 if (**xargv == '-') { /* Got an option (begins with dash) */ 128 c = *(*xargv+1); /* Get the option letter */ 129 x = doarg(c); /* Go handle the option */ 130 if (x < 0) doexit(1); 131 } else { /* No dash where expected */ 132 fprintf(stderr,"?Command-line option error: \"%s\"\n", *xargv); 133 usage(); /* Give usage message */ 134 doexit(1); 135 } 136 } 137 return(action); /* Then do any requested protocol */ 138} 139 140/* D O A R G -- Do a command-line argument. */ 141 142static int 143#ifdef __STDC__ 144doarg(char x) 145#else 146doarg(x) char x; 147#endif /* __STDC__ */ 148{ 149 int z; char *xp, **p; 150 151 xp = *xargv+1; /* Pointer for bundled args */ 152 while (x) { 153 switch (x) { 154 case 'r': /* Receive */ 155 if (action) fatal("conflicting actions"); 156 action = 'v'; 157 break; 158 159 case 's': /* Send */ 160 if (action) fatal("conflicting actions"); 161 if (*(xp+1)) fatal("invalid argument bundling after -s"); 162 nfils = 0; /* Initialize file counter, flag */ 163 cmlist = xargv+1; /* Remember this pointer */ 164 if (zchki(*cmlist) < 0) 165 fatal("file not found or not accessible"); 166 while (--xargc > 0) { /* Traverse the list */ 167 *xargv++; 168 if (**xargv == '-') 169 break; 170 nfils++; 171 } 172 xargc++, *xargv--; /* Adjust argv/argc */ 173 if (nfils < 1) fatal("missing filename for -s"); 174 action = 's'; 175 break; 176 177 case 'g': /* get */ 178 if (action) fatal("conflicting actions"); 179 if (*(xp+1)) fatal("invalid argument bundling after -g"); 180 *xargv++, xargc--; 181 if ((xargc == 0) || (**xargv == '-')) 182 fatal("missing filename for -g"); 183 cmarg = *xargv; 184 action = 'r'; 185 break; 186 187 case 'h': /* Help */ 188 case '?': 189 usage(); 190 doexit(0); 191 192 case 'i': /* Binary (image) file transfer */ 193 manual = 1; 194 text = 0; 195 break; 196 197 case 'T': /* Text file transfer */ 198 manual = 1; 199 text = 1; 200 break; 201 202 case 'p': /* Parity */ 203 if (*(xp+1)) fatal("invalid argument bundling"); 204 *xargv++, xargc--; 205 if ((xargc < 1) || (**xargv == '-')) 206 fatal("missing parity"); 207 switch(x = **xargv) { 208 case 'e': /* Even */ 209 case 'o': /* Odd */ 210 case 'm': /* Mark */ 211 case 's': parity = x; break; /* Space */ 212 case 'n': parity = 0; break; /* None */ 213 default: fatal("invalid parity"); 214 } 215 break; 216 217 case 'w': /* Writeover */ 218 backup = 0; /* Don't back up existing files */ 219 break; 220 221 case 'd': /* Debug */ 222 p = xargv; 223 *p++; 224 if ((xargc < 2) || (**p == '-')) { 225 db = fopen("debug.log","w"); 226 } else { 227 *xargv++, xargc--; 228 db = fopen(*xargv,"w"); 229 } 230 if (db) { 231 extern char * versio, * build; 232 if (!versio) versio = ""; 233 if (!build) build = ""; 234 debug = 1; 235 setbuf(db,NULL); 236 fprintf(db,"%s: %s\n", 237 (*versio ? versio : "GKERMIT VERSION UNKNOWN"), 238 (*build ? build : "BUILD UNKNOWN") 239 ); 240 fprintf(db,"MAXPATHLEN = %d\n",MAXPATHLEN); 241 if (gptr) fprintf(db,"GKERMIT=\"%s\"\n",gptr); 242 } 243 break; 244 245 case 'a': /* As-name */ 246 if (*(xp+1)) fatal("invalid argument bundling after -a"); 247 *xargv++, xargc--; 248 if ((xargc == 0) || (**xargv == '-')) 249 fatal("missing name for -a"); 250 cmarg2 = *xargv; 251 if (debug) fprintf(db,"as-name: %s\n",cmarg2); 252 break; 253 254 case 'e': 255 if (*(xp+1)) fatal("invalid argument bundling after -e"); 256 xargv++, xargc--; 257 if ((xargc < 1) || (**xargv == '-')) 258 fatal("missing length"); 259 z = atoi(*xargv); /* Convert to number. */ 260 if (z >= 40 && z <= MAXRP) { 261 rpsiz = urpsiz = z; 262 if (z > 94) rpsiz = 94; /* Fallback if other Kermit can't */ 263 } else { /* do long packets. */ 264 fatal("Unsupported packet length"); 265 } 266 break; 267 268 case 'b': /* Timeout */ 269 if (*(xp+1)) fatal("invalid argument bundling after -b"); 270 xargv++, xargc--; 271 if ((xargc < 1) || (**xargv == '-')) 272 fatal("missing value"); 273 z = atoi(*xargv); /* Convert to number */ 274 if (z < 0) z = 0; 275 if (z > 90) z = 90; 276 timint = z; 277 break; 278 279 case 'P': /* Path (file) names literal */ 280 literal = 1; 281 break; 282 283 case 'q': /* Quiet */ 284 quiet = 1; 285 break; 286 287 case 'K': /* Keep incompletely received files */ 288 keep = 1; 289 break; 290 291 case 'S': /* Disable streaming */ 292 streamok = -1; 293 break; 294 295 case 'X': /* gkermit is an external protocol */ 296 quiet = 1; /* No messages */ 297 nomodes = 1; /* Don't set tty modes */ 298 break; 299 300 case 'x': /* Force Xon/Xoff */ 301 xonxoff = 1; 302 noxonxoff = 0; 303 break; 304 305 case '-': /* Don't force Xon/Xoff */ 306 if (*(xp+1) == 'x') { 307 xonxoff = 0; 308 noxonxoff = 1; 309 } else { 310 fatal("invalid argument, type 'gkermit -h' for help"); 311 } 312 xp++; 313 break; 314 315 default: /* Anything else */ 316 fatal("invalid argument, type 'gkermit -h' for help"); 317 } 318 x = *++xp; /* See if options are bundled */ 319 } 320 if (debug) { 321 if (action) 322 fprintf(db,"cmdlin action = %c\n",action); 323 else 324 fprintf(db,"cmdlin action = (none)\n"); 325 } 326 return(action); 327} 328 329VOID 330fatal(msg) char *msg; { /* Fatal error message */ 331 fprintf(stderr,"\r\nFatal: %s",msg); /* doexit supplies crlf.. */ 332 doexit(1); /* Exit indicating failure */ 333} 334 335VOID 336usage() { 337 extern char * versio, * build, * url, * email; 338 if (!versio) versio = ""; 339 if (!*versio) versio = "gkermit UNKNOWN VERSION"; 340 if (!build) build = "UNKNOWN BUILD"; 341 if (!url) url = ""; 342 if (!email) email = ""; 343 fprintf(stderr,"%s: %s.\n",versio,build); 344 fprintf(stderr,"Usage: gkermit [ options ]\n"); 345 fprintf(stderr,"Options:\n"); 346 fprintf(stderr," -r Receive files\n"); 347 fprintf(stderr," -s fn Send files\n"); 348 fprintf(stderr," -g fn Get files from server\n"); 349 fprintf(stderr," -a fn As-name for single file\n"); 350 fprintf(stderr," -i Image (binary) mode transfer\n"); 351 fprintf(stderr," -T Text mode transfer\n"); 352 fprintf(stderr," -P Path/filename conversion disabled\n"); 353 fprintf(stderr," -w Write over existing files with same name\n"); 354 fprintf(stderr," -K Keep incompletely received files\n"); 355 fprintf(stderr," -p x Parity: x = o[dd],e[ven],m[ark],s[pace],n[one]\n") 356 ; 357 fprintf(stderr," -e n Receive packet-length (40-%d)\n",MAXRP); 358 fprintf(stderr," -b n Timeout (sec, 0 = none)\n"); 359 fprintf(stderr," -x Force Xon/Xoff (--x = Don't force Xon/Xoff)\n"); 360 fprintf(stderr," -S Disable streaming\n"); 361 fprintf(stderr," -X External protocol\n"); 362 fprintf(stderr," -q Quiet (suppress messages)\n"); 363 fprintf(stderr," -d [fn] Debug to ./debug.log [or specified file]\n"); 364 fprintf(stderr," -h Help (this message)\n"); 365 if (*url || *email) 366 fprintf(stderr,"More info: %s <%s>",url,email); 367} 368