home *** CD-ROM | disk | FTP | other *** search
- /* dio.c
- * Directed I/O package for BDS C vZ2.0
- *
- * Version 2.1 -- September 12, 1992 -- Gene Pizzetta
- * Corrected bug in redirected output to NUL:. Output was being echoed
- * to the screen because of a misplaced label.
- *
- * Version 2.0 -- August 15, 1992 -- Gene Pizzetta
- * I couldn't get piping to work properly under ZCPR3, so modification
- * was necessary. Then I missed ZCPR's path search and ARUNZ for the
- * piped-to utilities, so more modification was necessary. The remaining
- * command line after the pipe character ("|") is now loaded into the
- * multiple command line buffer, so things work as you would expect. Now
- * sets the program error flag if an error is encountered. Output can
- * now be appended to an existing file, sent to a printer (LST:), or
- * dumped to the bit bucket (NUL:). Piping is only available under
- * ZCPR3.
- *
- * June 1986 -- Leor Zolman
- * For BDS C v1.6.
- *
- * The following functions make up the directed I/O library:
- *
- * 1. dioinit(&argc,argv) Make this the first thing you do in your
- * "main" function, to process redirection
- * commands on the CP/M command line.
- *
- * 2. getchar() Gets a character from the keyboard, or from
- * a directed input file if one was specified
- * on the command line.
- *
- * 3. putchar(c) Puts a character out to the console, or to
- * a directed output file if one was specified
- * on the command line.
- *
- * 4. dioflush() Flushes directed output file, if open, and
- * closes all directed I/O files (if any).
- * This function must be called before your
- * program exits or returns to CP/M.
- *
- * To activate redirection, several special arguments may be given on the
- * command line to programs using this module:
- *
- * >filename "putchar" places characters into the given file
- * instead of to the console. An existing file with
- * same name will be overwritten.
- *
- * +filename like ">filename" (above) except that the characters
- * are also sent to the console.
- *
- * >>filename characters to be appended to the given existing file
- * instead of being sent to the console. If no such
- * file exists, it will be created.
- *
- * +>filename like ">>filename" (above) except that the characters
- * are also echoed at the console.
- *
- * >LST: characters are sent to the printer instead of to
- * the console. ">>LST:" works the same.
- *
- * +LST: like ">LST:" (above) except that the characters are
- * also echoed at the console. "+>LST:" works the same.
- *
- * >NUL: characters are sent to the "bit bucket". ">>NUL:"
- * works the same.
- *
- * <filename "getchar" returns characters from the given file
- * instead of from the keyboard.
- *
- * cmd1 |cmd2 characters from the standard output of "cmd1" are
- * sent to the standard input of "cmd2". Both "cmd1"
- * and "cmd2" must be compiled with this DIO package.
- *
- * There must never be any spaces between >, +, <, or | and the following
- * filename.
- *
- * When no "<" or "|" operator is used, standard input comes from the
- * console and all standard line editing characters are recognized (a
- * new feature of v1.45). To indicate end-of-file, you must type
- * ^Z <CR>
- * (control-Z followed by a carriage-return.)
- *
- * When no ">" or "|" operator is used, standard output goes to the
- * console.
- *
- * A program allowing redirection must have the following form:
- *
- * #include <stdio.h> /* standard header file */
- * #include "dio.h" /* directed I/O header */
- *
- * ... /* other externals, if any */
- *
- * main(argc,argv)
- * char **argv;
- * {
- * ... /* declarations */
- * dioinit(&argc,argv); /* initialize redirection */
- * ...
- * ... /* body of program using */
- * ... /* getchar and putchar */
- * ... /* or any routines that */
- * ... /* use stdin and stdout */
- * ...
- * dioflush(); /* clean up redirection */
- * }
- *
- * NOTES:
- *
- * 1. Console input may be raw (unbuffered, one character at a time) or
- * buffered (entire line must be typed before characters are returned,
- * allowing standard editing features, and characters come back one
- * at a time AFTER the entire line is typed). The default is raw.
- * For buffered console input, change BUF_CONS definition in DIO.H from
- * 0 to 1, then recompile this file and all files in your program.
- *
- * 2. Redirection and pipes work only for TEXT. This mechanism should
- * not be used for binary data. Piping works only under ZCPR3; other-
- * wise, DIO exits with a message is piping is attempted.
- *
- * 3. Do not define your own "getchar" or "putchar" when using the DIO
- * package, or things will get very confused.
- *
- * 4. Multiple pipes may be chained on one command line. For example, the
- * following command feeds the output of program "foo" into the input
- * of program "bar", the output of "bar" into the input of program
- * "zot", and the output of "zot" into a file called "output":
- *
- * A>foo arg1 |bar |zot arg2 arg3 >output <cr>
- *
- * "arg1" is an actual argument to "foo", and "arg2" and "arg3" are
- * actual arguments to "zot". This illustrates how actual arguments
- * may be interspersed with redirection commands. The programs see
- * the actual arguments, but command line preprocessing handled by the
- * "dioinit" function cause the programs to never need to know about
- * the redirection commands. All three programs ("foo", "bar" and
- * "zot") must have been compiled and linked with the DIO package for
- * everything to work properly. In addition, "bar" and "zot" must be
- * located along the ZCPR3 path or must be available via an extended
- * processor like ARUNZ or LX.
- */
-
- #include <stdio.h>
- #include "dio.h"
-
- #define CON_INPUT 1 /* BDOS call to read console */
- #define CON_OUTPUT 2 /* BDOS call to write to console */
- #define CON_STATUS 11 /* BDOS call to interrogate status */
-
- #define CONTROL_C 3 /* Quit character */
- #define INPIPE 2 /* bit setting to indicate directed
- input from a temp. pipe file */
- #define VERBOSE 2 /* bit setting to indicate output is to
- go to console AND directed output */
-
- /*
- * The "dioinit" function must be called at the beginning of the
- * "main" function:
- */
-
- #define argc *argcp
-
- dioinit(argcp,argv)
- int *argcp;
- char **argv;
- {
- int i,j, argcount;
-
- /* No directed I/O by default */
- _diflag = _doflag = _pipef = _apflag = _prflag = _nulflag = FALSE;
- _nullpos = &argv[argc];
- cmd = cmdstr; /* pointer to string for MCL */
-
- /* Assume no append */
- fnptr = 1; /* pointer to output filename */
- fmode = "w"; /* pointer to file open mode */
-
- #if BUF_CONS
- _conbuf[0] = 0; /* no characters in buffer yet */
- _conbufp = _conbuf; /* point to null buffer */
- #endif
-
- argcount = 1;
-
- for (i = 1; i < argc; i++) /* Scan the command line for > and < */
- {
- if (_pipef) break;
- switch(*argv[i])
- {
-
- case '<': /* Check for directed input: */
- if (!argv[i][1]) goto barf;
- if ((_dibuf = fopen(&argv[i][1], "r")) == NULL)
- {
- fputs("DIO: Can't open " ,stderr);
- fputs(&argv[i][1],stderr);
- fputs("\n",stderr);
- exit(10); /* file not found error */
- }
- _diflag = TRUE;
- if (strcmp(argv[i],"<TEMPIN.$$$") == 0)
- _diflag |= INPIPE;
- goto movargv;
-
- case '|': /* Check for pipe: */
- if (zenv() == NULL)
- {
- fputs("DIO: Pipes require ZCPR3",stderr);
- exit(4);
- }
- _pipef++;
- _pipedest = &argv[i][fnptr]; /* save prog name for MCL */
- if (argv[i][fnptr])
- {
- argv[i] = ".TEMPOUT.$$$"; /* temp. output */
- _savei = &argv[i];
- }
- goto foo;
-
- case '+':
- _doflag |= VERBOSE;
-
- foo: case '>': /* Check for directed output */
- if (argv[i][1] == '>') /* if we have a second ">" */
- {
- _apflag++; /* then we're appending */
- fmode = "a"; /* open file in append mode */
- fnptr++; /* that is, argv[i][2] */
- }
- if (!argv[i][fnptr]) /* any file or device name? */
- {
- barf: fputs("DIO: Bad redirection/pipe specifier",stderr);
- exit(4); /* miscellaneous error */
- }
- if (!strcmp(&argv[i][fnptr],"NUL:"))
- {
- _nulflag++;
- goto setdo;
- }
- if (!strcmp(&argv[i][fnptr],"LST:"))
- {
- _prflag++;
- goto setdo;
- }
- if (!_apflag) unlink(&argv[i][fnptr]);
- if ((_dobuf = fopen(&argv[i][fnptr], fmode)) == NULL)
- {
- fputs("DIO: Can't open " ,stderr);
- fputs(&argv[i][1],stderr);
- fputs("\n",stderr);
- exit(11); /* directory full error */
- }
- setdo: _doflag++;
-
- movargv: if (!_pipef)
- {
- for (j = i; j < argc; j++) argv[j] = argv[j+1];
- (argc)--;
- i--;
- _nullpos--;
- }
- else
- {
- argc = argcount;
- argv[argc] = 0;
- }
- break;
-
- default: /* handle normal arguments: */
- argcount++;
- }
- }
- }
-
- #undef argc
-
- /*
- * The "dioflush" function must be called before exiting the program.
- */
-
- dioflush()
- {
- if (_diflag)
- {
- fclose(_dibuf);
- if (_diflag & INPIPE) unlink("tempin.$$$");
- }
-
- if (_prflag || _nulflag) return;
-
- if (_doflag)
- {
- putc(CPMEOF,_dobuf);
- fclose(_dobuf);
- unlink("tempin.$$$"); /* in case previous pipe was aborted */
- rename("tempout.$$$","tempin.$$$");
- if (_pipef)
- {
- *_savei = "<TEMPIN.$$$";
- *_nullpos = NULL;
- strcpy(cmd,_pipedest);
- while (!(_savei == _nullpos))
- {
- strcat(cmd," ");
- strcat(cmd,*_savei);
- _savei++;
- }
- if (putcl(cmd) == FALSE) /* load ZCPR MCL */
- {
- fputs("\007DIO: Command line overflow\n",
- stderr);
- exit(15);
- }
- }
- }
- }
-
-
- /*
- * This version of "getchar" replaces the regular version when using
- * directed I/O. Note that the "BUF_CONS" defined symbol (in DIO.H)
- * controls whether the console input is to be raw or buffered (see
- * item 0. in NOTES above)
- */
-
- getchar()
- {
- int c;
-
- if (_diflag)
- {
- if ((c = getc(_dibuf)) == '\r') c = getc(_dibuf);
- }
- else
-
- #if BUF_CONS /* For buffered console input, get a line of text */
- { /* from the BDOS (using "gets"), & insert newline: */
- if (!*_conbufp)
- {
- gets(_conbufp = _conbuf);
- _conbuf[strlen(_conbuf) + 1] = '\0';
- _conbuf[strlen(_conbuf)] = '\n';
- }
- c = *_conbufp++;
- }
- #else /* for raw console input, simulate normal "getchar": */
- if ((c = bdos(CON_INPUT) & 0x7f) == CONTROL_C) exit(4);
- #endif
-
- if (c == CPMEOF) return EOF; /* Control-Z is EOF key */
-
- if (c == '\r')
- {
- c = '\n';
- #if !BUF_CONS
- if (!_diflag) bdos(2,'\n'); /* echo LF after CR to console */
- #endif
- }
- return c;
- }
-
-
- /*
- * This version of "putchar" replaces the regular version when using
- * directed I/O:
- */
-
- putchar(c)
- char c;
- {
- char *static;
- static = ""; /* remembers last character sent; start out null */
-
- if (_doflag)
- {
- if (_nulflag) goto nulskip;
- if (_prflag)
- {
- if (c == '\n' && *static != '\r') putc('\r',stdlst);
- *static = c;
- if(putc(c,stdlst) == ERROR)
- {
- fputs("DIO: Printer output error.",stderr);
- exit(4);
- }
- }
- else
- {
- if (c == '\n' && *static != '\r') putc('\r',_dobuf);
- *static = c;
- if(putc(c,_dobuf) == ERROR)
- {
- fputs("DIO: Output error--disk full?\n",stderr);
- exit(11); /* disk full error */
- }
- }
- nulskip: if (!(_doflag & VERBOSE)) return;
- }
- if (bdos(CON_STATUS) && bdos(CON_INPUT) == CONTROL_C)
- {
- fputs("\nDIO: Interrupt detected.",stderr);
- exit(4);
- }
- if (c == '\n' && *static != '\r') bdos(CON_OUTPUT,'\r');
- bdos(CON_OUTPUT,c);
- *static = c;
- }