ifdef.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. /*
  2. *
  3. * Conditionally compiled routines for setting up and reading the line. Things
  4. * were getting out of hand with all the ifdefs, and even though this defeats
  5. * part of the purpose of conditional complilation directives, I think it's easier
  6. * to follow this way. Thanks to Alan Buckwalter for the System V DKHOST code.
  7. *
  8. * postio now can be run as separate read and write processes, but requires that
  9. * you write a procedure called resetline() and perhaps modify readline() some.
  10. * I've already tested the code on System V and it seems to work. Ninth Edition
  11. * and BSD code may be missing.
  12. *
  13. * By request I've changed the way some of the setupline() procedures (eg. in the
  14. * System V implementation) handle things when no line has been given. If line is
  15. * NULL the new setupline() procedures try to continue, assuming whoever called
  16. * postio connected stdout to the printer. Things will only work if we can read
  17. * and write stdout!
  18. *
  19. */
  20. #include <stdio.h>
  21. #include <ctype.h>
  22. #include <fcntl.h>
  23. #include <signal.h>
  24. #include <sys/types.h>
  25. #include <errno.h>
  26. #include "ifdef.h" /* conditional header file inclusion */
  27. #include "gen.h" /* general purpose definitions */
  28. FILE *fp_ttyi, *fp_ttyo;
  29. char *ptr = mesg;
  30. extern int window_size;
  31. /*****************************************************************************/
  32. #ifdef SYSV
  33. setupline()
  34. {
  35. struct termio termio;
  36. /*
  37. *
  38. * Line initialization for SYSV. For now if no line is given (ie. line == NULL )
  39. * we continue on as before using stdout as ttyi and ttyo. Doesn't work when we're
  40. * running in interactive mode or forcing stuff that comes back from the printer
  41. * to stdout. Both cases are now caught by a test that's been added to routine
  42. * initialize(). The change is primarily for the version of lp that's available
  43. * with SVR3.2.
  44. *
  45. */
  46. #ifdef DKHOST
  47. if ( line != NULL && *line != '/' ) {
  48. if ( strncmp(line, "DK:", 3) == 0 )
  49. line += 3;
  50. dkhost_connect();
  51. #ifdef DKSTREAMS
  52. if ( ioctl(ttyi, I_PUSH, DKSTREAMS) == -1 )
  53. error(FATAL, "ioctl error - %s", DKSTREAMS);
  54. if ( ioctl(ttyi, I_PUSH, "ldterm") == -1 )
  55. error(FATAL, "ioctl error - ldterm");
  56. #endif
  57. } else
  58. #endif
  59. if ( line == NULL )
  60. ttyi = fileno(stdout);
  61. else if ( (ttyi = open(line, O_RDWR)) == -1 )
  62. error(FATAL, "can't open %s", line);
  63. if ( (ttyo = dup(ttyi)) == -1 )
  64. error(FATAL, "can't dup file descriptor for %s", line);
  65. if ( stopbits == 1 )
  66. stopbits = 0;
  67. else stopbits = CSTOPB;
  68. if ( fcntl(ttyi, F_SETFL, O_NDELAY) == -1 )
  69. error(FATAL, "fcntl error - F_SETFL");
  70. if ( ioctl(ttyi, TCGETA, &termio) == -1 )
  71. error(FATAL, "ioctl error - TCGETA");
  72. termio.c_iflag = IXON | IGNCR;
  73. termio.c_oflag = 0;
  74. termio.c_cflag = HUPCL | CREAD | CS8 | stopbits | baudrate;
  75. termio.c_lflag = 0;
  76. termio.c_cc[VMIN] = termio.c_cc[VTIME] = 0;
  77. if ( ioctl(ttyi, TCSETA, &termio) == -1 )
  78. error(FATAL, "ioctl error - TCSETA");
  79. if ( ioctl(ttyi, TCFLSH, 2) == -1 )
  80. error(FATAL, "ioctl error - TCFLSH");
  81. fp_ttyi = fdopen(ttyi, "r");
  82. } /* End of setupline */
  83. /*****************************************************************************/
  84. resetline()
  85. {
  86. int flags; /* for turning O_NDELAY off */
  87. struct termio termio; /* so we can reset flow control */
  88. /*
  89. *
  90. * Only used if we're running the program as separate read and write processes.
  91. * Called from split() after the initial connection has been made and returns
  92. * TRUE if two processes should work. Don't know if the O_NDELAY stuff is really
  93. * needed, but setting c_cc[VMIN] to 1 definitely is. If we leave it be (as a 0)
  94. * the read in readline() won't block!
  95. *
  96. */
  97. if ( (flags = fcntl(ttyi, F_GETFL, 0)) == -1 )
  98. error(FATAL, "fcntl error - F_GETFL");
  99. flags &= ~O_NDELAY;
  100. if ( fcntl(ttyi, F_SETFL, flags) == -1 )
  101. error(FATAL, "fcntl error - F_SETFL");
  102. if ( ioctl(ttyi, TCGETA, &termio) == -1 )
  103. error(FATAL, "ioctl error - TCGETA");
  104. termio.c_iflag &= ~IXANY;
  105. termio.c_iflag |= IXON | IXOFF;
  106. termio.c_cc[VMIN] = 1;
  107. termio.c_cc[VTIME] = 0;
  108. if ( ioctl(ttyi, TCSETA, &termio) == -1 )
  109. error(FATAL, "ioctl error - TCSETA");
  110. return(TRUE);
  111. } /* End of resetline */
  112. /*****************************************************************************/
  113. setupstdin(mode)
  114. int mode; /* what to do with stdin settings */
  115. {
  116. struct termio termio;
  117. static int saved = FALSE;
  118. static struct termio oldtermio;
  119. /*
  120. *
  121. * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for
  122. * stdin. Expect something like raw mode with no echo will be set up. Explicit
  123. * code to ensure blocking reads probably isn't needed because blocksize is set
  124. * to 1 when we're in interactive mode, but I've included it anyway.
  125. *
  126. */
  127. if ( interactive == TRUE )
  128. switch ( mode ) {
  129. case 0:
  130. if ( isatty(0) != 1 )
  131. error(FATAL, "stdin not a terminal - can't run interactive mode");
  132. if ( ioctl(0, TCGETA, &oldtermio) == -1 )
  133. error(FATAL, "can't save terminal settings");
  134. saved = TRUE;
  135. break;
  136. case 1:
  137. termio = oldtermio;
  138. termio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
  139. termio.c_cc[VMIN] = 1;
  140. termio.c_cc[VTIME] = 0;
  141. ioctl(0, TCSETA, &termio);
  142. break;
  143. case 2:
  144. if ( saved == TRUE )
  145. ioctl(0, TCSETA, &oldtermio);
  146. break;
  147. } /* End switch */
  148. } /* End of setupstdin */
  149. /*****************************************************************************/
  150. readline()
  151. {
  152. int n; /* read() return value */
  153. int ch; /* for interactive mode */
  154. static int tries = 0; /* consecutive times read returned 0 */
  155. /*
  156. *
  157. * Reads characters coming back from the printer on ttyi up to a newline (or EOF)
  158. * or until no more characters are available. Characters are put in mesg[], the
  159. * string is terminated with '\0' when we're done with a line and TRUE is returned
  160. * to the caller. If complete line wasn't available FALSE is returned. Interactive
  161. * mode should loop here forever, except during start(), echoing characters to
  162. * stdout. If it happens to leave FALSE should be returned. The non-blocking read
  163. * gets us out until split() is called.
  164. *
  165. * Some users (apparently just on 3B2 DKHOST systems) have had problems with the
  166. * two process implementation that's forced me to kludge things up some. When a
  167. * printer (on those systems) is turned off while postio is transmitting files
  168. * the write process hangs in writeblock() (postio.c) - it's typically in the
  169. * middle of a write() call, while the read() call (below) continually returns 0.
  170. * In the original code readline() returned FALSE when read() returned 0 and we
  171. * get into a loop that never ends - because the write process is hung. In the
  172. * one process implementation having read return 0 is legitimate because the line
  173. * is opened for no delay, but with two processes the read() blocks and a return
  174. * value of 0 should never occur. From my point of view the real problem is that
  175. * the write() call hangs on 3B2 DKHOST systems and apparently doesn't anywhere
  176. * else. If the write returned anything less than or equal to 0 writeblock() would
  177. * shut things down. The kludge I've implemented counts the number of consecutive
  178. * times read() returns a 0 and if it exceeds a limit (100) the read process will
  179. * shut things down. In fact one return of 0 from read() when we're in the two
  180. * process mode is undoubtedly sufficient and no counting should be necessary!!!
  181. * Moving the check to getstatus() should also work and is probably where things
  182. * belong.
  183. *
  184. */
  185. if ( interactive == FALSE ) {
  186. while ( (n = read(ttyi, ptr, 1)) != 0 ) {
  187. if ( n < 0 )
  188. if ( errno == EINTR )
  189. continue;
  190. else error(FATAL, "error reading %s", line);
  191. tries = 0;
  192. if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg ) {
  193. *(ptr+1) = '\0';
  194. if ( *ptr == '\004' )
  195. strcpy(ptr, "%%[ status: endofjob ]%%\n");
  196. ptr = mesg;
  197. return(TRUE);
  198. } /* End if */
  199. ptr++;
  200. } /* End while */
  201. if ( canread == TRUE && canwrite == FALSE ) /* read process kludge */
  202. if ( ++tries > 100 )
  203. error(FATAL, "printer appears to be offline - shutting down");
  204. return(FALSE);
  205. } /* End if */
  206. if ( canwrite == TRUE ) /* don't block during start() */
  207. return(FALSE);
  208. while ( (ch = getc(fp_ttyi)) != EOF )
  209. putc(ch, stdout);
  210. return(FALSE);
  211. } /* End of readline */
  212. #endif
  213. /*****************************************************************************/
  214. #ifdef V9
  215. #include <ipc.h>
  216. char tbuf[256]; /* temporary input buffer */
  217. char *nptr = tbuf; /* next character comes from here */
  218. char *eptr = tbuf; /* one past the last character in tbuf */
  219. setupline()
  220. {
  221. struct sgttyb sgtty;
  222. struct ttydevb ttydev; /* for setting up the line */
  223. static struct tchars tchar = { '\377', /* interrupt */
  224. '\377', /* quit */
  225. '\021', /* start output */
  226. '\023', /* stop output */
  227. '\377', /* end-of-file */
  228. '\377' /* input delimiter */
  229. };
  230. /*
  231. *
  232. * Line initialization for V9.
  233. *
  234. */
  235. if ( line == NULL ) {
  236. ttyi = ttyo = 1;
  237. return;
  238. } /* End if */
  239. alarm(120); /* watch for hanging opens */
  240. if ( line[0] == '/' ) {
  241. if ( (ttyi = open(line, O_RDWR)) == -1 )
  242. error(FATAL, "can't open %s", line);
  243. } else if ((ttyi = ipcopen(ipcpath(line, "dk", 0), "")) < 0) {
  244. sleep(5); /* wait for Datakit to hangup */
  245. if ((ttyi = ipcopen(ipcpath(line, "dk", 0), "")) < 0) {
  246. fprintf(stderr, "%s", errstr);
  247. error(FATAL, "can't ipcopen %s", line);
  248. }
  249. }
  250. alarm(0);
  251. if ( (ttyo = dup(ttyi)) == -1 )
  252. error(FATAL, "can't dup file descriptor for %s", line);
  253. if ( ioctl(ttyi, FIOPUSHLD, &tty_ld) == -1 )
  254. error(FATAL, "ioctl error - FIOPUSHLD");
  255. if ( ioctl(ttyi, TIOCGDEV, &ttydev) == -1 )
  256. error(FATAL, "ioctl error - TIOCGDEV");
  257. if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
  258. error(FATAL, "ioctl error - TIOCGETP");
  259. sgtty.sg_flags &= ~ECHO;
  260. sgtty.sg_flags &= ~CRMOD;
  261. sgtty.sg_flags |= CBREAK;
  262. ttydev.ispeed = baudrate;
  263. ttydev.ospeed = baudrate;
  264. if ( ioctl(ttyi, TIOCSDEV, &ttydev) == -1 )
  265. error(FATAL, "ioctl error - TIOCSDEV");
  266. if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
  267. error(FATAL, "ioctl error - TIOCSETP");
  268. if ( ioctl(ttyi, TIOCSETC, &tchar) == -1 )
  269. error(FATAL, "ioctl error - TIOCSETC");
  270. fp_ttyi = fdopen(ttyi, "r");
  271. } /* End of setupline */
  272. /*****************************************************************************/
  273. resetline()
  274. {
  275. struct sgttyb sgtty;
  276. /*
  277. *
  278. * Only used if we're running the program as separate read and write processes.
  279. * Called from split() after the initial connection has been made and returns
  280. * TRUE if two processes should work. Haven't tested or even compiled the stuff
  281. * for separate read and write processes on Ninth Edition systems - no guarantees
  282. * even though we return TRUE!
  283. *
  284. */
  285. if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
  286. error(FATAL, "ioctl error - TIOCGETP");
  287. sgtty.sg_flags |= TANDEM;
  288. if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
  289. error(FATAL, "ioctl error - TIOCSETP");
  290. return(TRUE);
  291. } /* End of resetline */
  292. /*****************************************************************************/
  293. setupstdin(mode)
  294. int mode; /* what to do with stdin settings */
  295. {
  296. struct sgttyb sgtty;
  297. static int saved = FALSE;
  298. static struct sgttyb oldsgtty;
  299. /*
  300. *
  301. * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for
  302. * stdin. Expect something like raw mode with no echo will be set up. Need to make
  303. * sure interrupt and quit still work - they're the only good way to exit when
  304. * we're running interactive mode. I haven't tested or even compiled this code
  305. * so there are no guarantees.
  306. *
  307. */
  308. if ( interactive == TRUE )
  309. switch ( mode ) {
  310. case 0:
  311. if ( ioctl(0, TIOCGETP, &oldsgtty) == -1 )
  312. error(FATAL, "can't save terminal settings");
  313. saved = TRUE;
  314. break;
  315. case 1:
  316. sgtty = oldsgtty;
  317. sgtty.sg_flags &= ~ECHO;
  318. sgtty.sg_flags |= CBREAK;
  319. ioctl(0, TIOCSETP, &sgtty);
  320. break;
  321. case 2:
  322. if ( saved == TRUE )
  323. ioctl(0, TIOCSETP, &oldsgtty);
  324. break;
  325. } /* End switch */
  326. } /* End of setupstdin */
  327. /*****************************************************************************/
  328. readline()
  329. {
  330. int n; /* read() return value */
  331. int ch; /* for interactive mode */
  332. /*
  333. *
  334. * Reads characters coming back from the printer on ttyi up to a newline (or EOF)
  335. * and transfers each line to the mesg[] array. Everything available on ttyi is
  336. * initially stored in tbuf[] and a line at a time is transferred from there to
  337. * mesg[]. The string in mesg[] is terminated with a '\0' and TRUE is returned to
  338. * the caller when we find a newline, EOF, or reach the end of the mesg[] array.
  339. * If nothing is available on ttyi we return FALSE if a single process is being
  340. * used for reads and writes, while in the two process implementation we force a
  341. * one character read. Interactive mode loops here forever, except during start(),
  342. * echoing everything that comes back on ttyi to stdout. The performance of a
  343. * simple getc/putc loop for interactive mode was unacceptable when run under mux
  344. * and has been replaced by more complicated code. When layers wasn't involved
  345. * the getc/putc loop worked well.
  346. *
  347. */
  348. if ( interactive == FALSE ) {
  349. while ( 1 ) {
  350. while ( nptr < eptr ) { /* grab characters from tbuf */
  351. *ptr = *nptr++;
  352. if ( *ptr == '\r' ) continue;
  353. if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg ) {
  354. *(ptr+1) = '\0';
  355. if ( *ptr == '\004' )
  356. strcpy(ptr, "%%[ status: endofjob ]%%\n");
  357. ptr = mesg;
  358. return(TRUE);
  359. } /* End if */
  360. ++ptr;
  361. } /* End for */
  362. nptr = eptr = tbuf;
  363. if ( ioctl(ttyi, FIONREAD, &n) < 0 )
  364. if ( errno == EINTR )
  365. continue;
  366. else error(FATAL, "ioctl error - FIONREAD");
  367. if ( n <= 0 )
  368. if ( canwrite == TRUE )
  369. return(FALSE);
  370. n = ((n < 1) ? 1 : ((n < sizeof(tbuf)) ? n : sizeof(tbuf)));
  371. if ( (n = read(ttyi, tbuf, n)) < 0 )
  372. if ( errno == EINTR )
  373. continue;
  374. else error(FATAL, "error reading line %s", line);
  375. else eptr = nptr + n;
  376. } /* End while */
  377. } /* End if */
  378. if ( canwrite == TRUE ) /* don't block during start() */
  379. return(FALSE);
  380. while ( 1 ) { /* only interactive mode gets here */
  381. if ( ioctl(ttyi, FIONREAD, &n) < 0 )
  382. error(FATAL, "ioctl error - FIONREAD");
  383. n = ((n < 1) ? 1 : ((n < sizeof(tbuf)) ? n : sizeof(tbuf)));
  384. if ( (n = read(ttyi, tbuf, n)) < 0 )
  385. error(FATAL, "error reading line %s", line);
  386. else if ( n == 0 ) /* should not happen */
  387. error(FATAL, "end of file in interactive mode");
  388. if ( write(1, tbuf, n) != n )
  389. error(FATAL, "error writing to stdout");
  390. } /* End while */
  391. return(FALSE);
  392. } /* End of readline */
  393. #endif
  394. /*****************************************************************************/
  395. #ifdef BSD4_2
  396. setupline()
  397. {
  398. struct sgttyb sgtty;
  399. static struct tchars tchar = { '\377', /* interrupt */
  400. '\377', /* quit */
  401. '\021', /* start output */
  402. '\023', /* stop output */
  403. '\377', /* end-of-file */
  404. '\377' /* input delimiter */
  405. };
  406. long lmodes;
  407. int disc = NTTYDISC;
  408. /*
  409. *
  410. * Line initialization for BSD4_2. As in the System V code, if no line is given
  411. * (ie. line == NULL) we continue on as before using stdout as ttyi and ttyo.
  412. *
  413. */
  414. if ( line == NULL )
  415. ttyi = fileno(stdout);
  416. else if ( (ttyi = open(line, O_RDWR)) == -1 )
  417. error(FATAL, "can't open %s", line);
  418. if ( (ttyo = dup(ttyi)) == -1 )
  419. error(FATAL, "can't dup file descriptor for %s", line);
  420. if (ioctl(ttyi, TIOCSETD, &disc) == -1 )
  421. error(FATAL, "ioctl error - TIOCSETD");
  422. if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
  423. error(FATAL, "ioctl error - TIOCGETP");
  424. if ( ioctl(ttyi, TIOCLGET, &lmodes) == -1 )
  425. error(FATAL, "ioctl error - TIOCLGET");
  426. sgtty.sg_flags &= ~ECHO;
  427. sgtty.sg_flags &= ~CRMOD;
  428. sgtty.sg_flags |= CBREAK;
  429. sgtty.sg_ispeed = baudrate;
  430. sgtty.sg_ospeed = baudrate;
  431. lmodes |= LDECCTQ;
  432. if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
  433. error(FATAL, "ioctl error - TIOCSETP");
  434. if ( ioctl(ttyi, TIOCSETC, &tchar) == -1 )
  435. error(FATAL, "ioctl error - TIOCSETC");
  436. if ( ioctl(ttyi, TIOCLSET, &lmodes) == -1 )
  437. error(FATAL, "ioctl error - TIOCLSET");
  438. fp_ttyi = fdopen(ttyi, "r");
  439. } /* End of setupline */
  440. /*****************************************************************************/
  441. resetline()
  442. {
  443. struct sgttyb sgtty;
  444. /*
  445. *
  446. * Only used if we're running the program as separate read and write processes.
  447. * Called from split() after the initial connection has been made and returns
  448. * TRUE if two processes should work. Haven't tested or even compiled the stuff
  449. * for separate read and write processes on Berkeley systems - no guarantees
  450. * even though we return TRUE!
  451. *
  452. */
  453. if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
  454. error(FATAL, "ioctl error - TIOCGETP");
  455. sgtty.sg_flags |= TANDEM;
  456. if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
  457. error(FATAL, "ioctl error - TIOCSETP");
  458. return(TRUE);
  459. } /* End of resetline */
  460. /*****************************************************************************/
  461. setupstdin(mode)
  462. int mode; /* what to do with stdin settings */
  463. {
  464. struct sgttyb sgtty;
  465. static int saved = FALSE;
  466. static struct sgttyb oldsgtty;
  467. /*
  468. *
  469. * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for
  470. * stdin. Expect something like raw mode with no echo will be set up. Need to make
  471. * sure interrupt and quit still work - they're the only good way to exit when
  472. * we're running interactive mode. I haven't tested or even compiled this code
  473. * so there are no guarantees.
  474. *
  475. */
  476. if ( interactive == TRUE )
  477. switch ( mode ) {
  478. case 0:
  479. if ( isatty(0) != 1 )
  480. error(FATAL, "stdin not a terminal - can't run interactive mode");
  481. if ( ioctl(0, TIOCGETP, &oldsgtty) == -1 )
  482. error(FATAL, "can't save terminal settings");
  483. saved = TRUE;
  484. break;
  485. case 1:
  486. sgtty = oldsgtty;
  487. sgtty.sg_flags &= ~ECHO;
  488. sgtty.sg_flags |= CBREAK;
  489. ioctl(0, TIOCSETP, &sgtty);
  490. break;
  491. case 2:
  492. if ( saved == TRUE )
  493. ioctl(0, TIOCSETP, &oldsgtty);
  494. break;
  495. } /* End switch */
  496. } /* End of setupstdin */
  497. /*****************************************************************************/
  498. readline()
  499. {
  500. int n; /* read() return value */
  501. int ch; /* for interactive mode */
  502. /*
  503. *
  504. * Reads characters coming back from the printer on ttyo up to a newline (or EOF)
  505. * or until no more characters are available. Characters are put in mesg[], the
  506. * string is terminated with '\0' when we're done with a line and TRUE is returned
  507. * to the caller. If complete line wasn't available FALSE is returned. Interactive
  508. * mode should loop here forever, except during start(), echoing characters to
  509. * stdout. If it happens to leave FALSE should be returned. Probably should read
  510. * everything available on ttyi into a temporary buffer and work from there rather
  511. * than reading one character at a time.
  512. *
  513. */
  514. if ( interactive == FALSE ) {
  515. while ( 1 ) {
  516. if ( ioctl(ttyi, FIONREAD, &n) < 0 )
  517. if ( errno == EINTR )
  518. continue;
  519. else error(FATAL, "ioctl error - FIONREAD");
  520. if ( n <= 0 )
  521. if ( canwrite == TRUE )
  522. return(FALSE);
  523. else n = 1;
  524. for ( ; n > 0; n-- ) {
  525. /*if ( read(ttyi, ptr, 1) < 0 )*/
  526. if ( (*ptr = getc(fp_ttyi)) == EOF )
  527. if ( errno == EINTR )
  528. continue;
  529. else error(FATAL, "error reading %s", line);
  530. if ( *ptr == '\r' ) continue;
  531. if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg ) {
  532. *(ptr+1) = '\0';
  533. if ( *ptr == '\004' )
  534. strcpy(ptr, "%%[ status: endofjob ]%%\n");
  535. ptr = mesg;
  536. return(TRUE);
  537. } /* End if */
  538. ++ptr;
  539. } /* End for */
  540. } /* End while */
  541. } /* End if */
  542. if ( canwrite == TRUE ) /* don't block during start() */
  543. return(FALSE);
  544. while ( (ch = getc(fp_ttyi)) != EOF )
  545. putc(ch, stdout);
  546. return(FALSE);
  547. } /* End of readline */
  548. /*****************************************************************************/
  549. /* @(#)strspn.c 1.2 */
  550. /*LINTLIBRARY*/
  551. /*
  552. * Return the number of characters in the maximum leading segment
  553. * of string which consists solely of characters from charset.
  554. */
  555. int
  556. strspn(string, charset)
  557. char *string;
  558. register char *charset;
  559. {
  560. register char *p, *q;
  561. for(q=string; *q != '\0'; ++q) {
  562. for(p=charset; *p != '\0' && *p != *q; ++p)
  563. ;
  564. if(*p == '\0')
  565. break;
  566. }
  567. return(q-string);
  568. }
  569. /* @(#)strpbrk.c 1.2 */
  570. /*LINTLIBRARY*/
  571. /*
  572. * Return ptr to first occurance of any character from `brkset'
  573. * in the character string `string'; NULL if none exists.
  574. */
  575. char *
  576. strpbrk(string, brkset)
  577. register char *string, *brkset;
  578. {
  579. register char *p;
  580. do {
  581. for(p=brkset; *p != '\0' && *p != *string; ++p)
  582. ;
  583. if(*p != '\0')
  584. return(string);
  585. }
  586. while(*string++);
  587. return((char*)0);
  588. }
  589. /* @(#)strtok.c 1.2 */
  590. /* 3.0 SID # 1.2 */
  591. /*LINTLIBRARY*/
  592. /*
  593. * uses strpbrk and strspn to break string into tokens on
  594. * sequentially subsequent calls. returns NULL when no
  595. * non-separator characters remain.
  596. * `subsequent' calls are calls with first argument NULL.
  597. */
  598. extern int strspn();
  599. extern char *strpbrk();
  600. char *
  601. strtok(string, sepset)
  602. char *string, *sepset;
  603. {
  604. register char *p, *q, *r;
  605. static char *savept;
  606. /*first or subsequent call*/
  607. p = (string == (char*)0)? savept: string;
  608. if(p == 0) /* return if no tokens remaining */
  609. return((char*)0);
  610. q = p + strspn(p, sepset); /* skip leading separators */
  611. if(*q == '\0') /* return if no tokens remaining */
  612. return((char*)0);
  613. if((r = strpbrk(q, sepset)) == (char*)0) /* move past token */
  614. savept = 0; /* indicate this is last token */
  615. else {
  616. *r = '\0';
  617. savept = ++r;
  618. }
  619. return(q);
  620. }
  621. #endif
  622. /*****************************************************************************/
  623. #ifdef DKHOST
  624. #ifndef DKSTREAMS
  625. short dkrmode[3] = {DKR_TIME, 0, 0};
  626. #endif
  627. dkhost_connect()
  628. {
  629. int ofd; /* for saving and restoring stderr */
  630. int dfd;
  631. int retrytime = 5;
  632. /*
  633. *
  634. * Tries to connect to a Datakit destination. The extra stuff I've added to save
  635. * and later restore stderr is primarily for our spooling setup at Murray Hill.
  636. * postio is usually called with stderr directed to a file that will be returned
  637. * to the user when the job finishes printing. Problems encountered by dkdial(),
  638. * like busy messages, go to stderr but don't belong in the user's mail. They'll
  639. * be temporarily directed to the log file. After we've connected stderr will be
  640. * restored.
  641. *
  642. */
  643. if ( *line == '\0' )
  644. error(FATAL, "incomplete Datakit line");
  645. if ( fp_log != NULL && fp_log != stderr ) { /* redirect dkdial errors */
  646. ofd = dup(2);
  647. close(2);
  648. dup(fileno(fp_log));
  649. } /* End if */
  650. while ( (dfd = ttyi = dkdial(line)) < 0 ) {
  651. if ( retrytime < 0 )
  652. error(FATAL, "can't connect to %s", line);
  653. sleep(retrytime++);
  654. if ( retrytime > 60 )
  655. retrytime = 60;
  656. } /* End while */
  657. if ( fp_log != NULL && fp_log != stderr ) { /* restore stderr */
  658. close(2);
  659. dup(ofd);
  660. close(ofd);
  661. } /* End if */
  662. #ifndef DKSTREAMS
  663. if ( ioctl(ttyi, DIOCRMODE, dkrmode) == -1 )
  664. error(FATAL, "ioctl error - DIOCRMODE");
  665. #ifdef DIOURPWD
  666. if ( window_size > 0 ) {
  667. short dkparm[3];
  668. dkparm[0] = dkminor(ttyi);
  669. dkparm[1] = 1;
  670. dkparm[2] = window_size;
  671. if ( ioctl(ttyi, DIOURPWD, dkparm) < 0 || ioctl(ttyi, DIOCFLUSH, 0) < 0 )
  672. error(NON_FATAL, "WSA failed");
  673. } /* End if */
  674. #endif
  675. line = dtnamer(dkminor(ttyi));
  676. if ( (ttyi = open(line, O_RDWR)) == -1 )
  677. error(FATAL, "can't open %s", line);
  678. close(dfd);
  679. #endif
  680. } /* End of dkhost_connect */
  681. #endif
  682. /*****************************************************************************/