home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume07 / pt < prev    next >
Encoding:
Internet Message Format  |  1991-08-27  |  18.1 KB

  1. From decwrl!sun-barr!cs.utexas.edu!uunet!allbery Thu Aug  3 08:51:32 PDT 1989
  2. Article 998 of comp.sources.misc:
  3. Path: decwrl!sun-barr!cs.utexas.edu!uunet!allbery
  4. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5. Newsgroups: comp.sources.misc
  6. Subject: v07i106: pt - show process family tree
  7. Message-ID: <61721@uunet.UU.NET>
  8. Date: 28 Jul 89 01:22:32 GMT
  9. Sender: allbery@uunet.UU.NET
  10. Reply-To: bauer@loligo.cc.fsu.edu (Jeff Bauer)
  11. Organization: Florida State University
  12. Lines: 777
  13. Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  14.  
  15. Posting-number: Volume 7, Issue 106
  16. Submitted-by: bauer@loligo.cc.fsu.edu (Jeff Bauer)
  17. Archive-name: pt
  18.  
  19. Here's a simple utility that displays the hierarchy of the process
  20. structure on a UNIX system.  I must admit, however, that "ps" output
  21. on System V is cleaner in terms of white space between columns
  22. than bsd systems and "pt" does a better job there.
  23.  
  24. Just delete everything above and include the "cut here" line and
  25. run it through "sh".
  26.  
  27.                 -- Jeff Bauer
  28.  
  29. -- cut here -- cut here -- cut here -- cut here -- cut here --
  30. #!/bin/sh
  31. # shar:    Shell Archiver
  32. #    Run the following text with /bin/sh to create:
  33. #    Makefile
  34. #    pt.1
  35. #    pt.1.cat
  36. #    pt.c
  37. sed 's/^X//' << 'SHAR_EOF' > Makefile
  38. X#
  39. X# Comment out the next line if you are building for System V
  40. X#
  41. XDEFINES=-DBSD
  42. XCFLAGS=-O
  43. X
  44. Xpt:    pt.c
  45. X    $(CC) $@.c -o $@ $(CFLAGS) $(DEFINES)
  46. SHAR_EOF
  47. sed 's/^X//' << 'SHAR_EOF' > pt.1
  48. X.TH PT 1
  49. X.SH NAME
  50. X\fBpt\fR \- display process family tree
  51. X.SH USAGE
  52. X.B pt [-a] [user]
  53. X.SH DESCRIPTION
  54. XThe 
  55. X.I pt
  56. Xcommand is a convenient alternative to using ps(1) to display a list
  57. Xof user processes.  Instead of showing a list of processes in the order
  58. Xthat they appear in the system process table,
  59. X.I pt
  60. Xdisplays processes in order of their family hierarchy.  The PID of
  61. Xchildren processes are indented to show the relationship between a
  62. Xparent and child process.
  63. X.sp
  64. XWith no parameters specified,
  65. X.I pt
  66. Xwill display only those processes not owned by "root".  If
  67. X.I \-a
  68. Xis specified,
  69. X.I pt
  70. Xwill display all processes.  If
  71. X.I user
  72. Xis specified,
  73. X.I pt
  74. Xwill display only processes owned by the user name specified.
  75. X.sp
  76. XThe column headings are somewhat self-explanatory; for further
  77. Xdetails see ps(1).
  78. X.SH EXAMPLE
  79. X.sp
  80. X$ pt carr
  81. X.br
  82. XPID                  User     Time    Pages  S  Command
  83. X.br
  84. X 8618                carr     0:00        8 (S) -ksh
  85. X.br
  86. X  8724               carr     0:00        8 (S) -ksh
  87. X.br
  88. X   8756              carr    16:13      479 (R) vlad6
  89. X.SH CAVEATS
  90. XWhen a user name is specified on the command line sometimes
  91. X.I pt
  92. Xcannot determine the correct lineage of a process.  Any of these
  93. Xorphan processes will appear under the heading of "Orphans" on
  94. Xthe output.
  95. X.sp
  96. XSince
  97. X.I pt
  98. Xreally is a filter from a forked-off ps(1) sometimes the parsing of
  99. Xthe output from ps(1) fails and the fields get garbled.
  100. X.SH SEE ALSO
  101. X.BR ps(1).
  102. SHAR_EOF
  103. sed 's/^X//' << 'SHAR_EOF' > pt.1.cat
  104. XPT(1)                     USER COMMANDS                     PT(1)
  105. X
  106. X
  107. X
  108. XNAME
  109. X     pt - display process family tree
  110. X
  111. XUSAGE
  112. X     pt [-a] [user]
  113. X
  114. XDESCRIPTION
  115. X     The _p_t command is a convenient alternative to using ps(1) to
  116. X     display a list of user processes.  Instead of showing a list
  117. X     of processes in the order that they  appear  in  the  system
  118. X     process  table, _p_t displays processes in order of their fam-
  119. X     ily hierarchy.  The PID of children processes  are  indented
  120. X     to show the relationship between a parent and child process.
  121. X
  122. X     With no parameters specified, _p_t  will  display  only  those
  123. X     processes  not owned by "root".  If -_a is specified, _p_t will
  124. X     display all  processes.   If  _u_s_e_r  is  specified,  _p_t  will
  125. X     display only processes owned by the user name specified.
  126. X
  127. X     The  column  headings  are  somewhat  self-explanatory;  for
  128. X     further details see ps(1).
  129. X
  130. XEXAMPLE
  131. X     $ pt carr
  132. X     PID                  User     Time    Pages  S  Command
  133. X      8618                carr     0:00        8 (S) -ksh
  134. X       8724               carr     0:00        8 (S) -ksh
  135. X        8756              carr    16:13      479 (R) vlad6
  136. X
  137. XCAVEATS
  138. X     When a user name is specified on the command line  sometimes
  139. X     _p_t  cannot  determine the correct lineage of a process.  Any
  140. X     of these orphan processes will appear under the  heading  of
  141. X     "Orphans" on the output.
  142. X
  143. X     Since _p_t really is a filter from a  forked-off  ps(1)  some-
  144. X     times  the  parsing  of  the output from ps(1) fails and the
  145. X     fields get garbled.
  146. X
  147. XSEE ALSO
  148. X     ps(1).
  149. SHAR_EOF
  150. sed 's/^X//' << 'SHAR_EOF' > pt.c
  151. X/*
  152. X    pt.c    - show process family tree
  153. X
  154. X    pt [-a] [user]
  155. X
  156. X    Default compilation is for System V UNIX.
  157. X    To compile for a bsd system try :
  158. X
  159. X    cc pt.c -o pt -O -DBSD
  160. X                            */
  161. X
  162. X#include <stdio.h>
  163. X#include <fcntl.h>
  164. X#include <string.h>
  165. X#ifdef    BSD
  166. X#include <pwd.h>
  167. X#include <ctype.h>
  168. X#endif    BSD
  169. X
  170. X#define    MAXLINE    256
  171. X#define    MYBUFSZ    256
  172. X#define    STDIN    0
  173. X#define    STDOUT    1
  174. X#define    STDERR    2
  175. X
  176. Xchar line[MAXLINE], token[MAXLINE];
  177. Xint firstr, cur_char, cur_row, cur_col;
  178. X
  179. X#define    TRUE    1
  180. X#define    FALSE    0
  181. X#define    UNDEF    2
  182. X
  183. Xstruct psl {
  184. X    char state[8];        /* S */
  185. X    char user[9];        /* UID */
  186. X    unsigned int pid;    /* PID */
  187. X    unsigned int ppid;    /* PPID */
  188. X    unsigned int pages;    /* SZ */
  189. X    char time[12];        /* TIME */
  190. X    char verb[32];        /* COMD */
  191. X};
  192. X
  193. Xstruct plist {
  194. X    struct psl cp;
  195. X    struct plist *s;        /* sibling */
  196. X    struct plist *c;        /* child */
  197. X};
  198. X
  199. Xstruct psl cp;
  200. Xstruct plist *proot;
  201. Xstruct plist *orphans;
  202. Xint orphcnt;
  203. Xint showroot = FALSE;
  204. X#ifdef    BSD
  205. Xstruct passwd *pe;
  206. Xextern int errno;
  207. X#endif    BSD
  208. X
  209. Xextern char *malloc();
  210. Xvoid strcpy2(), cp_plist(), pprint();
  211. Xint pinsert();
  212. Xstruct plist *pfind();
  213. X
  214. Xvoid main(argc, argv)
  215. Xint argc;
  216. Xchar **argv;
  217. X{
  218. X    int gls;
  219. X    int pfds[2];
  220. X    char who[9];
  221. X    int slen, wsp;
  222. X    char tbuf[32], tbuf2[32];
  223. X#ifdef    BSD
  224. X    char d1[32], d2[32], d3[32], d4[32], d5[32], d6[32], d7[32];
  225. X#endif
  226. X    struct plist *child;
  227. X    int fostered;
  228. X    int offset;
  229. X    int adopted;
  230. X    int i, j;
  231. X
  232. X    if (argc == 1) who[0] = '\0';
  233. X
  234. X    while (argc--) {
  235. X      if (argc != 0) {
  236. X        if (strcmp(argv[argc], "-a") == 0)
  237. X          showroot = TRUE;
  238. X        else
  239. X          strcpy2(who, argv[argc], 8);
  240. X      }
  241. X    }
  242. X    if (argc > 3) {
  243. X      fprintf(stderr,"Usage : %s [-a] [user]\n", argv[0]);
  244. X      exit(1);
  245. X    }
  246. X    if (strcmp(who, "root") == 0)
  247. X      showroot = TRUE;
  248. X
  249. X    orphcnt = 0;
  250. X
  251. X    if (pipe(pfds) < 0) {
  252. X        perror("pipe");
  253. X        exit(1);
  254. X    }
  255. X
  256. X    if (fork() == 0) {        /* BEGIN child processing */
  257. X      if (close(STDOUT) < 0) {    /* release fd 1 */
  258. X        perror("close1");
  259. X        exit(1);
  260. X      }
  261. X      if (dup(pfds[1]) < 0) {    /* re-use fd 1 */
  262. X        perror("dup1");
  263. X        exit(1);
  264. X      }
  265. X      if (close(pfds[1]) < 0) {
  266. X        perror("close2");
  267. X        exit(1);
  268. X      }
  269. X      if (close(pfds[0]) < 0) {
  270. X        perror("close3");
  271. X        exit(1);
  272. X      }
  273. X      if (who[0] == '\0')
  274. X#ifdef    BSD
  275. X        execl("/bin/ps","ps","-axlw",0);
  276. X#else
  277. X        execl("/bin/ps","ps","-elf",0);
  278. X#endif    BSD
  279. X      else 
  280. X#ifdef    BSD
  281. X        execl("/bin/ps","ps","-axlw",0);    /* no single-user filter on bsd "ps" */
  282. X#else
  283. X        execl("/bin/ps","ps","-u",who,"-lf",0);
  284. X#endif    BSD
  285. X    }                /* END child processing */
  286. X
  287. X    if (close(STDIN) < 0) {        /* release fd 0 */
  288. X      perror("close4");
  289. X      exit(1);
  290. X    }
  291. X    if (dup(pfds[0]) < 0) {        /* re-use fd 0 */
  292. X      perror("dup2");
  293. X      exit(1);
  294. X    }
  295. X    if (close(pfds[0]) < 0) {
  296. X      perror("close5");
  297. X      exit(1);
  298. X    }
  299. X    if (close(pfds[1]) < 0) {
  300. X      perror("close6");
  301. X      exit(1);
  302. X    }
  303. X
  304. X    firstr = TRUE;
  305. X    cur_row = 0;
  306. X    while ((gls = getline(STDIN, line, MAXLINE)) >= 0) {
  307. X      if (gls == -2) break;
  308. X      cur_char = 0;
  309. X      cur_col = 0;
  310. X      offset = FALSE;
  311. X#ifdef    BSD
  312. X      d7[0] = '\0';
  313. X#endif    BSD
  314. X      while (get_token(line, token, MAXLINE, &wsp) >= 0) {
  315. X        if (cur_row > 0) {        /* skip column headings */
  316. X          switch (cur_col) {
  317. X#ifdef    BSD
  318. X        case 0 :
  319. X          if (((wsp > 0) && (strlen(token) > 5)) ||
  320. X            ((wsp == 0) && (strlen(token) > 10))) {
  321. X            j = 0;
  322. X            for (i = (7 - wsp); i < strlen(token); i++)
  323. X              tbuf[j++] = token[i];
  324. X            tbuf[j+1] = '\0';
  325. X            strcpy(token, tbuf);
  326. X            cur_col += 1;
  327. X            sscanf(token, "%d", &i);
  328. X            if ((pe = getpwuid(i)) != NULL)
  329. X              strcpy2(cp.user, pe->pw_name, 8);
  330. X            else {
  331. X              strcpy2(cp.user, "(bogus)", 8);
  332. X              fprintf(stderr,"1: Checking UID %d : ",i);
  333. X              perror("getpwuid");
  334. X            }
  335. X          }
  336. X          else if ((wsp == 6) && (strlen(token) > 1)) {
  337. X            cur_col += 1;
  338. X            sscanf(token, "%d", &i);
  339. X            if ((pe = getpwuid(i)) != NULL)
  340. X              strcpy2(cp.user, pe->pw_name, 8);
  341. X            else {
  342. X              strcpy2(cp.user, "(bogus)", 8);
  343. X              fprintf(stderr,"2: Checking UID %d : ",i);
  344. X              perror("getpwuid");
  345. X            }
  346. X          }
  347. X          break;      
  348. X        case 1 :
  349. X          sscanf(token, "%d", &i);
  350. X          if ((pe = getpwuid(i)) != NULL)
  351. X            strcpy2(cp.user, pe->pw_name, 8);
  352. X          else {
  353. X            strcpy2(cp.user, "(bogus)", 8);
  354. X            fprintf(stderr,"3: Checking UID %d : ",i);
  355. X            perror("getpwuid");
  356. X          }        
  357. X          break;
  358. X        case 2 :
  359. X          sscanf(token, "%d", &cp.pid);
  360. X          break;
  361. X        case 3 :
  362. X          sscanf(token, "%d", &cp.ppid);
  363. X          break;
  364. X        case 7 :
  365. X          if (strlen(token) > 4)
  366. X            offset = TRUE;
  367. X          break;
  368. X        case 8 :
  369. X          if (offset == TRUE) {
  370. X            strcpy2(d1, token, 32);
  371. X          }
  372. X          break;
  373. X        case 9 :
  374. X          if (offset == TRUE) {
  375. X            strcpy2(d2, token, 32);
  376. X          }
  377. X          else {
  378. X            strcpy2(d1, token, 32);
  379. X          }        
  380. X          break;
  381. X        case 10 :
  382. X          if (offset == TRUE) {
  383. X            strcpy2(d3,token, 32);
  384. X          }
  385. X          else {
  386. X            strcpy2(d2, token, 32);
  387. X          }        
  388. X          break;
  389. X        case 11 :
  390. X          if (offset == TRUE) {
  391. X            strcpy(d4, token, 32);
  392. X          }
  393. X          else {
  394. X            strcpy2(d3, token, 32);
  395. X          }
  396. X          break;
  397. X        case 12 :
  398. X          if (offset == TRUE) {
  399. X            strcpy2(d5, token, 32);
  400. X          }
  401. X          else {
  402. X            strcpy2(d4, token, 32);
  403. X          }
  404. X          break;
  405. X        case 13 :
  406. X          if (offset == TRUE) { 
  407. X            strcpy2(d6, token, 32);
  408. X          }
  409. X          else {
  410. X            strcpy2(d5, token, 32);
  411. X          }
  412. X          break;
  413. X        case 14 :
  414. X          if (offset == TRUE) {
  415. X            strcpy2(d7, token, 32);
  416. X          }
  417. X          else {
  418. X            strcpy2(d6, token, 32);
  419. X          }
  420. X          break;
  421. X#else
  422. X        case 1 :
  423. X          cp.state[0] = token[0];
  424. X          cp.state[1] = '\0';
  425. X          if (strlen(token) > 1) {
  426. X            strcpy2(cp.user, (token+1), 8);
  427. X            cur_col += 1;
  428. X          }
  429. X          if ((cp.state[0] == 'R') || (cp.state[0] == 'O'))
  430. X            offset = TRUE;    /* "WCHAN" is empty */
  431. X          break;
  432. X        case 2 :
  433. X          strcpy2(cp.user, token, 8);
  434. X          break;
  435. X        case 3 :
  436. X          sscanf(token, "%d", &cp.pid);
  437. X          break;
  438. X        case 4 :
  439. X          sscanf(token, "%d", &cp.ppid);
  440. X          break;
  441. X        case 9 :
  442. X          if (cp.state[0] == 'Z') {
  443. X            cp.pages = 0;
  444. X            break;
  445. X          }
  446. X          strcpy(tbuf,token);
  447. X          if ((slen = strlen(token)) > 9 ) {
  448. X            strcpy2(tbuf, token, (slen-9));
  449. X            cur_col += 1;
  450. X          }
  451. X          sscanf(tbuf, "%d", &cp.pages);
  452. X          break;
  453. X        case 12 :
  454. X          if (offset == TRUE) {
  455. X            strcpy2(cp.time, token, 12);
  456. X          }
  457. X          break;
  458. X        case 13 :
  459. X          if (offset == TRUE) {
  460. X            strcpy2(cp.verb, token, 32);
  461. X          }
  462. X          else {
  463. X            strcpy2(cp.time, token, 12);
  464. X          }
  465. X          strcpy2(tbuf2, token, 12);
  466. X          break;
  467. X        case 14 :
  468. X          if (offset == FALSE) {
  469. X            strcpy2(cp.verb, token, 32);
  470. X          }
  471. X          break;
  472. X#endif    BSD
  473. X          }
  474. X          cur_col += 1;
  475. X        }
  476. X      }
  477. X#ifdef    BSD
  478. X    
  479. X      /* Sigh... */
  480. X
  481. X      if (isupper(d2[0]) || (d2[0] == 'p')) {
  482. X        strcpy(cp.state, d2);
  483. X        strcpy(cp.time, d4);
  484. X        strcpy(cp.verb, d5);
  485. X      }
  486. X      else {
  487. X        strcpy(cp.state, d3);
  488. X        strcpy(cp.time, d5);
  489. X        strcpy(cp.verb, d6);
  490. X      }
  491. X
  492. X#endif    BSD
  493. X      if (cur_row > 0) {
  494. X#ifdef    BSD
  495. X        if (who[0] == '\0')
  496. X          pinsert(&cp, TRUE);
  497. X        else
  498. X          if (strcmp(cp.user, who) == 0)
  499. X            pinsert(&cp, TRUE);
  500. X#else
  501. X        pinsert(&cp, TRUE);
  502. X#endif    BSD
  503. X      }
  504. X      cur_row += 1;
  505. X    }
  506. X    wait(0);
  507. X
  508. X    /* Place orphans into their foster homes */
  509. X
  510. X    fostered = 0;
  511. X
  512. X    while (orphcnt != fostered) {
  513. X
  514. X      adopted = FALSE;
  515. X
  516. X      for (child = orphans; child != NULL; child = child->s) {
  517. X        if (strcmp(child->cp.state, "HOME") != 0) {
  518. X          if (pinsert(&child->cp, FALSE) == TRUE) {
  519. X        strcpy(child->cp.state, "HOME");
  520. X            fostered += 1;
  521. X        adopted = TRUE;
  522. X          }
  523. X        }
  524. X      }
  525. X      if (adopted == FALSE) {
  526. X        break;
  527. X      }
  528. X    }
  529. X    printf("PID\t\t\t    User     Time    Pages  S  Command\n");
  530. X    pprint(proot, 0, FALSE);
  531. X    if (orphcnt != fostered) {
  532. X      printf("Orphans :\n");
  533. X      printf("PID (PPID)\t\t    User     Time    Pages  S  Command\n");
  534. X      pprint(orphans, 0, TRUE);
  535. X    }
  536. X}
  537. X
  538. Xint pinsert(cp, adopt)        /* TRUE = info inserted; FALSE = info orphaned */
  539. Xstruct psl *cp;
  540. Xint adopt;            /* TRUE = add orphans to orphan list */
  541. X{
  542. X    struct plist *parent, *sibling;
  543. X    int iflag;
  544. X
  545. X    iflag = TRUE;
  546. X    if (proot == NULL) {    /* call this one root for now */
  547. X      if ((proot = (struct plist *) malloc(sizeof(struct plist))) == NULL) {
  548. X        fprintf(stderr,"malloc failed\n");
  549. X        exit(1);
  550. X      }
  551. X      cp_plist(proot, cp);
  552. X    }
  553. X    else {            /* find parent; traverse sibling list & insert */
  554. X      if ((parent = pfind(proot, cp->ppid)) == NULL) {    /* no parent yet */
  555. X        iflag = FALSE;
  556. X        if (adopt == TRUE) {
  557. X          orphcnt += 1;
  558. X          if (orphans == NULL) {
  559. X            if ((orphans = (struct plist *) malloc(sizeof(struct plist))) == NULL) {
  560. X              fprintf(stderr,"malloc failed\n");
  561. X              exit(1);
  562. X            }
  563. X            cp_plist(orphans, cp);
  564. X          }
  565. X          else {            /* chain orphans together (heartless!) */
  566. X            for (sibling = orphans; sibling->s != NULL; sibling = sibling->s);
  567. X            if ((sibling->s = (struct plist *) malloc(sizeof(struct plist))) == NULL) {
  568. X              fprintf(stderr,"malloc failed\n");
  569. X              exit(1);
  570. X            }
  571. X            cp_plist(sibling->s, cp);
  572. X          }
  573. X        }
  574. X      }
  575. X      else {            /* parent exists */
  576. X        if (parent->c == NULL) {    /* first child */
  577. X          if ((parent->c = (struct plist *) malloc(sizeof(struct plist))) == NULL) {
  578. X            fprintf(stderr,"malloc failed\n");
  579. X            exit(1);
  580. X          }
  581. X          cp_plist(parent->c, cp);
  582. X        }
  583. X        else {            /* siblings exist */
  584. X          sibling = parent->c;
  585. X          while (sibling->s != NULL) sibling = sibling->s;
  586. X          if ((sibling->s = (struct plist *) malloc(sizeof(struct plist))) == NULL) {
  587. X            fprintf(stderr,"malloc failed\n");
  588. X            exit(1);
  589. X          }
  590. X          cp_plist(sibling->s, cp);
  591. X        }
  592. X      }
  593. X    }
  594. X    return(iflag);
  595. X}
  596. X
  597. Xstruct plist *pfind(cp, ppid)
  598. Xstruct plist *cp;
  599. Xint ppid;
  600. X{
  601. X    struct plist *p;
  602. X
  603. X    if (cp == NULL) return(NULL);
  604. X    else if (cp->cp.pid == ppid) return(cp);
  605. X    else {
  606. X      if ((p = pfind(cp->c, ppid)) == NULL)
  607. X        return(pfind(cp->s, ppid));
  608. X      else
  609. X        return(p);
  610. X    }
  611. X}
  612. X
  613. Xvoid pprint(cp, cnt, orphflg)
  614. Xstruct plist *cp;
  615. Xint cnt, orphflg;
  616. X{
  617. X    int i, j;
  618. X    char buf[16];
  619. X
  620. X    if (cp == NULL) return;
  621. X
  622. X    if (strcmp(cp->cp.state, "HOME") != 0) {
  623. X      if (!((showroot == FALSE) && (strcmp(cp->cp.user, "root") == 0))) {
  624. X        if (orphflg == TRUE) {
  625. X#ifdef    BSD
  626. X          sprintf(buf, "%d (%d)",cp->cp.pid, cp->cp.ppid);
  627. X          j = strlen(buf);
  628. X#else
  629. X          j = sprintf(buf, "%d (%d)",cp->cp.pid, cp->cp.ppid);
  630. X#endif    BSD
  631. X        }
  632. X        else {
  633. X#ifdef    BSD
  634. X          sprintf(buf, "%d", cp->cp.pid);
  635. X          j = strlen(buf);
  636. X#else
  637. X          j = sprintf(buf, "%d", cp->cp.pid);
  638. X#endif    BSD
  639. X        }
  640. X        for (i = 0; i < cnt; i++) printf(" ");
  641. X        printf(" %s", buf);
  642. X        for (i = 0; i < (3-(((cnt*1)+j+1)/8)); i++) printf("\t");
  643. X        printf("%8s %8s %8d (%s) %s\n", cp->cp.user, cp->cp.time,
  644. X          cp->cp.pages, cp->cp.state, cp->cp.verb);
  645. X      }
  646. X    }
  647. X
  648. X    pprint(cp->c, cnt+1, orphflg);
  649. X    pprint(cp->s, cnt, orphflg);
  650. X}
  651. X
  652. Xvoid cp_plist(pto, pfrom)
  653. Xstruct plist *pto;
  654. Xstruct psl *pfrom;
  655. X{
  656. X    strcpy(pto->cp.state, pfrom->state);
  657. X    strcpy(pto->cp.user, pfrom->user);
  658. X    pto->cp.pid = pfrom->pid;
  659. X    pto->cp.ppid = pfrom->ppid;
  660. X    pto->cp.pages = pfrom->pages;
  661. X    strcpy(pto->cp.time, pfrom->time);
  662. X    strcpy(pto->cp.verb, pfrom->verb);
  663. X    pto->c = pto->s = NULL;
  664. X}
  665. X
  666. Xint getline(fd,buf,max)
  667. Xint fd;
  668. Xchar *buf;
  669. Xint max;
  670. X
  671. X/*
  672. X    getline(fd, buffer, max)
  673. X
  674. X    Get a line from file *fd* up to *max* bytes into *buffer*.
  675. X    Return 0 if OK, -1 if hit EOF, -2 if first read is NULL,
  676. X    -3 if read failed.
  677. X                                */
  678. X
  679. X{
  680. X    static char mybuf[MYBUFSZ];    /* internal buffer */
  681. X    static int myend = 0;        /* # bytes in mybuf */
  682. X    static int mycnt = 0;        /* # bytes already scanned */
  683. X    static char *curline = NULL;    /* beginning of current line to get */
  684. X    char *p, lastc;
  685. X    int nbytes;
  686. X
  687. X    if (firstr == TRUE) curline = NULL;
  688. X
  689. X    if (curline == NULL) {    /* empty buffer */
  690. X      if ((myend = read(fd, mybuf, MYBUFSZ)) < 0) {
  691. X        perror("read");
  692. X        return(-3);
  693. X      }
  694. X      curline = mybuf;        /* new buffer filled */
  695. X      mycnt = 0;
  696. X    }
  697. X
  698. X    if ((myend == 0) && firstr) {    /* first read hit EOF (empty file) */
  699. X      *buf = '\0';
  700. X      return(-2);
  701. X    }
  702. X
  703. X    if (myend == 0) {        /* later read hit EOF */
  704. X      *buf = '\0';
  705. X      return(-1);
  706. X    }
  707. X
  708. X    firstr = FALSE;
  709. X
  710. X    p = curline;
  711. X    nbytes = 0;
  712. X
  713. X    read_loop:
  714. X
  715. X    while ((*p != '\n') && (mycnt < myend) && (nbytes <= max)) {
  716. X      *buf++ = *p++;
  717. X      mycnt += 1;
  718. X      nbytes += 1;
  719. X    }
  720. X    lastc = *p;
  721. X    p += 1;
  722. X    mycnt += 1;
  723. X
  724. X    if ((mycnt >= myend) && (lastc != '\n')) {
  725. X      if ((myend = read(fd, mybuf, MYBUFSZ)) < 0) {
  726. X        perror("read");
  727. X        return(-3);
  728. X      }
  729. X      p = curline = mybuf;
  730. X      lastc = *p;
  731. X      mycnt = 0;
  732. X    }
  733. X    if ((mycnt != myend) && (lastc != '\n')) goto read_loop;
  734. X
  735. X    *buf += 1;
  736. X    *buf = '\0';
  737. X    curline = p;    /* set for next *getline* call */
  738. X
  739. X    if (mycnt >= myend)
  740. X      curline = NULL;    /* reached end of buffer */
  741. X
  742. X    return(0);
  743. X}
  744. X
  745. Xint get_token(line, token, max, wsp)    /* return 0 = token, -1 = no tokens left on line */
  746. Xchar *line, *token;
  747. Xint *wsp;                /* # of white spaces preceding token */
  748. Xint max;
  749. X{
  750. X    int i, j;
  751. X
  752. X    i = cur_char;
  753. X    j = 0;
  754. X    *wsp = 0;
  755. X
  756. X    if ((i >= (max-1)) || (line[i] == '\0')) {
  757. X      *token = '\0';
  758. X      return(-1);
  759. X    }
  760. X
  761. X    while((line[i] == ' ') || (line[i] == '\t')) {
  762. X      i++;
  763. X      *(wsp)++;
  764. X    }
  765. X
  766. X    while ((line[i] != ' ') && (line[i] != '\t') && (line[i] != '\n')
  767. X        && (line[i] != '\r') && (line[i] != '\0'))
  768. X      token[j++] = line[i++];
  769. X
  770. X    token[j] = '\0';
  771. X
  772. X    if (line[i] != '\0') cur_char = i + 1;
  773. X    else cur_char = i;
  774. X    return(0);
  775. X}
  776. X
  777. Xvoid strcpy2(dst, src, max)
  778. Xchar *dst, *src;
  779. Xint max;
  780. X{
  781. X    int i;
  782. X
  783. X    i = 0;
  784. X    while ((src[i] != ' ') && (i < max) && (src[i] != '\0')) {
  785. X      dst[i] = src[i];
  786. X      i += 1;
  787. X    }
  788. X    dst[i] = '\0';
  789. X}
  790. SHAR_EOF
  791. exit
  792.  
  793.  
  794.