Open Computing ``Hands-On'': ``Wizard's Grabbag'' Column: February 1994: Listings Listing: The upload program collects input characters, writing them to an output file. A. Listing of the upload program: 1 #ifdef TERMIO /* System V or BSD4.3+ */ 2 #include /* Declares struct termio and flags */ 3 #define STDIN_FILENO 0 /* Standard-input file descriptor */ 4 struct termio oldterm, /* Original driver settings */ 5 newterm; /* "raw" I/O driver settings */ 6 #else /* Use POSIX serial I/O interface */ 7 #define _POSIX_SOURCE 1 /* Hide vendor extensions to POSIX */ 8 #include /* Declares atoi(), exit(); */ 9 #include /* close(), isatty(), read(), write(), 10 tcgetattr(), and tcsetattr() */ 11 #include /* Declares termios, CRTL(c) */ 12 struct termios oldterm, /* Original driver settings */ 13 newterm; /* "Raw" I/O driver settings */ 14 #endif /* POSIX */ 15 16 #include /* Read these with _POSIX_SOURCE set */ 17 #include /* Defines open() symbolic constants */ 18 19 #define CTRL(c) ((c)&037) /* Macro to get control char code */ 20 #define CR CTRL('m') /* Carriage return is Control-M */ 21 #define CZ CTRL('z') /* DOS EOF character is Control Z */ 22 #define FALSE 0 /* Logical falsehood */ 23 #define TRUE 1 /* Logical truth */ 24 static char *prog; /* Points to name of this program */ 25 26 static char SccsID[] = "@(#) upload.c, Frank Lees, Jan. 89; \ 27 POSIX port by Becca Thomas, read time out by Ray Swartz, Oct. 93"; 28 29 void reset_term() /* Reset serial driver */ 30 { 31 #ifdef TERMIO 32 if (ioctl(STDIN_FILENO, TCSETAF, &oldterm) < 0) 33 #else /* Assume POSIX */ 34 if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &oldterm) < 0) 35 #endif 36 perror("Error resetting serial I/O flags"); 37 } 38 39 void usage() /* Display correct command-line usage */ 40 { 41 fprintf(stderr, 42 "\nUsage: %s [ -b ] [ -m ] [ -q secs ] [ -z ] output-file\n\ 43 -b Binary transfer (8 data bits; default: 7 data bits)\n\ 44 -m Pass Control-Ms to output (default: block them)\n\ 45 -q # Quit time (is rounded up to next 10 secs; default 10 sec)\n\ 46 -z Pass Control-Zs to output (default: block them)\n\ 47 output-file Won't overwrite existing file with same path name\n", 48 prog); 49 } 50 51 main(argc, argv) 52 int argc; char *argv[]; 53 { 54 char c; /* Character read/written */ 55 int binary = FALSE, /* Default is text transfer */ 56 block_M = TRUE, /* Don't pass carriage retns */ 57 block_Z = TRUE, /* Don't pass control-Z */ 58 fdo, /* Output-file descriptor */ 59 loop_count, /* Outer loop counter */ 60 optletter, /* Option letter */ 61 quit_time = 10, /* Max wait time betwn chars */ 62 status = 0; /* Exit status */ 63 extern char *optarg; /* Option argument value */ 64 extern int optind; /* Index of next argument */ 65 66 prog = argv[0]; /* Point to program's name */ 67 68 /* Process command-line options: */ 69 while ((optletter = getopt(argc, argv, "bmq:z")) != EOF) { 70 switch(optletter) { 71 case 'b': binary = TRUE; break; 72 case 'm': block_M = FALSE; break; 73 case 'q': if ((quit_time = atoi(optarg)) < 10) { 74 fprintf(stderr, 75 "Quit time must greater than 10 sec\n"); 76 usage(); exit(1); 77 } 78 /* round up to next highest multiple of ten: */ 79 quit_time = (10 + ((quit_time - 1)/10) * 10); 80 break; 81 case 'z': block_Z = FALSE; break; 82 case '?': usage(); exit(1); /* unknown option */ 83 } /* end of switch statement */ 84 } /* end of while loop */ 85 86 /* Check remaining (non-option) argument(s): */ 87 switch (argc - optind) { /* number of remaining args */ 88 case 0: (void)fprintf(stderr, 89 "Must specify output-file name argument.\n"); 90 usage(); exit(1); 91 case 1: break; /* one argument is okay */ 92 default: (void)fprintf(stderr, 93 "Only one non-option argument is allowed.\n"); 94 usage(); exit(1); 95 } 96 97 /* Open output-file for writing: */ 98 if ((fdo = open(argv[optind], O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) { 99 perror("Error opening output file"); exit(2); 100 } 101 102 /* Make sure standard input denotes a terminal: */ 103 if (!isatty(STDIN_FILENO)) { 104 (void)fprintf(stderr, 105 "Error, standard input is not a terminal device.\n"); 106 exit(3); 107 } 108 109 /* Get original serial I/O settings: */ 110 #ifdef TERMIO 111 if (ioctl(STDIN_FILENO, TCGETA, &oldterm) < 0) { 112 #else /* Assume POSIX */ 113 if (tcgetattr(STDIN_FILENO, &oldterm) < 0) { 114 #endif 115 perror("Error getting serial I/O flags"); exit(4); 116 } 117 118 newterm = oldterm; /* structure copy */ 119 /* Reset option flags for non-canonical operation: 120 (most SYSV, BSD4.3+, and POSIX option flags are the same) */ 121 newterm.c_lflag &= ~(ECHO | ICANON | ISIG); 122 newterm.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); 123 newterm.c_cflag &= ~(CSIZE | PARENB); 124 newterm.c_cflag |= CS8; 125 newterm.c_oflag &= ~(OPOST); 126 newterm.c_cc[VMIN] = 0; 127 newterm.c_cc[VTIME] = 100; /* Times out after 100 * 0.1 secs */ 128 129 /* Set "raw" mode operation, flushing input queue: */ 130 #ifdef TERMIO 131 if (ioctl(STDIN_FILENO, TCSETAF, &newterm) < 0) { 132 #else /* Assume POSIX */ 133 if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &newterm) < 0) { 134 #endif 135 perror("Error setting raw serial I/O"); exit(5); 136 } 137 138 /* Collect input characters and write to output file: */ 139 (void)printf("START of Transfer\r\n"); 140 loop_count = quit_time/10; 141 while (loop_count-- > 0) { 142 while (read(STDIN_FILENO, &c, 1)) { 143 if (!binary) 144 c &= 0x7f; /* Mask bit 8 if not binary */ 145 /* Pass the character if one of these tests is successful:*/ 146 if (binary || ((c != CR) && (c != CZ)) || 147 ((c == CR) && !block_M) || ((c == CZ) && !block_Z)) 148 if (write(fdo, &c, 1) < 0) { 149 perror("Error writing to output file"); 150 reset_term(); exit(6); 151 } 152 loop_count = (quit_time/10 - 1); /* reset if read */ 153 } 154 } 155 156 if (close(fdo) < 0) { /* Done with output file */ 157 perror("Error closing output file"); reset_term(); exit(7); 158 } 159 160 (void)printf("END of Transfer\007\r\n"); 161 reset_term(); exit(0); 162 } B. A command line to compile for ``termio''-structure environments: $ cc -D TERMIO -o upload upload.c C. Alternate call that will open an existing file without an error indication: 98 if ((fdo = open(argv[optind], O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0 { D. The ``termios''-structure definition: struct termios { tcflag_t c_iflag; /* input modes */ tcflag_t c_oflag; /* output modes */ tcflag_t c_cflag; /* control modes */ tcflag_t c_lflag; /* line discipline modes */ cc_t c_cc[NCCS]; /* control chars */ }; E. The ``termio''-structure definition: struct termio { unsigned short c_iflag; /* input modes */ unsigned short c_oflag; /* output modes */ unsigned short c_cflag; /* control modes */ unsigned short c_lflag; /* line discipline modes */ char c_line; /* line discipline */ unsigned char c_cc[NCC]; /* control chars */ }; TABLE: Serial-driver structure flags manipulated by upload. ECHO Input characters echoed back to source ICANON Assemble input into lines, recognize control characters ISIG Recognize control characters that cause signals BRKINT Generate SIGINT (interrupt signal) on "break" ICRNL Received carriage return is translated into newline character ISTRIP Strip most-significant bit of each character IXON Use start-stop control on input CSIZE Character size mask PARENB Perform parity checking on incoming characters CS8 Use all eight bits OPOST Use implementation-dependent output processing VMIN Minimum number of bytes read before "read" call returns VTIME Number of tenths-of-a-second to wait before "read" returns ------------------------------------------------------------------------------- Copyright © 1995 The McGraw-Hill Companies, Inc. All Rights Reserved. Edited by Becca Thomas / Online Editor / UnixWorld Online / beccat@wcmh.com [Go to Contents] [Search Editorial] Last Modified: Sunday, 10-Sep-95 07:55:46 PDT