00001 /* 00002 Miscellaneous examples for Chap. 4 00003 AUP2, Chap. 4 00004 00005 Copyright 2003 by Marc J. Rochkind. All rights reserved. 00006 May be copied only for purposes and under conditions described 00007 on the Web page www.basepath.com/aup/copyright.htm. 00008 00009 The Example Files are provided "as is," without any warranty; 00010 without even the implied warranty of merchantability or fitness 00011 for a particular purpose. The author and his publisher are not 00012 responsible for any damages, direct or incidental, resulting 00013 from the use or non-use of these Example Files. 00014 00015 The Example Files may contain defects, and some contain deliberate 00016 coding mistakes that were included for educational reasons. 00017 You are responsible for determining if and how the Example Files 00018 are to be used. 00019 00020 */ 00021 #include "defs.h" 00022 #include "setblock.h" 00023 #include "../c2/bufio.h" 00024 00025 /* read line from terminal */ 00026 /*[getln]*/ 00027 bool getln(char *s, ssize_t max, bool *iseof) 00028 { 00029 ssize_t nread; 00030 00031 switch (nread = read(STDIN_FILENO, s, max - 1)) { 00032 case -1: 00033 EC_FAIL 00034 case 0: 00035 *iseof = true; 00036 return true; 00037 default: 00038 if (s[nread - 1] == '\n') 00039 nread--; 00040 s[nread] = '\0'; 00041 *iseof = false; 00042 return true; 00043 } 00044 00045 EC_CLEANUP_BGN 00046 return false; 00047 EC_CLEANUP_END 00048 } 00049 /*[]*/ 00050 00051 /* read line from anywhere */ 00052 /*[getln2]*/ 00053 bool getln2(char *s, ssize_t max, bool *iseof) 00054 { 00055 ssize_t n; 00056 char c; 00057 00058 n = 0; 00059 while (true) 00060 switch (read(STDIN_FILENO, &c, 1)) { 00061 case -1: 00062 EC_FAIL 00063 case 0: 00064 s[n] = '\0'; 00065 *iseof = true; 00066 return true; 00067 default: 00068 if (c == '\n') { 00069 s[n] = '\0'; 00070 *iseof = false; 00071 return true; 00072 } 00073 if (n >= max - 1) { 00074 errno = E2BIG; 00075 EC_FAIL 00076 } 00077 s[n++] = c; 00078 } 00079 00080 EC_CLEANUP_BGN 00081 return false; 00082 EC_CLEANUP_END 00083 } 00084 /*[test_setblock]*/ 00085 static void test_setblock(void) 00086 { 00087 char s[100]; 00088 ssize_t n; 00089 time_t tstart, tnow; 00090 00091 ec_neg1( tstart = time(NULL) ) 00092 ec_false( setblock(STDIN_FILENO, false) ) 00093 while (true) { 00094 ec_neg1( tnow = time(NULL) ) 00095 printf("Waiting for input (%.0f sec.) ...\n", 00096 difftime(tnow, tstart)); 00097 switch(n = read(STDIN_FILENO, s, sizeof(s) - 1)) { 00098 case 0: 00099 printf("EOF\n"); 00100 break; 00101 case -1: 00102 if (errno == EAGAIN) { 00103 sleep(5); 00104 continue; 00105 } 00106 EC_FAIL 00107 default: 00108 if (s[n - 1] == '\n') 00109 n--; 00110 s[n] = '\0'; 00111 printf("Read \"%s\"\n", s); 00112 continue; 00113 } 00114 break; 00115 } 00116 return; 00117 00118 EC_CLEANUP_BGN 00119 EC_FLUSH("test_setblock") 00120 EC_CLEANUP_END 00121 } 00122 /*[]*/ 00123 static void test_setblock2(void) 00124 { 00125 char s[100]; 00126 bool iseof; 00127 00128 ec_false( setblock(STDIN_FILENO, true) ) 00129 while (true) { 00130 ec_false( getln(s, sizeof(s), &iseof) ) 00131 if (iseof) { 00132 printf("EOF\n"); 00133 break; 00134 } 00135 else 00136 printf("Read \"%s\"\n", s); 00137 } 00138 return; 00139 00140 EC_CLEANUP_BGN 00141 EC_FLUSH("test_setblock2") 00142 EC_CLEANUP_END 00143 } 00144 /*[]*/ 00145 static void test_Bfdopen(void) 00146 { 00147 BUFIO *stin; 00148 int c; 00149 /*[Bfdopen-test]*/ 00150 ec_null( stin = Bfdopen(STDIN_FILENO, "r") ) 00151 while ((c = Bgetc(stin)) != -1) 00152 /* process character */ 00153 /*[]*/ 00154 putchar(c); 00155 if (errno != 0) 00156 EC_FAIL 00157 printf("Got EOF\n"); 00158 ec_false( Bclose(stin) ) 00159 return; 00160 00161 EC_CLEANUP_BGN 00162 (void)Bclose(stin); 00163 EC_FLUSH("test_Bfdopen") 00164 EC_CLEANUP_END 00165 } 00166 #if 0 00167 #define Sfdopen Sopen 00168 #define refresh exit 00169 00170 void junk(void) /* don't call! */ 00171 { 00172 /*4-3*/ 00173 STREAM *stin; 00174 char c; 00175 00176 if ((stin = Sfdopen(STDIN_FILENO, "r")) == NULL) 00177 syserr("Sfdopen"); 00178 c = Sgetc(stin); 00179 /**/ 00180 00181 /*4-5*/ 00182 if (!cready()) 00183 refresh(); 00184 c = cget(); 00185 /**/ 00186 } 00187 #endif 00188 00189 #include <fcntl.h> 00190 /*[cready-cget]*/ 00191 #define EMPTY '\0' 00192 static unsigned char cbuf = EMPTY; 00193 typedef enum {CR_READY, CR_NOTREADY, CR_EOF} CR_STATUS; 00194 00195 bool cready(CR_STATUS *statusp) 00196 { 00197 if (cbuf != EMPTY) { 00198 *statusp = CR_READY; 00199 return true; 00200 } 00201 setblock(STDIN_FILENO, false); 00202 switch (read(STDIN_FILENO, &cbuf, 1)) { 00203 case -1: 00204 if (errno == EAGAIN) { 00205 *statusp = CR_NOTREADY; 00206 return true; 00207 } 00208 EC_FAIL 00209 case 0: 00210 *statusp = CR_EOF; 00211 return true; 00212 case 1: 00213 return true; 00214 default: /* "impossible" case */ 00215 errno = 0; 00216 EC_FAIL 00217 } 00218 00219 EC_CLEANUP_BGN 00220 return false; 00221 EC_CLEANUP_END 00222 } 00223 00224 bool cget(CR_STATUS *statusp, int *cp) 00225 { 00226 if (cbuf != EMPTY) { 00227 *cp = cbuf; 00228 cbuf = EMPTY; 00229 *statusp = CR_READY; 00230 return true; 00231 } 00232 setblock(0, true); 00233 switch (read(STDIN_FILENO, cp, 1)) { 00234 case -1: 00235 EC_FAIL 00236 case 0: 00237 *cp = 0; 00238 *statusp = CR_EOF; 00239 return true; 00240 case 1: 00241 *statusp = CR_READY; 00242 return true; 00243 default: /* "impossible" case */ 00244 errno = 0; 00245 EC_FAIL 00246 } 00247 00248 EC_CLEANUP_BGN 00249 return false; 00250 EC_CLEANUP_END 00251 } 00252 /*[]*/ 00253 00254 00255 /*[readany]*/ 00256 int readany(int fds[], int nfds, int *whichp) 00257 { 00258 int i; 00259 unsigned char c; 00260 00261 for (i = 0; i < nfds; i++) 00262 setblock(fds[i], false); /* inefficient to do this every time */ 00263 i = 0; 00264 while (true) { 00265 if (i >= nfds) { 00266 sleep(1); 00267 i = 0; 00268 } 00269 c = 0; /* return value for EOF */ 00270 if (read(fds[i], &c, 1) == -1) { 00271 if (errno == EAGAIN) { 00272 i++; 00273 continue; 00274 } 00275 EC_FAIL 00276 } 00277 *whichp = i; 00278 return c; 00279 } 00280 00281 EC_CLEANUP_BGN 00282 return -1; 00283 EC_CLEANUP_END 00284 } 00285 /*[readany2]*/ 00286 int readany2(int fds[], int nfds, int *whichp) 00287 { 00288 fd_set set_read; 00289 int i, maxfd = 0; 00290 unsigned char c; 00291 00292 FD_ZERO(&set_read); 00293 for (i = 0; i < nfds; i++) { 00294 FD_SET(fds[i], &set_read); 00295 if (fds[i] > maxfd) 00296 maxfd = fds[i]; 00297 } 00298 ec_neg1( select(maxfd + 1, &set_read, NULL, NULL, NULL) ) 00299 for (i = 0; i < nfds; i++) { 00300 if (FD_ISSET(fds[i], &set_read)) { 00301 c = 0; /* return value for EOF */ 00302 ec_neg1( read(fds[i], &c, 1) ) 00303 *whichp = i; 00304 return c; 00305 } 00306 } 00307 /* "impossible" to get here */ 00308 errno = 0; 00309 EC_FAIL 00310 00311 EC_CLEANUP_BGN 00312 return -1; 00313 EC_CLEANUP_END 00314 } 00315 #ifndef DARWIN 00316 /*[readany3]*/ 00317 #include <poll.h> 00318 00319 #define MAXFDS 100 00320 00321 int readany3(int fds[], int nfds, int *whichp) 00322 { 00323 struct pollfd fdinfo[MAXFDS] = { { 0 } }; 00324 int i; 00325 unsigned char c; 00326 00327 if (nfds > MAXFDS) { 00328 errno = E2BIG; 00329 EC_FAIL 00330 } 00331 for (i = 0; i < nfds; i++) { 00332 fdinfo[i].fd = fds[i]; 00333 fdinfo[i].events = POLLIN | POLLPRI; 00334 } 00335 ec_neg1( poll(fdinfo, nfds, -1) ) 00336 for (i = 0; i < nfds; i++) { 00337 if (fdinfo[i].revents & (POLLIN | POLLPRI)) { 00338 c = 0; /* return value for EOF */ 00339 ec_neg1( read(fdinfo[i].fd, &c, 1) ) 00340 *whichp = i; 00341 return c; 00342 } 00343 } 00344 /* "impossible" to get here */ 00345 errno = 0; 00346 EC_FAIL 00347 00348 EC_CLEANUP_BGN 00349 return -1; 00350 EC_CLEANUP_END 00351 } 00352 /*[]*/ 00353 #endif /* DARWIN */ 00354 /*[readany_test]*/ 00355 static void readany_test(void) 00356 { 00357 int fds[2] = {-1, -1}, which; 00358 int c; 00359 bool ok = false; 00360 00361 ec_neg1( fds[0] = open("/dev/tty", O_RDWR) ) 00362 ec_neg1( fds[1] = open("/dev/pts/3", O_RDWR) ) 00363 while ((c = readany(fds, 2, &which)) > 0) 00364 printf("Got %c from terminal %d\n", isprint(c) ? c : '?', which); 00365 ec_neg1( c ) 00366 ok = true; 00367 EC_CLEANUP 00368 00369 EC_CLEANUP_BGN 00370 if (fds[0] != -1) 00371 (void)close(fds[0]); 00372 if (fds[1] != -1) 00373 (void)close(fds[1]); 00374 if (!ok) 00375 EC_FLUSH("readany_test1") 00376 EC_CLEANUP_END 00377 } 00378 /*[]*/ 00379 static void readany_test2(void) 00380 { 00381 int fds[2] = {-1, -1}, which; 00382 int c; 00383 bool ok = false; 00384 00385 ec_neg1( fds[0] = open("/dev/tty", O_RDWR) ) 00386 ec_neg1( fds[1] = open("/dev/pts/3", O_RDWR) ) 00387 while ((c = readany2(fds, 2, &which)) > 0) 00388 printf("Got %c from terminal %d\n", isprint(c) ? c : '?', which); 00389 ec_neg1( c ) 00390 ok = true; 00391 EC_CLEANUP 00392 00393 EC_CLEANUP_BGN 00394 if (fds[0] != -1) 00395 (void)close(fds[0]); 00396 if (fds[1] != -1) 00397 (void)close(fds[1]); 00398 if (!ok) 00399 EC_FLUSH("readany_test2") 00400 EC_CLEANUP_END 00401 } 00402 #ifndef DARWIN 00403 static void readany_test3(void) 00404 { 00405 int fds[2] = {-1, -1}, which; 00406 int c; 00407 bool ok = false; 00408 00409 ec_neg1( fds[0] = open("/dev/tty", O_RDWR) ) 00410 ec_neg1( fds[1] = open("/dev/pts/3", O_RDWR) ) 00411 while ((c = readany3(fds, 2, &which)) > 0) 00412 printf("Got %c from terminal %d\n", isprint(c) ? c : '?', which); 00413 ec_neg1( c ) 00414 ok = true; 00415 EC_CLEANUP 00416 00417 EC_CLEANUP_BGN 00418 if (fds[0] != -1) 00419 (void)close(fds[0]); 00420 if (fds[1] != -1) 00421 (void)close(fds[1]); 00422 if (!ok) 00423 EC_FLUSH("readany_test3") 00424 EC_CLEANUP_END 00425 } 00426 #endif /* DARWIN */ 00427 int main(void) 00428 { 00429 char s[100]; 00430 #if 1 00431 int c; 00432 CR_STATUS status; 00433 int count = 0; 00434 while (true) { 00435 ec_false( cready(&status) ) 00436 switch (status) { 00437 case CR_READY: 00438 ec_false( cget(&status, &c) ) 00439 if (status == CR_EOF) { 00440 printf("EOF from cget\n"); 00441 setblock(STDIN_FILENO, true); 00442 exit(EXIT_SUCCESS); 00443 } 00444 printf("After %d cready() calls, got %c\n", count, c); 00445 count = 0; 00446 case CR_NOTREADY: 00447 count++; 00448 continue; 00449 case CR_EOF: 00450 printf("EOF from cready\n"); 00451 setblock(STDIN_FILENO, true); 00452 exit(EXIT_SUCCESS); 00453 } 00454 } 00455 #if 0 /* AUP1 -- not sure what this is doing */ 00456 if (cready()) 00457 printf("READY\n"); 00458 else 00459 printf("NOT READY\n"); 00460 if ((c = cget()) == -1) { 00461 printf("EOF\n"); 00462 exit(EXIT_SUCCESS); 00463 } 00464 if (c == 1) { 00465 setblock(0, true); 00466 exit(EXIT_SUCCESS); 00467 } 00468 printf("%c", c); 00469 #endif 00470 00471 #endif 00472 00473 /*[refresh-example]*/ 00474 ec_false( cready(&status) ) 00475 if (status == CR_NOTREADY) 00476 refresh(); 00477 ec_false( cget(&status, &c) ) 00478 /*[]*/ 00479 00480 00481 00482 #if 0 00483 { 00484 bool iseof; 00485 00486 setbuf(stdout, NULL); 00487 00488 { 00489 int fd1 = 1, fd2 = 4; 00490 00491 /*[fd_set-example]*/ 00492 fd_set set; 00493 00494 FD_ZERO(&set); 00495 FD_SET(fd1, &set); 00496 FD_SET(fd2, &set); 00497 if (FD_ISSET(fd1, &set)) { 00498 /* do something with fd1, depending on which set */ 00499 } 00500 /*[]*/ 00501 } 00502 //test_Bfdopen(); 00503 //test_setblock(); 00504 //test_setblock2(); 00505 readany_test2(); 00506 exit(EXIT_SUCCESS); 00507 00508 while (1) { 00509 printf("Type (getln): "); 00510 /*[getln-test]*/ 00511 ec_false( getln(s, sizeof(s), &iseof) ) 00512 if (iseof) 00513 printf("EOF\n"); 00514 else 00515 printf("Read: %s\n", s); 00516 /*[]*/ 00517 if (strcmp(s, "quit") == 0) 00518 break; 00519 printf("Type (getln2): "); 00520 /*[getln2-test]*/ 00521 ec_false( getln2(s, sizeof(s), &iseof) ) 00522 if (iseof) 00523 printf("EOF: %s\n", s); 00524 else 00525 printf("Read: %s\n", s); 00526 /*[]*/ 00527 if (strcmp(s, "quit") == 0) 00528 break; 00529 } 00530 exit(EXIT_SUCCESS); 00531 00532 } 00533 #endif 00534 EC_CLEANUP_BGN 00535 setblock(STDIN_FILENO, true); 00536 exit(EXIT_FAILURE); 00537 EC_CLEANUP_END 00538 }