/**** Naive argument processing example - it does not use getopt() ****/ #include /* Next five lines would ordinarily be put in a header file */ extern void fatal(char *message); extern int convert(int repeat,int caseflag); #define SAMECASE 0 #define LOWERCASE 1 #define UPPERCASE 2 static int usage(void); /* local function only */ char *progname; /* global variable to store program name */ /**** main(): Process arguments only. Other computations done elsewhere. ****/ int main(int argc, char *argv[]) { char c; int repeat_number=1, caseflag=SAMECASE; int i; progname = argv[0]; /* store name of program */ /* Process all options ('-' flags) */ i = 0; while (++i < argc && argv[i][0] == '-') /* Conventionally: while (--argc > 0 && (*++argv)[0] == '-') ++argv advances to next argv string, so *argv will be same as above version's argv[i] and so would use *argv instead below. */ {int j; /*** How to handle end of options flag -- */ if (argv[i][1] == '-' && argv[i][2] == '\0') /* end of options */ {i++; break; } /* take each character following the - in turn */ j = 1; while ((c = argv[i][j++]) != '\0') switch (c) {case 'l': /* set flag variable for 'l' here or do action */ caseflag = LOWERCASE; break; /*** How to handle two different options with same code */ case 'u': case 'U': caseflag = UPPERCASE; /* -u -l conflicts ignored */ break; /*** How to handle option with argument */ case 'r': if (argv[i][j] != '\0') /* error if 'r' is grouped */ {fprintf(stderr,"%s: -r option cannot be grouped\n", progname); usage(); return 1; } /* take next argv as argument */ /* could replace scan with: repeat_number = atoi(argv[i]) */ if (++i >= argc || 1 != sscanf(argv[i],"%d",&repeat_number)) {fprintf(stderr,"%s: -r option requires numeric argument\n", progname); usage(); return 1; } /* skip over the rest of this argv (without checking it) and position 'j' so that the inside 'while' above exits */ j = 0; while (argv[i][j++] != '\0'); j--; break; default : fprintf(stderr,"%s: bad flag %c\n",progname,c); usage(); return 1; break; /* not necessary - here for safety only */ } /* end switch */ } /* end options */ /* Remaining arguments are operands. Process these. We expect none. */ if (i < argc) {fprintf(stderr,"%s: unexpected operands\n",progname); usage(); return 1; } /* Finished argument processing */ /* Now use simple loop, while or a few simple function calls */ return convert(repeat_number,caseflag); /* return exit status */ } /**** Print usage message ****/ int usage(void) { fprintf(stderr,"usage: %s [-l] [-u|-U] [-r ]\n",progname); /* no manual or other documentation so we provide more explanation: */ fprintf(stderr," convert characters where\n"); fprintf(stderr," -l lower cases all\n"); fprintf(stderr," -u or -U upper cases all\n"); fprintf(stderr," -r repeats each character times - default 1\n"); return 0; } /**** Functions that do actual work. Ordinarily in another file. ****/ int convert(int repeat,int caseflag) { int c,i; if (repeat < 0) fatal("cannot repeat character negative number of times"); while ((c = getchar()) != EOF) for (i=0; i < repeat; i++) if (caseflag == UPPERCASE) putchar(toupper(c)); else if (caseflag == LOWERCASE) putchar(tolower(c)); else putchar(c); return 0; } /**** fatal - abort with error message. Ordinarily in another file. ****/ extern char *progname; void fatal(char *message) { fprintf(stderr,"%s: fatal error: %s\n",progname,message); exit(1); /* Do not want to return, instead exit(), which aborts program after cleaning up open files, etc. */ }