cae7291

shpipe v2

Mar 2nd, 2016
1,848
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 59.84 KB | None | 0 0
  1. #!/usr/bin/perl
  2. # shpipe -- self expanding paste archive
  3. #
  4. # CREATED 2016/03/03-00:01:50 UTC
  5. #
  6. # INFO shell with pipes
  7. #
  8. # arguments:
  9. # "-h" -- display help
  10. # "-help" -- display help (same as -h)
  11. # "-O<odir>" -- output directory
  12. # "-tail" -- remove subdirectory from individual files
  13. # "-x" -- extract files
  14. #
  15. # "-tab" -- tab control
  16. # 0 -- no change
  17. # 1 -- create tabs from spaces
  18. # 2 -- expand tabs to spaces at beginning of line
  19. # 3 -- expand tabs to spaces everywhere
  20. #
  21. # installation/extraction instructions:
  22. # (1) save this file to /where_ever_you_want
  23. # (2) perl /where_ever_you_want
  24. # (3) if perl not installed, try "yum install perl" [or equiv for your sys]
  25. # and repeat (2)
  26. #
  27. # how to extract manually:
  28. # after the data __DATA__ line there are optional default option lines
  29. #
  30. # each file is preceeded by:
  31. # % <file>
  32. # and the lines after that do _not_ start with "%" are the data for that file
  33. #
  34. # for example:
  35. # % file1
  36. # file1's line 1 ...
  37. # file1's line 2 ...
  38. # ...
  39. # file1's line n...
  40. # % file2
  41. # file2's line 1 ...
  42. # file2's line 2 ...
  43. # ...
  44. # file2's line n...
  45.  
  46. master(@ARGV);
  47. exit(0);
  48.  
  49. # master -- master control
  50. sub master
  51. {
  52. my(@argv) = @_;
  53. my($esc,$bf);
  54. my($otail,$ofile,$xfsrc,$xfdata,$xfdst);
  55. my($lno,$bytot,$bycnt);
  56.  
  57. $pgmfile = $0;
  58. $pgmtail = filetail($pgmfile);
  59.  
  60. select(STDOUT);
  61. $| = 1;
  62.  
  63. select(STDERR);
  64. $| = 1;
  65.  
  66. $esc = "%";
  67.  
  68. open($xfsrc,"<$pgmfile");
  69.  
  70. $xfdata = "joinup::DATA";
  71. $xfdata = \*$xfdata;
  72. $datapos = tell($xfdata);
  73.  
  74. while ($bf = <$xfdata>) {
  75. $bycnt = length($bf);
  76.  
  77. # process separater line
  78. if ($bf =~ s/^$esc\s+//) {
  79. if (defined($otail)) {
  80. printf("%d lines %d chars\n",$lno,$bytot)
  81. unless (defined($opf_lns));
  82. }
  83. else {
  84. optget(\@argv);
  85. if (defined($opt_h)) {
  86. usage($xfsrc);
  87. $opt_x = 0;
  88. }
  89. $opt_tail = 1
  90. if ($opt_O eq "-");
  91. }
  92.  
  93. $otail = optfile($bf);
  94.  
  95. undef($lno);
  96. undef($bytot);
  97.  
  98. {
  99. $ofile = filetail($ofile)
  100. if ($opt_tail);
  101.  
  102. $ofile = $otail;
  103.  
  104. last if ($opt_O eq "-");
  105. last if ($opt_O eq "");
  106. $ofile = "$opt_O/$otail";
  107. }
  108.  
  109. if (defined($opf_lns)) {
  110. printf("%s %s --> %s\n",
  111. $opt_x ? "LNS" : "LN?",$ofile,$opf_lns);
  112. }
  113. else {
  114. printf("%s %s -- ",
  115. $opt_x ? "EXTRACT" : "LIST",$ofile);
  116. }
  117.  
  118. next unless ($opt_x);
  119.  
  120. # always do this to ensure things work if overwrite and type
  121. # [symlink vs file] has changed
  122. unlink($ofile);
  123. close($xfdst);
  124.  
  125. if (defined($opf_lns)) {
  126. next if (symlink($opf_lns,$ofile));
  127. sysfault("$pgmtail: unable to symlink '%s' to '%s' -- $!\n",
  128. $ofile,$opf_lns);
  129. }
  130.  
  131. # open the file
  132. open($xfdst,">$ofile") ||
  133. sysfault("$pgmtail: unable to open '%s' -- $!\n",$ofile);
  134.  
  135. # change permission
  136. if (defined($opf_chmod)) {
  137. $opf_chmod =~ s/^0+//;
  138. $opf_chmod = oct($opf_chmod);
  139. chmod($opf_chmod,$ofile);
  140. }
  141.  
  142. next;
  143. }
  144.  
  145. # handle data line
  146. if (defined($otail)) {
  147. ++$lno;
  148. $bytot += $bycnt;
  149. next unless ($opt_x);
  150. $bf = tabfix($bf)
  151. if ($opt_tab);
  152. print($xfdst $bf);
  153. next;
  154. }
  155.  
  156. # handle default options
  157. if ($bf =~ /^-/) {
  158. chomp($bf);
  159. optget($bf);
  160. next;
  161. }
  162.  
  163. # FIXME/CAE -- this is now junk/bad data
  164. printf("$pgmtail: INFO %s",$bf);
  165. }
  166.  
  167. printf("%d lines %d chars\n",$lno,$bytot)
  168. if (defined($otail));
  169.  
  170. close($xfdst);
  171.  
  172. {
  173. last if ($opt_x);
  174. last if ($opt_h);
  175. printf("$pgmtail: rerun with -h to get help\n");
  176. printf("$pgmtail: rerun with -x to actually extract files\n");
  177. }
  178.  
  179. close($xfsrc);
  180. }
  181.  
  182. # optget -- decode command line options
  183. sub optget
  184. {
  185. my($argv) = @_;
  186.  
  187. $argv = [$argv]
  188. unless (ref($argv));
  189.  
  190. while (1) {
  191. vbqdash($argv);
  192. vbqstrdcd($_,"-h",1,\$opt_h);
  193. vbqstrdcd($_,"-O","-",\$opt_O);
  194. vbqnumdcd($_,"-tab",1,\$opt_tab);
  195. vbqnumdcd($_,"-tail",1,\$opt_tail);
  196. vbqnumdcd($_,"-x",1,\$opt_x);
  197. usage();
  198. }
  199. }
  200.  
  201. # optfile -- decode per-file options
  202. sub optfile
  203. {
  204. my($bf) = @_;
  205. my($otail);
  206.  
  207. chomp($bf);
  208.  
  209. @cmdargv = split(" ",$bf);
  210. $otail = shift(@cmdargv);
  211.  
  212. undef($opf_lns);
  213. undef($opf_chmod);
  214.  
  215. while (1) {
  216. vbqdash(\@cmdargv);
  217. vbqstrdcd($_,"-lns",undef,\$opf_lns);
  218. vbqstrdcd($_,"-chmod","0755",\$opf_chmod);
  219. usage();
  220. }
  221.  
  222. $otail;
  223. }
  224.  
  225. # tabfix -- fix up tabs
  226. sub tabfix
  227. {
  228. my($rhs) = @_;
  229. my($pre);
  230.  
  231. if ($bf =~ s/^(\s+)//) {
  232. $pre = $1;
  233. $pre =~ s/ /\t/g;
  234. $bf = $pre . $bf;
  235. }
  236.  
  237. $bf;
  238. }
  239.  
  240. # sysfault -- output error
  241. sub sysfault
  242. {
  243.  
  244. printf(@_);
  245. exit(1);
  246. }
  247.  
  248. # usage -- show usage
  249. sub usage
  250. {
  251. my($xfsrc) = @_;
  252.  
  253. seek($xfsrc,0,0);
  254.  
  255. while ($bf = <$xfsrc>) {
  256. chomp($bf);
  257. next if ($bf =~ /^#!/);
  258. last unless ($bf =~ s/^# ?//);
  259. print($bf,"\n");
  260. }
  261. }
  262.  
  263.  
  264. sub vbqdash
  265. {
  266. my($ptr) = @_;
  267. my($opt);
  268.  
  269. $opt = $ptr->[0];
  270. last unless ($opt =~ /^-/);
  271.  
  272. shift(@$ptr);
  273. last if ($opt eq "--");
  274.  
  275. $_ = $opt
  276. unless (defined(wantarray));
  277.  
  278. $opt;
  279. }
  280.  
  281. sub vbqnumdcd
  282. {
  283. my($bf,$key,$dft,$var) = @_;
  284.  
  285. if ($bf =~ /^$key(.*)$/) {
  286. my($val) = $1;
  287. $val =~ s/^=//s;
  288.  
  289. $val = $dft
  290. if ($val eq "");
  291. $val += 0;
  292.  
  293. vbqchk($var,"vbqnumdcd");
  294.  
  295. $$var = $val;
  296. next;
  297. }
  298. }
  299.  
  300. sub vbqstrdcd
  301. {
  302. my($bf,$key,$dft,$var) = @_;
  303.  
  304. if ($bf =~ /^$key(.*)$/s) {
  305. my($val) = $1;
  306. $val =~ s/^=//;
  307.  
  308. $val = $dft
  309. if ($val eq "");
  310.  
  311. vbqchk($var,"vbqstrdcd");
  312.  
  313. $$var = $val
  314. if (defined($val));
  315. next;
  316. }
  317. }
  318.  
  319. sub vbqchk
  320. # ptr -- pointer to check
  321. # reason -- reason for call
  322. {
  323. my($ptr,$reason) = @_;
  324. my($typ);
  325. my($ok);
  326.  
  327. if (defined(&blesscore)) {
  328. $typ = blesscore($ptr);
  329. }
  330. else {
  331. $typ = $ptr;
  332. $typ =~ s/[(].+$//;
  333. }
  334.  
  335. if ($reason =~ /^vbqv/) {
  336. $ok = ($typ eq "ARRAY");
  337. }
  338. else {
  339. $ok = ($typ eq "SCALAR");
  340. }
  341.  
  342. unless ($ok) {
  343. $ptr = prtstr($ptr)
  344. if (defined(&prtstr));
  345. vbqfault("!vbqchk: invalid pointer -- ptr=%s reason='%s'\n",
  346. $ptr,$reason);
  347. }
  348. }
  349.  
  350. sub vbqusage
  351. {
  352. my($opt,$reason) = @_;
  353.  
  354. if ($reason =~ s/^!//) {
  355. vbqzprtx("$reason: unknown option -- '%s'\n",$opt);
  356. }
  357. else {
  358. vbqfault("!$reason: unknown option -- '%s'\n",$opt);
  359. }
  360. }
  361.  
  362. sub vbqzprtx
  363. {
  364.  
  365. goto &_zprtx
  366. if (defined(&_zprtx));
  367.  
  368. printf(STDERR @_);
  369. }
  370.  
  371. sub vbqfault
  372. {
  373.  
  374. goto &sysfault
  375. if (defined(&sysfault));
  376.  
  377. vbqzprtx(@_);
  378. exit(1);
  379. }
  380.  
  381. sub filetail
  382. {
  383. my($file) = @_;
  384.  
  385. $file =~ s,.*/,,g;
  386.  
  387. $file;
  388. }
  389.  
  390. package joinup;
  391. __DATA__
  392. -O-
  393. % dlk.c
  394. // shpipe/dlk -- "smart" list "class" for C
  395.  
  396. #include <shpipe.h>
  397.  
  398. // dlhfree -- free list
  399. dlh_p
  400. dlhfree(dlh_p dlh)
  401. {
  402.  
  403. _dlhfree(dlh);
  404. sysfree(dlh);
  405.  
  406. dlh = NULL;
  407.  
  408. return dlh;
  409. }
  410.  
  411. // _dlhfree -- clean list
  412. dlh_p
  413. _dlhfree(dlh_p dlh)
  414. {
  415. dlv_p dlv;
  416. dlk_p dlk;
  417. dlk_p next;
  418.  
  419. dlv = dlh->dlh_dlv;
  420.  
  421. for (dlk = dlh->dlh_head; dlk != NULL; dlk = next) {
  422. next = dlk->dlk_next;
  423. dlv->dlv_free(dlk);
  424. }
  425.  
  426. dlh = NULL;
  427.  
  428. return dlh;
  429. }
  430.  
  431. // dlkpush -- append string to end of list
  432. dlk_p
  433. dlkpush(dlh_p dlh,dlk_p dlk)
  434. {
  435. dlk_p tail;
  436.  
  437. tail = dlh->dlh_tail;
  438.  
  439. dlk->dlk_next = NULL;
  440. dlk->dlk_prev = tail;
  441.  
  442. if (tail != NULL)
  443. tail->dlk_next = dlk;
  444.  
  445. dlh->dlh_tail = dlk;
  446.  
  447. if (dlh->dlh_head == NULL)
  448. dlh->dlh_head = dlk;
  449.  
  450. dlhinc(dlh,1);
  451.  
  452. return dlk;
  453. }
  454.  
  455. // dlhcut -- cut out entry and split list
  456. void
  457. dlhcut(dlh_p dlhlhs,dlh_p dlhrhs,dlk_p dlk)
  458. {
  459. dlk_p prev;
  460. dlk_p next;
  461.  
  462. dbgprt(1,"dlhcut: ENTER\n");
  463.  
  464. dbgexec(1,dlhrhs->dlh_dlv->dlv_show(dlk,"dlhcut"));
  465.  
  466. dbgexec(1,dlhshow(dlhrhs,"dlhrhs/BEF"));
  467.  
  468. prev = dlk->dlk_prev;
  469. next = dlk->dlk_next;
  470.  
  471. // set left side list
  472. dlhlhs->dlh_tail = prev;
  473. if (dlk == dlhrhs->dlh_head)
  474. dlhlhs->dlh_head = NULL;
  475. else
  476. dlhlhs->dlh_head = dlhrhs->dlh_head;
  477.  
  478. // set right side list
  479. dlhrhs->dlh_head = next;
  480. if (dlk == dlhrhs->dlh_tail)
  481. dlhlhs->dlh_tail = NULL;
  482.  
  483. // break sibling links
  484. if (next != NULL)
  485. next->dlk_prev = NULL;
  486. if (prev != NULL)
  487. prev->dlk_next = NULL;
  488.  
  489. // recount the nodes in both lists
  490. #if DLHCNT
  491. dlhlhs->dlh_cnt = 0;
  492. dlhinc(dlhrhs,-1);
  493. for (dlk_p cur = dlhlhs->dlh_head; cur != NULL; cur = cur->dlk_next) {
  494. dlhinc(dlhlhs,1);
  495. dlhinc(dlhrhs,-1);
  496. }
  497. #endif
  498.  
  499. dlk->dlk_prev = NULL;
  500. dlk->dlk_next = NULL;
  501.  
  502. dbgexec(1,dlhshow(dlhrhs,"dlhrhs/AFT"));
  503. dbgexec(1,dlhshow(dlhlhs,"dlhlhs/AFT"));
  504.  
  505. dbgprt(1,"dlhcut: EXIT\n");
  506. }
  507.  
  508. // dlkunlink -- remove item from list
  509. dlk_p
  510. dlkunlink(dlh_p dlh,dlk_p dlk)
  511. {
  512. dlk_p prev;
  513. dlk_p next;
  514.  
  515. prev = dlk->dlk_prev;
  516. next = dlk->dlk_next;
  517.  
  518. dlhinc(dlh,-1);
  519.  
  520. if (prev != NULL)
  521. prev->dlk_next = next;
  522. else
  523. dlh->dlh_head = next;
  524.  
  525. if (next != NULL)
  526. next->dlk_prev = prev;
  527. else
  528. dlh->dlh_tail = prev;
  529.  
  530. dlk->dlk_prev = NULL;
  531. dlk->dlk_next = NULL;
  532.  
  533. return dlk;
  534. }
  535.  
  536. // dlhcnt -- calculate item count
  537. int
  538. dlhcnt(dlh_p dlh)
  539. {
  540. int cnt;
  541.  
  542. #if DLHCNT
  543. cnt = dlh->dlh_cnt;
  544. #else
  545. cnt = 0;
  546. for (dlk_p dlk = dlh->dlh_head; dlk != NULL; dlk = dlk->dlk_next)
  547. cnt += 1;
  548. #endif
  549.  
  550. return cnt;
  551. }
  552.  
  553. // dlhshow -- output a list
  554. void
  555. dlhshow(dlh_p dlh,const char *reason)
  556. {
  557. dlk_p dlk;
  558. dlv_p dlv;
  559.  
  560. _dbgprt("dlhshow: ENTER (from %s)\n",reason);
  561.  
  562. dlv = dlh->dlh_dlv;
  563.  
  564. for (dlk = dlh->dlh_head; dlk != NULL; dlk = dlk->dlk_next) {
  565. _dbgprt("dlhshow: OPT dlk_opt=%s\n",strtgb(opt_tgb,dlk->dlk_opt));
  566. dlv->dlv_show(dlk,reason);
  567. }
  568.  
  569. _dbgprt("dlhshow: EXIT\n");
  570. }
  571. % parse.c
  572. // shpipe/parse -- line parser
  573. //
  574. // NOTE: split on "&" first before ";"
  575.  
  576. #include <shpipe.h>
  577.  
  578. static xcmd_p xcmd; // command list
  579. static xstr_p xstr; // current string under construction
  580. static int stopflg; // stop flag
  581. static int newflg; // 1=create new string
  582.  
  583. #define GETC \
  584. if (stopflg) \
  585. break; \
  586. chr = *parsecur++; \
  587. if (chr == 0) { \
  588. stopflg = 1; \
  589. break; \
  590. }
  591.  
  592. #define PEEKC(_chr) \
  593. if (stopflg) \
  594. break; \
  595. _chr = *parsecur
  596.  
  597. // parseline -- line buffer parser
  598. xcmd_p
  599. parseline(char *buf)
  600. {
  601. int chr;
  602. int c2;
  603.  
  604. parsebuf = buf;
  605. parsecur = buf;
  606. stopflg = 0;
  607.  
  608. xcmd = xcmdnew();
  609. newflg = 1;
  610. xstr = NULL;
  611.  
  612. while (1) {
  613. GETC;
  614.  
  615. //xcmdshow(xcmd,"parseline");
  616.  
  617. if ((chr == ' ') || (chr == '\t')) {
  618. newflg = 1;
  619. continue;
  620. }
  621.  
  622. if (chr == '\\') {
  623. GETC;
  624. parsenew(chr,TOKWORD);
  625. continue;
  626. }
  627.  
  628. switch (chr) {
  629. case '"':
  630. case '\'':
  631. parsequo(chr);
  632. continue;
  633. break;
  634.  
  635. case '>':
  636. case '<':
  637. newflg = 2;
  638. parsenew(chr,TOKSEP);
  639.  
  640. // handle "<<" or ">>"
  641. PEEKC(c2);
  642. if (c2 == chr) {
  643. xstraddchar(xstr,c2);
  644. GETC;
  645. }
  646.  
  647. // handle ">&" or "<&"
  648. PEEKC(c2);
  649. if (c2 == '&') {
  650. xstraddchar(xstr,c2);
  651. GETC;
  652. }
  653.  
  654. continue;
  655. break;
  656.  
  657. case '`':
  658. case '&':
  659. case '|':
  660. case ';':
  661. newflg = 2;
  662. parsenew(chr,TOKSEP);
  663. continue;
  664. break;
  665. }
  666.  
  667. parsenew(chr,TOKWORD);
  668. }
  669.  
  670. return xcmd;
  671. }
  672.  
  673. // parsenew -- add char
  674. void
  675. parsenew(int chr,int type)
  676. {
  677.  
  678. if (newflg > 0) {
  679. newflg -= 1;
  680. xstr = xstrnew();
  681. xstr->xstr_type = type;
  682. xcmdpush(xcmd,xstr);
  683. }
  684.  
  685. if (chr > 0)
  686. xstraddchar(xstr,chr);
  687. }
  688.  
  689. // parsequo -- parse quoted string
  690. void
  691. parsequo(int quo)
  692. {
  693. int chr;
  694. int type;
  695.  
  696. type = (quo == '"') ? TOKQUO2 : TOKQUO1;
  697.  
  698. parsenew(-1,type);
  699.  
  700. //xstraddchar(xstr,quo);
  701.  
  702. while (1) {
  703. GETC;
  704.  
  705. if (chr == quo)
  706. break;
  707.  
  708. xstraddchar(xstr,chr);
  709.  
  710. if (chr == '\\') {
  711. GETC;
  712. xstraddchar(xstr,chr);
  713. continue;
  714. }
  715. }
  716. }
  717.  
  718. // tokmatch1 -- find a given token based on type and prefix value
  719. int
  720. tokmatch1(xstr_p xstr,int type,const char *src)
  721. {
  722. char *dst;
  723. int matchflg;
  724.  
  725. do {
  726. matchflg = 0;
  727.  
  728. if (type != 0) {
  729. if (xstr->xstr_type != type)
  730. break;
  731. }
  732.  
  733. dst = xstrcstr(xstr);
  734. if (dst[0] != src[0])
  735. break;
  736.  
  737. matchflg = 1;
  738. } while (0);
  739.  
  740. return matchflg;
  741. }
  742.  
  743. // tokmatch2 -- find a given token based on type and exact value
  744. int
  745. tokmatch2(xstr_p xstr,int type,const char *src)
  746. {
  747. char *dst;
  748. int matchflg;
  749.  
  750. do {
  751. matchflg = 0;
  752.  
  753. if (type != 0) {
  754. if (xstr->xstr_type != type)
  755. break;
  756. }
  757.  
  758. dst = xstrcstr(xstr);
  759. if (strcmp(dst,src) != 0)
  760. break;
  761.  
  762. matchflg = 1;
  763. } while (0);
  764.  
  765. return matchflg;
  766. }
  767.  
  768. // errprt -- show parsing error
  769. void
  770. errprt(xlst_p xlst,xcmd_p xcmd,xstr_p xstr,const char *fmt,...)
  771. {
  772. va_list ap;
  773. int idx;
  774.  
  775. va_start(ap,fmt);
  776. vfprintf(stderr,fmt,ap);
  777. va_end(ap);
  778.  
  779. ++errstop;
  780.  
  781. if (xlst != NULL)
  782. xlst->xlst_opt |= OPTNOGO;
  783.  
  784. if (xcmd != NULL)
  785. xcmd->xcmd_opt |= OPTNOGO;
  786.  
  787. if (xstr != NULL) {
  788. fprintf(stderr,">>%s\n",xstr->xstr_bufptr);
  789. fputs(">>",stderr);
  790. for (idx = 0; idx < xstr->xstr_bufoff; ++idx)
  791. fputc('-',stderr);
  792. fputs("^\n",stderr);
  793. }
  794. }
  795. % pipe.c
  796. // shpipe/pipe -- pipeline control
  797.  
  798. #include <shpipe.h>
  799.  
  800. // cmdpipefork -- attach pipe to given command in pipeline
  801. int
  802. cmdpipefork(xcmd_p xcmd,u32 popt,int pno,xcmd_p prev)
  803. {
  804. xpipe_p xpipe;
  805. int pipeflg;
  806.  
  807. pipeflg = 0;
  808.  
  809. do {
  810. // command does not use this pipe end
  811. if ((xcmd->xcmd_opt & popt) == 0)
  812. break;
  813.  
  814. // we need the correct pipe struct
  815. if (prev == NULL)
  816. break;
  817. xpipe = &prev->xcmd_xpipe;
  818.  
  819. // duplicate the desired unit on the correct stdin/stdout
  820. dup2(xpipe->xpipe_fd[pno],pno);
  821.  
  822. // get rid of the [now] extraneous unit
  823. CLOSEME(xpipe->xpipe_fd[pno]);
  824.  
  825. // close the side we don't use
  826. pno = ! pno;
  827. CLOSEME(xpipe->xpipe_fd[pno]);
  828.  
  829. pipeflg = 1;
  830. } while (0);
  831.  
  832. return pipeflg;
  833. }
  834.  
  835. // cmdpipeall -- set up piped job
  836. void
  837. cmdpipeall(xcmd_p xcmd)
  838. {
  839. u32 opt;
  840. xstr_p xstr;
  841. xlst_p xlst;
  842.  
  843. dbgprt(1,"cmdpipeall: ENTER\n");
  844.  
  845. dbgexec(1,xcmdshow(xcmd,"cmdpipeall"));
  846.  
  847. // remember the OPTDETACH flag
  848. opt = xcmd->xcmd_opt;
  849.  
  850. xlst = xlstnew();
  851. xlst->xlst_opt |= opt & OPTDETACH;
  852.  
  853. // it's bad if we get "| cat"
  854. xstr = xcmd->xcmd_head;
  855. if (tokmatch2(xstr,TOKSEP,"|"))
  856. errprt(xlst,xcmd,xstr,"cmdpipe: malformed '|' at beginning\n");
  857.  
  858. // it's bad if we get "cat |"
  859. xstr = xcmd->xcmd_tail;
  860. if (tokmatch2(xstr,TOKSEP,"|"))
  861. errprt(xlst,xcmd,xstr,"cmdpipe: malformed '|' at end\n");
  862.  
  863. do {
  864. if (errstop)
  865. break;
  866.  
  867. cmdsplit(xlst,xcmd,TOKSEP,"|",0);
  868.  
  869. // mark all pipe sub-commands as having both input and output pipes
  870. for (xcmd = xlst->xlst_head; xcmd != NULL; xcmd = xcmd->xcmd_next) {
  871. xcmd->xcmd_opt |= OPTIPIPE;
  872. xcmd->xcmd_opt |= OPTOPIPE;
  873. }
  874.  
  875. // first command of pipeline has no input pipe
  876. xcmd = xlst->xlst_head;
  877. xcmd->xcmd_opt &= ~OPTIPIPE;
  878.  
  879. // last command of pipeline has no output pipe
  880. xcmd = xlst->xlst_tail;
  881. xcmd->xcmd_opt &= ~OPTOPIPE;
  882.  
  883. // kick off the parts of the pipe
  884. for (xcmd = xlst->xlst_head; xcmd != NULL; xcmd = xcmd->xcmd_next) {
  885. if (errstop)
  886. break;
  887.  
  888. cmdredall(xcmd);
  889.  
  890. if (xcmd->xcmd_opt & OPTNOGO) {
  891. xlst->xlst_opt |= OPTNOGO;
  892. break;
  893. }
  894. }
  895.  
  896. // don't wait if entire pipeline is detached
  897. if (opt & OPTDETACH)
  898. break;
  899.  
  900. // wait for pipeline to complete
  901. cmdpipewait(xlst);
  902. } while (0);
  903.  
  904. xlstfree(xlst);
  905.  
  906. dbgprt(1,"cmdpipeall: EXIT\n");
  907. }
  908.  
  909. // cmdpipewait -- wait for pipeline to complete
  910. void
  911. cmdpipewait(xlst_p xlst)
  912. {
  913. xcmd_p xcmd;
  914. int expcnt;
  915. pid_t pid;
  916. int status;
  917. int stage;
  918.  
  919. dbgprt(1,"cmdpipewait: ENTER\n");
  920.  
  921. // get number of _active_ pipe stages
  922. expcnt = 0;
  923. for (xcmd = xlst->xlst_head; xcmd != NULL; xcmd = xcmd->xcmd_next) {
  924. if (xcmd->xcmd_pid > 0)
  925. expcnt += 1;
  926. }
  927.  
  928. dbgprt(1,"cmdpipewait: EXPCNT expcnt=%d\n",expcnt);
  929.  
  930. while (expcnt > 0) {
  931. pid = waitpid(0,&status,0);
  932. if (pid < 0)
  933. break;
  934. dbgprt(1,"cmdpipewait: WAITPID status=%8.8X pid=%d\n",status,pid);
  935.  
  936. // find match for just completed process
  937. stage = -1;
  938. for (xcmd = xlst->xlst_head; xcmd != NULL; xcmd = xcmd->xcmd_next) {
  939. ++stage;
  940. if (xcmd->xcmd_pid == pid) {
  941. dbgprt(1,"cmdpipewait: MATCH stage=%d\n",stage);
  942. expcnt -= 1;
  943. xcmd->xcmd_status = status;
  944. xcmd->xcmd_opt |= OPTDONE;
  945. xcmd->xcmd_pid = -1;
  946. break;
  947. }
  948. }
  949. }
  950.  
  951. dbgprt(1,"cmdpipewait: EXIT\n");
  952. }
  953. % red.c
  954. // shpipe/red -- redirection and fork/exec control
  955.  
  956. #include <shpipe.h>
  957.  
  958. // cmdredall -- strip and setup redirections and fork/exec job
  959. void
  960. cmdredall(xcmd_p xcmd)
  961. {
  962.  
  963. dbgprt(1,"cmdredall: ENTER\n");
  964.  
  965. dbgexec(1,xcmdshow(xcmd,"cmdredall"));
  966.  
  967. do {
  968. // split off redirections
  969. cmdredzone(xcmd);
  970. if (errstop)
  971. break;
  972.  
  973. // open the units
  974. cmdredopen(xcmd);
  975. if (errstop)
  976. break;
  977.  
  978. // fork job
  979. cmdredfork(xcmd);
  980. } while (0);
  981.  
  982. dbgprt(1,"cmdredall: EXIT\n");
  983. }
  984.  
  985. // cmdredzone -- strip and setup redirections
  986. void
  987. cmdredzone(xcmd_p xcmd)
  988. {
  989. int redno;
  990. redir_p red;
  991. char *sep;
  992. xstr_p xstr;
  993. u32 popt;
  994.  
  995. dbgprt(1,"cmdredzone: ENTER\n");
  996.  
  997. popt = 0;
  998.  
  999. // split off redirections
  1000. for (redno = 0; redno <= 1; ++redno) {
  1001. if (xcmd->xcmd_opt & OPTNOGO)
  1002. break;
  1003.  
  1004. red = &xcmd->xcmd_redir[redno];
  1005.  
  1006. switch (redno) {
  1007. case 0:
  1008. sep = "<";
  1009. popt = OPTIPIPE;
  1010. break;
  1011.  
  1012. case 1:
  1013. sep = ">";
  1014. popt = OPTOPIPE;
  1015. break;
  1016.  
  1017. default:
  1018. popt = 0;
  1019. break;
  1020. }
  1021.  
  1022. // find the separater
  1023. red->red_sep = xcmdfind1(xcmd,TOKSEP,sep);
  1024. if (red->red_sep == NULL)
  1025. continue;
  1026.  
  1027. // get the filename
  1028. red->red_file = red->red_sep->xstr_next;
  1029. if (red->red_file == NULL) {
  1030. errprt(NULL,xcmd,red->red_sep,
  1031. "cmdredzone: missing filename for '%s'\n",sep);
  1032. break;
  1033. }
  1034.  
  1035. // remove them from the command arguments
  1036. xcmdunlink(xcmd,red->red_sep);
  1037. xcmdunlink(xcmd,red->red_file);
  1038.  
  1039. // check for errors
  1040. xstr = xcmdfind1(xcmd,TOKSEP,sep);
  1041. if (xstr != NULL) {
  1042. errprt(NULL,xcmd,xstr,
  1043. "cmdredzone: duplicate redirection '%s'\n",sep);
  1044. break;
  1045. }
  1046.  
  1047. // check for overlap with pipe
  1048. if (xcmd->xcmd_opt & popt) {
  1049. errprt(NULL,xcmd,xstr,"cmdredzone: pipe overlap '%s'\n",sep);
  1050. break;
  1051. }
  1052. }
  1053.  
  1054. do {
  1055. if (xcmd->xcmd_opt & OPTNOGO)
  1056. break;
  1057.  
  1058. // no child arguments
  1059. if (xcmd->xcmd_head == NULL) {
  1060. errprt(NULL,xcmd,NULL,
  1061. "cmdredzone: no command after redirections\n");
  1062. break;
  1063. }
  1064. } while (0);
  1065.  
  1066. dbgprt(1,"cmdredzone: EXIT\n");
  1067. }
  1068.  
  1069. // cmdredopen -- open redirection units in parent
  1070. void
  1071. cmdredopen(xcmd_p xcmd)
  1072. {
  1073. int redno;
  1074. redir_p red;
  1075. char *sep;
  1076. char *file;
  1077. int opt;
  1078.  
  1079. // we open the units in the parent so we can abort _without_ forking a child
  1080. // if the unit open fails
  1081.  
  1082. dbgprt(1,"cmdredopen: ENTER\n");
  1083.  
  1084. // open the units
  1085. for (redno = 0; redno <= 1; ++redno) {
  1086. if (xcmd->xcmd_opt & OPTNOGO)
  1087. break;
  1088.  
  1089. red = &xcmd->xcmd_redir[redno];
  1090. if (red->red_file == NULL)
  1091. continue;
  1092.  
  1093. file = xstrcstr(red->red_file);
  1094. sep = xstrcstr(red->red_sep);
  1095.  
  1096. switch (redno) {
  1097. case 0: // open stdin
  1098. if (xcmd->xcmd_opt & OPTIPIPE)
  1099. continue;
  1100. red->red_fd = open(file,O_RDONLY);
  1101. break;
  1102.  
  1103. case 1: // open stdout
  1104. if (xcmd->xcmd_opt & OPTIPIPE)
  1105. continue;
  1106. opt = O_WRONLY | O_CREAT;
  1107. if (sep[1] == '>')
  1108. opt |= O_APPEND;
  1109. red->red_fd = open(file,opt,0644);
  1110. break;
  1111. }
  1112.  
  1113. dbgprt(1,"cmdredzone: OPEN redno=%d red_fd=%d file='%s'\n",
  1114. redno,red->red_fd,file);
  1115.  
  1116. if (red->red_fd < 0)
  1117. errprt(NULL,xcmd,red->red_file,
  1118. "cmdredzone: unable to open '%s' -- %s\n",
  1119. file,strerror(errno));
  1120. }
  1121.  
  1122. dbgprt(1,"cmdredopen: EXIT\n");
  1123. }
  1124.  
  1125. // cmdredfork -- fork job
  1126. void
  1127. cmdredfork(xcmd_p xcmd)
  1128. {
  1129. int redno;
  1130. redir_p red;
  1131. int pipeflg;
  1132. xpipe_p xpipe;
  1133. pid_t pid;
  1134. char *argv[SHANYMAX];
  1135.  
  1136. dbgprt(1,"cmdredfork: ENTER\n");
  1137.  
  1138. // create output pipe for us [and input side for next command in chain]
  1139. if (xcmd->xcmd_opt & OPTOPIPE) {
  1140. xpipe = &xcmd->xcmd_xpipe;
  1141. pipe(xpipe->xpipe_fd);
  1142. dbgprt(1,"cmdredfork: MKPIPE %d/%d\n",
  1143. xpipe->xpipe_fd[0],xpipe->xpipe_fd[1]);
  1144. }
  1145.  
  1146. pid = fork();
  1147. xcmd->xcmd_pid = pid;
  1148.  
  1149. switch (pid) {
  1150. case 0: // child
  1151. for (redno = 0; redno <= 1; ++redno) {
  1152. // attach pipe units
  1153. switch (redno) {
  1154. case 0:
  1155. pipeflg = cmdpipefork(xcmd,OPTIPIPE,XPIPE_READ,
  1156. xcmd->xcmd_prev);
  1157. break;
  1158.  
  1159. case 1:
  1160. pipeflg = cmdpipefork(xcmd,OPTOPIPE,XPIPE_WRITE,xcmd);
  1161. break;
  1162.  
  1163. default:
  1164. pipeflg = 0;
  1165. break;
  1166. }
  1167. if (pipeflg)
  1168. continue;
  1169.  
  1170. // do we have a redirection?
  1171. red = &xcmd->xcmd_redir[redno];
  1172. if (red->red_file == NULL)
  1173. continue;
  1174.  
  1175. // attach the redirection
  1176. dup2(red->red_fd,redno);
  1177. CLOSEME(red->red_fd);
  1178. }
  1179.  
  1180. // get arguments in format needed by execvp
  1181. xcmdargv(xcmd,argv);
  1182.  
  1183. // execute the child program
  1184. execvp(argv[0],argv);
  1185.  
  1186. sysfault("cmdredfork: exec error on '%s' -- %s\n",
  1187. argv[0],strerror(errno));
  1188. break;
  1189.  
  1190. case -1: // fork error
  1191. /* unlikely but possible if hit a limit */
  1192. errprt(NULL,xcmd,NULL,"ERROR can't create child process!\n");
  1193. cmdredclose(xcmd,1);
  1194. break;
  1195.  
  1196. default: // parent
  1197. dbgprt(1,"cmdredfork: FORK pid=%d\n",pid);
  1198. cmdredclose(xcmd,0);
  1199.  
  1200. // don't wait for detached jobs
  1201. if (xcmd->xcmd_opt & OPTDETACH)
  1202. break;
  1203.  
  1204. // don't wait for piped jobs here -- we must finish constructing the
  1205. // pipeline
  1206. if (xcmd->xcmd_opt & (OPTIPIPE | OPTOPIPE))
  1207. break;
  1208.  
  1209. waitpid(pid,&xcmd->xcmd_status,0);
  1210. xcmd->xcmd_opt |= OPTDONE;
  1211. break;
  1212. }
  1213.  
  1214. dbgprt(1,"cmdredfork: EXIT\n");
  1215. }
  1216.  
  1217. // cmdredclose -- close redirections and pipe units in parent
  1218. void
  1219. cmdredclose(xcmd_p xcmd,int errflg)
  1220. {
  1221. int redno;
  1222. xpipe_p xpipe;
  1223. xcmd_p prev;
  1224. redir_p red;
  1225.  
  1226. dbgprt(1,"cmdredclose: ENTER errflg=%d\n",errflg);
  1227.  
  1228. // we get called by parent after fork to clean up units that are no longer
  1229. // needed and would gunk up a later stage child in a pipeline
  1230.  
  1231. // we have to keep the read side of the pipe for the _next_ stage [unless
  1232. // there's been a fatal error]
  1233. xpipe = &xcmd->xcmd_xpipe;
  1234. if (errflg)
  1235. CLOSEME(xpipe->xpipe_fd[XPIPE_READ]);
  1236. CLOSEME(xpipe->xpipe_fd[XPIPE_WRITE]);
  1237.  
  1238. // close pipe units from prior stage [if we have one]
  1239. prev = xcmd->xcmd_prev;
  1240. if (prev != NULL) {
  1241. xpipe = &xcmd->xcmd_xpipe;
  1242. CLOSEME(xpipe->xpipe_fd[XPIPE_READ]);
  1243. CLOSEME(xpipe->xpipe_fd[XPIPE_WRITE]);
  1244. }
  1245.  
  1246. // close all our redirections
  1247. for (redno = 0; redno <= 1; ++redno) {
  1248. red = &xcmd->xcmd_redir[redno];
  1249. CLOSEME(red->red_fd);
  1250. XSTRFREE(red->red_sep);
  1251. XSTRFREE(red->red_file);
  1252. }
  1253.  
  1254. dbgprt(1,"cmdredclose: EXIT\n");
  1255. }
  1256. % shpipe.c
  1257. // shpipe/shpipe -- shell with pipes
  1258.  
  1259. #define _SHPIPE_GLO_
  1260. #include <shpipe.h>
  1261.  
  1262. char *prompt = "% ";
  1263.  
  1264. // main -- main program
  1265. int
  1266. main(int argc,char **argv)
  1267. {
  1268. pid_t pid;
  1269. char line[SHANYMAX];
  1270. char *cp;
  1271. char *ifile;
  1272. int status;
  1273. int promptflg;
  1274. xcmd_p xcmd;
  1275. xlst_p xlst;
  1276.  
  1277. --argc;
  1278. ++argv;
  1279.  
  1280. for (; argc > 0; --argc, ++argv) {
  1281. cp = *argv;
  1282. if (*cp != '-')
  1283. break;
  1284.  
  1285. switch (cp[1]) {
  1286. case 'd':
  1287. opt_debug = 1;
  1288. break;
  1289. }
  1290. }
  1291.  
  1292. xfintop = stdin;
  1293. ifile = NULL;
  1294. pidtop = getpid();
  1295.  
  1296. if (argc > 0) {
  1297. ifile = *argv;
  1298. xfintop = fopen(ifile,"r");
  1299. if (xfintop == NULL)
  1300. sysfault("main: unable to open '%s' -- %s\n",
  1301. ifile,strerror(errno));
  1302. }
  1303.  
  1304. parseinfo.xstr_file = ifile;
  1305.  
  1306. //int joke = open("/dev/null",O_RDONLY);
  1307. xfdget(xfdchk_std);
  1308. //close(joke);
  1309.  
  1310. //signal(SIGINT, SIG_IGN);
  1311.  
  1312. promptflg = (ifile == NULL);
  1313.  
  1314. while (1) {
  1315. sysmchk();
  1316. xfdchk(xfdchk_std);
  1317.  
  1318. if (promptflg) {
  1319. promptflg = 0;
  1320. fprintf(stderr,"%s",prompt);
  1321. fflush(stderr);
  1322. }
  1323.  
  1324. // reap detached jobs
  1325. while (1) {
  1326. pid = waitpid(0,&status,WNOHANG);
  1327. if (pid <= 0)
  1328. break;
  1329. }
  1330.  
  1331. // abort script on errors
  1332. if ((ifile != NULL) && errstop)
  1333. break;
  1334. errstop = 0;
  1335.  
  1336. // get new input line
  1337. if (ifile != NULL)
  1338. parseinfo.xstr_fpos = ftell(xfintop);
  1339. cp = fgets(line,sizeof(line),xfintop);
  1340.  
  1341. // we can be interrupted if we enable SIGCHLD (i.e. we can keep things
  1342. // tidy even if we wait for hours for user input)
  1343. if (cp == NULL) {
  1344. fprintf(stderr,"main: DEBUG_CAE/GETS -- %s\n",strerror(errno));
  1345. if (errno != EINTR)
  1346. break;
  1347. continue;
  1348. }
  1349.  
  1350. promptflg = (ifile == NULL);
  1351.  
  1352. ++parseinfo.xstr_lno;
  1353.  
  1354. cp = strchr(line,'\n');
  1355. if (cp != NULL)
  1356. *cp = 0;
  1357.  
  1358. if (ifile != NULL)
  1359. dbgprt(1,"main: LINE '%s'\n",line);
  1360.  
  1361. xcmd = parseline(line);
  1362.  
  1363. dbgexec(1,xcmdshow(xcmd,"parseline"));
  1364.  
  1365. xlst = xlstnew();
  1366. cmdsplit(xlst,xcmd,TOKSEP,";",OPTLOCK);
  1367.  
  1368. // do single commands separated by semicolons
  1369. for (xcmd = xlst->xlst_head; xcmd != NULL; xcmd = xcmd->xcmd_next) {
  1370. cmdsemi(xcmd);
  1371. xcmd->xcmd_opt &= ~OPTLOCK;
  1372. }
  1373.  
  1374. xlstfree(xlst);
  1375. }
  1376.  
  1377. if (parseinfo.xstr_file != NULL)
  1378. fclose(xfintop);
  1379.  
  1380. return 0;
  1381. }
  1382.  
  1383. // cmdsemi -- run a job
  1384. void
  1385. cmdsemi(xcmd_p xcmd)
  1386. {
  1387. xstr_p xstr;
  1388.  
  1389. xcmd->xcmd_opt &= ~(OPTNOGO | OPTDETACH);
  1390.  
  1391. // decide if we want a detached job
  1392. do {
  1393. xstr = xcmdfind2(xcmd,TOKSEP,"&");
  1394.  
  1395. if (xstr == NULL)
  1396. break;
  1397. xcmd->xcmd_opt |= OPTDETACH;
  1398.  
  1399. // the token _must_ be the last or we can't really divine intent too
  1400. // well
  1401. if (xstr->xstr_next != NULL) {
  1402. errprt(NULL,xcmd,xstr,
  1403. "cmdsemi: found '&' in middle of command\n");
  1404. break;
  1405. }
  1406.  
  1407. // just get rid of it
  1408. xcmdunlink(xcmd,xstr);
  1409. xstrfree(xstr);
  1410. } while (0);
  1411.  
  1412. // decide if we have pipes
  1413. // do this early to allow the simple [non-pipe] case to go quickly
  1414. do {
  1415. if (xcmd->xcmd_opt & OPTNOGO)
  1416. break;
  1417.  
  1418. xstr = xcmdfind2(xcmd,TOKSEP,"|");
  1419. if (xstr != NULL)
  1420. cmdpipeall(xcmd);
  1421. else
  1422. cmdredall(xcmd);
  1423. } while (0);
  1424. }
  1425.  
  1426. // cmdsplit -- split on token
  1427. void
  1428. cmdsplit(xlst_p xlst,xcmd_p xcmd,int type,char *sep,u32 opt)
  1429. {
  1430. xstr_p xstr;
  1431. xcmd_p xcut;
  1432.  
  1433. while (1) {
  1434. xstr = xcmdfind2(xcmd,type,sep);
  1435. if (xstr == NULL)
  1436. break;
  1437.  
  1438. xcut = xcmdcut(xcmd,xstr);
  1439. xcut->xcmd_opt |= opt;
  1440. xlstpush(xlst,xcut);
  1441.  
  1442. xstrfree(xstr);
  1443. }
  1444.  
  1445. if (xcmd->xcmd_head != NULL) {
  1446. xcmd->xcmd_opt |= opt;
  1447. xlstpush(xlst,xcmd);
  1448. }
  1449. else
  1450. xcmdfree(xcmd);
  1451. }
  1452. % shpipe.h
  1453. // shpipe/shpipe.h -- shell pipe control
  1454.  
  1455. #ifndef _shpipe_shpipe_h_
  1456. #define _shpipe_shpipe_h_
  1457.  
  1458. #include <stdio.h>
  1459. #include <stdlib.h>
  1460. #include <stdarg.h>
  1461. #include <unistd.h>
  1462. #include <string.h>
  1463. #include <errno.h>
  1464. #include <signal.h>
  1465. #include <sys/stat.h>
  1466. #include <fcntl.h>
  1467. #include <sys/types.h>
  1468. #include <sys/wait.h>
  1469.  
  1470. #define SUPER_INLINE __attribute__((always_inline)) static inline
  1471.  
  1472. #ifdef _SHPIPE_GLO_
  1473. #define EXTRN_SHPIPE /**/
  1474. #else
  1475. #define EXTRN_SHPIPE extern
  1476. #endif
  1477.  
  1478. typedef unsigned char byte;
  1479. typedef unsigned int u32;
  1480.  
  1481. #define CAST(_typ,_val) \
  1482. ((_typ) (_val))
  1483.  
  1484. #define FWD(_typ) \
  1485. struct _##_typ; \
  1486. typedef struct _##_typ _typ##_t; \
  1487. typedef _typ##_t *_typ##_p
  1488.  
  1489. FWD(xstr);
  1490. FWD(xpipe);
  1491. FWD(redir);
  1492. FWD(xcmd);
  1493. FWD(xlst);
  1494.  
  1495. #define SHANYMAX 300 // maximum for anything
  1496.  
  1497. // bit mask operations
  1498. #define BTVOFF(_bitno) ((_bitno) >> 3)
  1499. #define BTVMSK(_bitno) (1u << ((_bitno) % 0x07))
  1500. #define BTVLEN(_bitcnt) ((((_bitcnt) + 7) >> 3) << 3)
  1501. #define BTVSET(_vec,_bitno) _vec[BTVOFF(_bitno)] |= BTVMSK(_bitno)
  1502. #define BTVCLR(_vec,_bitno) _vec[BTVOFF(_bitno)] &= ~BTVMSK(_bitno)
  1503.  
  1504. #ifndef DLHCNT
  1505. #define DLHCNT 1
  1506. #endif
  1507.  
  1508. #ifndef XMEMCHK
  1509. #define XMEMCHK 1
  1510. #endif
  1511.  
  1512. #if XMEMCHK
  1513. #define syscalloc(_cnt,_len,_mag) _syscalloc(_cnt,_len,_mag,__FILE__,__LINE__)
  1514. #define sysfree(_vp) _sysfree(_vp)
  1515. #define sysmchk() _sysmchk()
  1516. #else
  1517. #define syscalloc(_cnt,_len,_mag) calloc(_cnt,_len)
  1518. #define sysfree(_vp) free(_vp)
  1519. #define sysmchk() /**/
  1520. #endif
  1521.  
  1522. #ifndef XFDCHK
  1523. #define XFDCHK 1
  1524. #endif
  1525.  
  1526. #define XFDMAX 1024
  1527.  
  1528. #if XFDCHK
  1529. #define xfdget(_vec) _xfdget(_vec)
  1530. #define xfdchk(_vec) _xfdchk(_vec)
  1531. #else
  1532. #define xfdget(_vec) /**/
  1533. #define xfdchk(_vec) /**/
  1534. #endif
  1535.  
  1536. pid_t pidtop; // top/master process id
  1537. FILE *xfintop; // top input stream
  1538.  
  1539. EXTRN_SHPIPE byte xfdchk_std[BTVLEN(XFDMAX)];
  1540.  
  1541. // magic numbers
  1542. typedef enum {
  1543. SYSMAGIC_XSTR = 0xDEADBE01,
  1544. SYSMAGIC_XCMD = 0xDEADBE02,
  1545. SYSMAGIC_XLST = 0xDEADBE03,
  1546. SYSMAGIC_ARGV = 0xDEADBE04,
  1547. } sysmagic_t;
  1548.  
  1549. // allocation control
  1550. FWD(xmem);
  1551. struct _xmem {
  1552. sysmagic_t xmem_magic; // magic number
  1553. xmem_p xmem_next; // linkage
  1554. const char *xmem_file; // file
  1555. int xmem_lno; // line number
  1556. //long xmem_rsvp;
  1557. };
  1558. EXTRN_SHPIPE xmem_p xmemall;
  1559.  
  1560. EXTRN_SHPIPE int opt_debug;
  1561.  
  1562. #define sysfault(_fmt...) \
  1563. do { \
  1564. fprintf(stderr,_fmt); \
  1565. exit(1); \
  1566. } while (0)
  1567.  
  1568. #define dbgprt(_lvl,_fmt...) \
  1569. do { \
  1570. if (opt_debug) \
  1571. _dbgprt(_fmt); \
  1572. } while (0)
  1573.  
  1574. #define _dbgprt(_fmt...) \
  1575. fprintf(stderr,_fmt)
  1576.  
  1577. #define dbgexec(_lvl,_expr) \
  1578. do { \
  1579. if (opt_debug) \
  1580. _expr; \
  1581. } while (0)
  1582.  
  1583. #define OPTALL(_cmd) \
  1584. _cmd(TOKSEP,"special separater") \
  1585. _cmd(TOKQUO1,"single quoted string") \
  1586. _cmd(TOKQUO2,"double quoted string") \
  1587. _cmd(TOKWORD,"ordinary word") \
  1588. _cmd(OPTNOGO,"error occurred") \
  1589. _cmd(OPTDETACH,"detach job") \
  1590. _cmd(OPTLOCK,"struct locked") \
  1591. _cmd(OPTIPIPE,"input pipe") \
  1592. _cmd(OPTOPIPE,"output pipe") \
  1593. _cmd(OPTDONE,"command done")
  1594.  
  1595. #define _OPTDEF(_sym,_reason) \
  1596. _##_sym,
  1597. enum {
  1598. OPTALL(_OPTDEF)
  1599. };
  1600.  
  1601. #define _OPTMSK(_sym,_reason) \
  1602. _sym = (1 << _##_sym),
  1603. enum {
  1604. OPTALL(_OPTMSK)
  1605. };
  1606.  
  1607. // option/symbol display control
  1608. FWD(tgb);
  1609. struct _tgb {
  1610. const char *tgb_tag; // symbol name
  1611. u32 tgb_val; // symbol value
  1612. const char *tgb_reason; // symbol explanation
  1613. };
  1614.  
  1615. #define TGBEOT \
  1616. { .tgb_tag = NULL }
  1617. #define TGBMORE(_tgb) \
  1618. _tgb != NULL
  1619.  
  1620. #define _OPTTGB(_sym,_reason) \
  1621. { .tgb_tag = #_sym, .tgb_val = _sym, .tgb_reason = _reason },
  1622. #ifdef _SHPIPE_GLO_
  1623. tgb_t opt_tgb[] = {
  1624. OPTALL(_OPTTGB)
  1625. TGBEOT
  1626. };
  1627. #else
  1628. extern tgb_t opt_tgb[];
  1629. #endif
  1630.  
  1631. FWD(dlh);
  1632. FWD(dlk);
  1633. FWD(dlv);
  1634.  
  1635. #define DLKDEF(_typ) \
  1636. sysmagic_t _typ##_magic; /* magic number */ \
  1637. u32 _typ##_opt; /* options */ \
  1638. _typ##_p _typ##_prev; /* pointer to previous item in list */ \
  1639. _typ##_p _typ##_next /* pointer to next item in list */
  1640.  
  1641. #define DLKOF(_ptr) \
  1642. CAST(dlk_p,_ptr)
  1643.  
  1644. #define DLHDEF(_pre,_typ) \
  1645. _typ##_p _pre##head; /* head of list */ \
  1646. _typ##_p _pre##tail; /* tail of list */ \
  1647. dlv_p _pre##dlv; /* virtual function table pointer */ \
  1648. int _pre##cnt; /* number of items in list */
  1649.  
  1650. #define DLHOF(_ptr,_pre) \
  1651. CAST(dlh_p,&_ptr->_pre##head)
  1652.  
  1653. // doubly linked list virtual function table
  1654. struct _dlv {
  1655. void (*dlv_free)(dlk_p dlk); // free the item
  1656. void (*dlv_show)(dlk_p dlk,const char *reason); // show the item
  1657. };
  1658.  
  1659. // doubly linked list item
  1660. struct _dlk {
  1661. DLKDEF(dlk);
  1662. };
  1663.  
  1664. // doubly linked list header
  1665. struct _dlh {
  1666. DLHDEF(dlh_,dlk);
  1667. };
  1668.  
  1669. // string buffer
  1670. struct _xstr {
  1671. DLKDEF(xstr); // linkage
  1672. u32 xstr_type; // string type
  1673.  
  1674. size_t xstr_maxlen; // maximum space in string buffer
  1675. char *xstr_lhs; // pointer to start of string
  1676. char *xstr_rhs; // pointer to current string append
  1677.  
  1678. char *xstr_file; // input file
  1679. long xstr_fpos; // input file position
  1680. int xstr_lno; // input file line number
  1681.  
  1682. char *xstr_bufptr; // pointer to buffer
  1683. long xstr_bufoff; // beginning buffer offset
  1684. };
  1685.  
  1686. // pipe control
  1687. struct _xpipe {
  1688. int xpipe_fd[2]; // pipe units
  1689. };
  1690. #define XPIPE_READ 0 // read/input side of pipe
  1691. #define XPIPE_WRITE 1 // write/output side of pipe
  1692.  
  1693. // redirection control
  1694. struct _redir {
  1695. xstr_p red_sep; // separater
  1696. xstr_p red_file; // filename
  1697. int red_fd; // open file unit
  1698. };
  1699.  
  1700. // close file descriptor
  1701. #define CLOSEME(_fd) \
  1702. _fd = closeme(_fd,__FILE__,__LINE__)
  1703.  
  1704. #define XSTRFREE(_xstr) \
  1705. _xstr = xstrfree(_xstr)
  1706.  
  1707. // command control
  1708. struct _xcmd {
  1709. DLKDEF(xcmd); // linkage
  1710. DLHDEF(xcmd_,xstr); // list of strings
  1711.  
  1712. redir_t xcmd_redir[2]; // redirection control
  1713. xpipe_t xcmd_xpipe; // output side pipe
  1714.  
  1715. pid_t xcmd_pid; // process id
  1716. int xcmd_status; // completion status
  1717. };
  1718.  
  1719. #define XCMD_DLHOF(_xcmd) \
  1720. DLHOF(_xcmd,xcmd_)
  1721.  
  1722. // command list
  1723. struct _xlst {
  1724. DLKDEF(xlst); // linkage
  1725. DLHDEF(xlst_,xcmd); // list of commands
  1726. };
  1727.  
  1728. #define XLST_DLHOF(_xlst) \
  1729. DLHOF(_xlst,xlst_)
  1730.  
  1731. EXTRN_SHPIPE xstr_t parseinfo; // information
  1732. EXTRN_SHPIPE char *parsebuf; // current buffer
  1733. EXTRN_SHPIPE char *parsecur; // current offset
  1734. EXTRN_SHPIPE int errstop; // errors
  1735.  
  1736. #include <shpipe.proto>
  1737.  
  1738. // closeme -- close a unit
  1739. SUPER_INLINE int
  1740. closeme(int fd,const char *file,int lno)
  1741. {
  1742.  
  1743. #if XFDCHK
  1744. fd = _closeme(fd,file,lno);
  1745. #else
  1746. do {
  1747. if (fd < 0)
  1748. break;
  1749. dbgprt(1,"closeme: CLOSE fd=%d file='%s' lno=%d\n",
  1750. fd,file,lno);
  1751. close(fd);
  1752. _fd = -1;
  1753. } while (0)
  1754. #endif
  1755.  
  1756. return fd;
  1757. }
  1758.  
  1759. // btvget -- fetch bit vector value
  1760. SUPER_INLINE byte
  1761. btvget(const byte *vec,int bitno)
  1762. {
  1763.  
  1764. vec += BTVOFF(bitno);
  1765.  
  1766. return *vec & BTVMSK(bitno);
  1767. }
  1768.  
  1769. // btvset -- set bit vector value
  1770. SUPER_INLINE void
  1771. btvset(byte *vec,int bitno,int val)
  1772. {
  1773. byte msk;
  1774.  
  1775. vec += BTVOFF(bitno);
  1776. msk = BTVMSK(bitno);
  1777.  
  1778. if (val)
  1779. *vec |= msk;
  1780. else
  1781. *vec &= ~msk;
  1782. }
  1783.  
  1784. // dlhinc -- increment/decrement list count
  1785. SUPER_INLINE void
  1786. dlhinc(dlh_p dlh,int inc)
  1787. {
  1788. #if DLHCNT
  1789. dlh->dlh_cnt += inc;
  1790. #endif
  1791. }
  1792.  
  1793. // xstrcstr -- get the "c string" value
  1794. SUPER_INLINE char *
  1795. xstrcstr(xstr_p xstr)
  1796. {
  1797.  
  1798. return xstr->xstr_lhs;
  1799. }
  1800.  
  1801. // xcmd virtual function table
  1802. #ifdef _SHPIPE_GLO_
  1803. dlv_t xcmd_dlv = {
  1804. .dlv_free = xstrfree_dlv,
  1805. .dlv_show = xstrshow_dlv,
  1806. };
  1807. #else
  1808. extern dlv_t xcmd_dlv;
  1809. #endif
  1810.  
  1811. // xlst virtual function table
  1812. #ifdef _SHPIPE_GLO_
  1813. dlv_t xlst_dlv = {
  1814. .dlv_free = xcmdfree_dlv,
  1815. .dlv_show = xcmdshow_dlv,
  1816. };
  1817. #else
  1818. extern dlv_t xlst_dlv;
  1819. #endif
  1820.  
  1821. #endif
  1822. % shredir.c
  1823. // shpipe/shredir -- original answer
  1824.  
  1825. #include <stdio.h>
  1826. #include <stdlib.h>
  1827. #include <unistd.h>
  1828. #include <string.h>
  1829. #include <errno.h>
  1830. #include <signal.h>
  1831. #include <sys/stat.h>
  1832. #include <fcntl.h>
  1833. #include <sys/types.h>
  1834. #include <sys/wait.h>
  1835.  
  1836. char *prompt = "% ";
  1837.  
  1838. int
  1839. main()
  1840. {
  1841. int pid;
  1842. //int child_pid;
  1843. char line[81];
  1844. char *token;
  1845. char *separator = " \t\n";
  1846. char **args;
  1847. char **args2;
  1848. char *cp;
  1849. char *ifile;
  1850. char *ofile;
  1851. int i;
  1852. int j;
  1853. int err;
  1854. //int check;
  1855. //char history[90];
  1856. //typedef void (*sighandler_t) (int);
  1857.  
  1858. args = malloc(80 * sizeof(char *));
  1859. args2 = malloc(80 * sizeof(char *));
  1860.  
  1861. //signal(SIGINT, SIG_IGN);
  1862.  
  1863. while (1) {
  1864. fprintf(stderr, "%s", prompt);
  1865. fflush(stderr);
  1866.  
  1867. if (fgets(line, 80, stdin) == NULL)
  1868. break;
  1869.  
  1870. // split up the line
  1871. i = 0;
  1872. while (1) {
  1873. token = strtok((i == 0) ? line : NULL, separator);
  1874. if (token == NULL)
  1875. break;
  1876. args[i++] = token; /* build command array */
  1877. }
  1878. args[i] = NULL;
  1879. if (i == 0)
  1880. continue;
  1881.  
  1882. // assume no redirections
  1883. ofile = NULL;
  1884. ifile = NULL;
  1885.  
  1886. // split off the redirections
  1887. j = 0;
  1888. i = 0;
  1889. err = 0;
  1890. while (1) {
  1891. cp = args[i++];
  1892. if (cp == NULL)
  1893. break;
  1894.  
  1895. switch (*cp) {
  1896. case '<':
  1897. if (cp[1] == 0)
  1898. cp = args[i++];
  1899. else
  1900. ++cp;
  1901. ifile = cp;
  1902. if (cp == NULL)
  1903. err = 1;
  1904. else
  1905. if (cp[0] == 0)
  1906. err = 1;
  1907. break;
  1908.  
  1909. case '>':
  1910. if (cp[1] == 0)
  1911. cp = args[i++];
  1912. else
  1913. ++cp;
  1914. ofile = cp;
  1915. if (cp == NULL)
  1916. err = 1;
  1917. else
  1918. if (cp[0] == 0)
  1919. err = 1;
  1920. break;
  1921.  
  1922. default:
  1923. args2[j++] = cp;
  1924. break;
  1925. }
  1926. }
  1927. args2[j] = NULL;
  1928.  
  1929. // we got something like "cat <"
  1930. if (err)
  1931. continue;
  1932.  
  1933. // no child arguments
  1934. if (j == 0)
  1935. continue;
  1936.  
  1937. switch (pid = fork()) {
  1938. case 0:
  1939. // open stdin
  1940. if (ifile != NULL) {
  1941. int fd = open(ifile, O_RDONLY);
  1942.  
  1943. if (dup2(fd, STDIN_FILENO) == -1) {
  1944. fprintf(stderr, "dup2 failed");
  1945. }
  1946.  
  1947. close(fd);
  1948. }
  1949.  
  1950. // trying to get this to work
  1951. // NOTE: now it works :-)
  1952. // open stdout
  1953. if (ofile != NULL) {
  1954. // args[1] = NULL;
  1955. int fd2;
  1956.  
  1957. //printf("PLEASE WORK");
  1958. if ((fd2 = open(ofile, O_WRONLY | O_CREAT, 0644)) < 0) {
  1959. perror("couldn't open output file.");
  1960. exit(0);
  1961. }
  1962.  
  1963. // args+=2;
  1964. printf("okay");
  1965. dup2(fd2, STDOUT_FILENO);
  1966. close(fd2);
  1967. }
  1968.  
  1969. execvp(args2[0], args2); /* child */
  1970. signal(SIGINT, SIG_DFL);
  1971. fprintf(stderr, "ERROR %s no such program\n", line);
  1972. exit(1);
  1973. break;
  1974.  
  1975. case -1:
  1976. /* unlikely but possible if hit a limit */
  1977. fprintf(stderr, "ERROR can't create child process!\n");
  1978. break;
  1979.  
  1980. default:
  1981. //printf("am I here");
  1982. wait(NULL);
  1983. //waitpid(pid, 0, 0);
  1984. }
  1985. }
  1986.  
  1987. exit(0);
  1988. }
  1989. % str.c
  1990. // shpipe/str -- string functions
  1991.  
  1992. #include <shpipe.h>
  1993.  
  1994. #define TMPMAX 20
  1995. static int tmpidx;
  1996. static char tmpbuf[TMPMAX][SHANYMAX];
  1997.  
  1998. // strtmp -- temporary persistent string buffer
  1999. char *
  2000. strtmp(void)
  2001. {
  2002. char *bf;
  2003.  
  2004. bf = tmpbuf[tmpidx];
  2005. if (++tmpidx >= TMPMAX)
  2006. tmpidx = 0;
  2007.  
  2008. *bf = 0;
  2009.  
  2010. return bf;
  2011. }
  2012.  
  2013. // strtgb -- display option mask
  2014. char *
  2015. strtgb(tgb_p tgb,u32 opt)
  2016. {
  2017. char *bp;
  2018. const char *sep;
  2019. char *bf;
  2020.  
  2021. bf = strtmp();
  2022. bp = bf;
  2023.  
  2024. *bp++ = '(';
  2025.  
  2026. sep = "";
  2027. for (; TGBMORE(tgb); ++tgb) {
  2028. if (opt & tgb->tgb_val) {
  2029. bp += sprintf(bp,"%s%s",sep,tgb->tgb_tag);
  2030. sep = " ";
  2031. }
  2032. }
  2033.  
  2034. *bp++ = ')';
  2035. *bp = 0;
  2036.  
  2037. return bf;
  2038. }
  2039. % sysf.c
  2040. // shpipe/sysf -- file descriptor leak detection
  2041.  
  2042. #include <shpipe.h>
  2043.  
  2044. // _closeme -- close a unit
  2045. int
  2046. _closeme(int fd,const char *file,int lno)
  2047. {
  2048. int err;
  2049.  
  2050. do {
  2051. if (fd < 0)
  2052. break;
  2053.  
  2054. dbgprt(1,"closeme: CLOSE fd=%d file='%s' lno=%d\n",
  2055. fd,file,lno);
  2056.  
  2057. err = 0;
  2058. if (fd == fileno(xfintop))
  2059. err |= 1;
  2060. if (fd == 0)
  2061. err |= 2;
  2062. #if 0
  2063. if (fd == 3)
  2064. err |= 4;
  2065. #endif
  2066.  
  2067. if (err)
  2068. sysfault("_closeme: fault -- fd=%d file='%s' lno=%d\n",fd,file,lno);
  2069.  
  2070. close(fd);
  2071.  
  2072. fd = -1;
  2073. } while (0);
  2074.  
  2075. return fd;
  2076. }
  2077.  
  2078. // _xfdget -- get vector of currently open file descriptors
  2079. void
  2080. _xfdget(byte *vec)
  2081. {
  2082. int fd;
  2083. int err;
  2084.  
  2085. for (fd = 0; fd < XFDMAX; ++fd) {
  2086. err = fcntl(fd,F_GETFD);
  2087. err = (err >= 0);
  2088. btvset(vec,fd,err);
  2089. }
  2090. }
  2091.  
  2092. // _xfdchk -- get vector of currently open file descriptors
  2093. void
  2094. _xfdchk(byte *stdvec)
  2095. {
  2096. byte stdval;
  2097. byte curval;
  2098. int fd;
  2099. int err;
  2100. byte curvec[BTVLEN(XFDMAX)];
  2101.  
  2102. _xfdget(curvec);
  2103.  
  2104. err = 0;
  2105. for (fd = 0; fd < XFDMAX; ++fd) {
  2106. stdval = btvget(stdvec,fd);
  2107. stdval = stdval ? 1 : 0;
  2108.  
  2109. curval = btvget(curvec,fd);
  2110. curval = curval ? 1 : 0;
  2111.  
  2112. if (curval != stdval) {
  2113. err = 1;
  2114. fprintf(stderr,"xfdchk: mismatch -- fd=%d stdval=%d curval=%d\n",
  2115. fd,stdval,curval);
  2116. }
  2117. }
  2118.  
  2119. if (err)
  2120. sysfault("xfdchk: aborting\n");
  2121. }
  2122. % sysm.c
  2123. // shpipe/sysm -- memory leak detection
  2124.  
  2125. #include <shpipe.h>
  2126.  
  2127. // _syscalloc -- get new list
  2128. void *
  2129. _syscalloc(size_t cnt,size_t len,sysmagic_t magno,const char *file,int lno)
  2130. {
  2131. xmem_p xmem;
  2132. void *vp;
  2133.  
  2134. if ((sizeof(xmem_t) % 8) != 0)
  2135. sysfault("_syscalloc: xmem_t sizeof fault -- %ld\n",
  2136. (long) sizeof(xmem_t));
  2137.  
  2138. // get total size [including our control struct]
  2139. len *= cnt;
  2140. len += sizeof(xmem_t);
  2141.  
  2142. // allocate and clear
  2143. xmem = malloc(len);
  2144. memset(xmem,0,len);
  2145.  
  2146. // link us into the global list
  2147. xmem->xmem_next = xmemall;
  2148. xmemall = xmem;
  2149.  
  2150. // say who did the allocation
  2151. xmem->xmem_magic = magno;
  2152. xmem->xmem_file = file;
  2153. xmem->xmem_lno = lno;
  2154.  
  2155. // get the visible pointer
  2156. vp = xmem;
  2157. vp += sizeof(xmem_t);
  2158.  
  2159. return vp;
  2160. }
  2161.  
  2162. // _sysfree -- free list
  2163. void
  2164. _sysfree(void *vp)
  2165. {
  2166. xmem_p xmem;
  2167. xmem_p cur;
  2168. xmem_p prev;
  2169.  
  2170. // get our internal pointer
  2171. vp -= sizeof(xmem_t);
  2172. xmem = vp;
  2173.  
  2174. // find our place in the global list
  2175. prev = NULL;
  2176. for (cur = xmemall; cur != NULL; prev = cur, cur = cur->xmem_next) {
  2177. if (cur == xmem)
  2178. break;
  2179. }
  2180.  
  2181. // remove us from the list
  2182. if (prev != NULL)
  2183. prev->xmem_next = xmem->xmem_next;
  2184. else
  2185. xmemall = xmem->xmem_next;
  2186.  
  2187. // release the memory
  2188. free(xmem);
  2189. }
  2190.  
  2191. // _sysmchk -- check memory
  2192. void
  2193. _sysmchk(void)
  2194. {
  2195. xmem_p xmem;
  2196. void *vp;
  2197.  
  2198. for (xmem = xmemall; xmem != NULL; xmem = xmem->xmem_next) {
  2199. vp = xmem;
  2200. vp += sizeof(xmem_t);
  2201.  
  2202. _dbgprt("sysmchk: vp=%p xmem_file='%s' xmem_lno=%d\n",
  2203. vp,xmem->xmem_file,xmem->xmem_lno);
  2204.  
  2205. switch (xmem->xmem_magic) {
  2206. case SYSMAGIC_XSTR:
  2207. xstrshow(vp);
  2208. break;
  2209.  
  2210. case SYSMAGIC_XCMD:
  2211. xcmdshow(vp,"sysmchk");
  2212. break;
  2213.  
  2214. case SYSMAGIC_XLST:
  2215. xlstshow(vp,"sysmchk");
  2216. break;
  2217.  
  2218. case SYSMAGIC_ARGV:
  2219. break;
  2220. }
  2221. }
  2222.  
  2223. if (xmemall != NULL)
  2224. sysfault("_sysmchk: aborting\n");
  2225. }
  2226. % xcmd.c
  2227. // shpipe/xcmd -- "smart" list "class" for C
  2228.  
  2229. #include <shpipe.h>
  2230.  
  2231. // xcmdnew -- get new list
  2232. xcmd_p
  2233. xcmdnew(void)
  2234. {
  2235. int redno;
  2236. dlh_p dlh;
  2237. xpipe_p xpipe;
  2238. xcmd_p xcmd;
  2239.  
  2240. xcmd = syscalloc(1,sizeof(xcmd_t),SYSMAGIC_XCMD);
  2241.  
  2242. for (redno = 0; redno <= 1; ++redno)
  2243. xcmd->xcmd_redir[redno].red_fd = -1;
  2244.  
  2245. xpipe = &xcmd->xcmd_xpipe;
  2246. for (redno = 0; redno <= 1; ++redno)
  2247. xpipe->xpipe_fd[redno] = -1;
  2248.  
  2249. dlh = XCMD_DLHOF(xcmd);
  2250. dlh->dlh_dlv = &xcmd_dlv;
  2251.  
  2252. return xcmd;
  2253. }
  2254.  
  2255. // xcmdfree -- free list
  2256. xcmd_p
  2257. xcmdfree(xcmd_p xcmd)
  2258. {
  2259. xpipe_p xpipe;
  2260.  
  2261. do {
  2262. if (xcmd == NULL)
  2263. break;
  2264.  
  2265. if (xcmd->xcmd_opt & OPTLOCK)
  2266. break;
  2267.  
  2268. xpipe = &xcmd->xcmd_xpipe;
  2269.  
  2270. xcmd->xcmd_opt &= ~OPTIPIPE;
  2271. CLOSEME(xpipe->xpipe_fd[XPIPE_READ]);
  2272.  
  2273. xcmd->xcmd_opt &= ~OPTOPIPE;
  2274. CLOSEME(xpipe->xpipe_fd[XPIPE_WRITE]);
  2275.  
  2276. _dlhfree(XCMD_DLHOF(xcmd));
  2277. sysfree(xcmd);
  2278.  
  2279. xcmd = NULL;
  2280. } while (0);
  2281.  
  2282. return xcmd;
  2283. }
  2284.  
  2285. // xcmdargv -- convert list to argv
  2286. char **
  2287. xcmdargv(xcmd_p xcmd,char **argv)
  2288. // argv -- flat list pointer (null means allocate)
  2289. {
  2290. char **av;
  2291. int cnt;
  2292. xstr_p xstr;
  2293.  
  2294. if (argv == NULL) {
  2295. cnt = xcmdcnt(xcmd);
  2296. argv = syscalloc(cnt + 1,sizeof(char *),SYSMAGIC_ARGV);
  2297. }
  2298.  
  2299. av = argv;
  2300.  
  2301. for (xstr = xcmd->xcmd_head; xstr != NULL; xstr = xstr->xstr_next, ++av)
  2302. *av = xstrcstr(xstr);
  2303.  
  2304. *av = NULL;
  2305.  
  2306. return argv;
  2307. }
  2308.  
  2309. // xcmdpush -- append string to end of list
  2310. xstr_p
  2311. xcmdpush(xcmd_p xcmd,xstr_p xstr)
  2312. {
  2313.  
  2314. dlkpush(XCMD_DLHOF(xcmd),DLKOF(xstr));
  2315.  
  2316. return xstr;
  2317. }
  2318.  
  2319. // xcmdfind1 -- find a given token based on type and prefix value
  2320. xstr_p
  2321. xcmdfind1(xcmd_p xcmd,int type,const char *src)
  2322. {
  2323. xstr_p xstr;
  2324.  
  2325. for (xstr = xcmd->xcmd_head; xstr != NULL; xstr = xstr->xstr_next) {
  2326. if (tokmatch1(xstr,type,src))
  2327. break;
  2328. }
  2329.  
  2330. return xstr;
  2331. }
  2332.  
  2333. // xcmdfind2 -- find a given token based on type and exact value
  2334. xstr_p
  2335. xcmdfind2(xcmd_p xcmd,int type,const char *src)
  2336. {
  2337. xstr_p xstr;
  2338.  
  2339. for (xstr = xcmd->xcmd_head; xstr != NULL; xstr = xstr->xstr_next) {
  2340. if (tokmatch2(xstr,type,src))
  2341. break;
  2342. }
  2343.  
  2344. return xstr;
  2345. }
  2346.  
  2347. // xcmdcut -- cut out entry and split list
  2348. xcmd_p
  2349. xcmdcut(xcmd_p xcmdrhs,xstr_p xstr)
  2350. {
  2351. xcmd_p xcmdlhs;
  2352.  
  2353. xcmdlhs = xcmdnew();
  2354. dlhcut(XCMD_DLHOF(xcmdlhs),XCMD_DLHOF(xcmdrhs),DLKOF(xstr));
  2355.  
  2356. return xcmdlhs;
  2357. }
  2358.  
  2359. // xcmdunlink -- remove string from list
  2360. xstr_p
  2361. xcmdunlink(xcmd_p xcmd,xstr_p xstr)
  2362. {
  2363.  
  2364. dlkunlink(XCMD_DLHOF(xcmd),DLKOF(xstr));
  2365.  
  2366. return xstr;
  2367. }
  2368.  
  2369. // xcmdcnt -- calculate string count
  2370. int
  2371. xcmdcnt(xcmd_p xcmd)
  2372. {
  2373.  
  2374. return dlhcnt(XCMD_DLHOF(xcmd));
  2375. }
  2376.  
  2377. // xcmdshow -- output a list
  2378. void
  2379. xcmdshow(xcmd_p xcmd,const char *reason)
  2380. {
  2381.  
  2382. dlhshow(XCMD_DLHOF(xcmd),reason);
  2383. }
  2384.  
  2385. // xcmdfree_dlv -- release string buffer data
  2386. void
  2387. xcmdfree_dlv(dlk_p dlk)
  2388. {
  2389.  
  2390. xcmdfree((xcmd_p) dlk);
  2391. }
  2392.  
  2393. // xcmdshow_dlv -- show data
  2394. void
  2395. xcmdshow_dlv(dlk_p dlk,const char *reason)
  2396. {
  2397.  
  2398. xcmdshow((xcmd_p) dlk,reason);
  2399. }
  2400. % xlst.c
  2401. // shpipe/xlst -- "smart" list "class" for C
  2402.  
  2403. #include <shpipe.h>
  2404.  
  2405. // xlstnew -- get new list
  2406. xlst_p
  2407. xlstnew(void)
  2408. {
  2409. dlh_p dlh;
  2410. xlst_p xlst;
  2411.  
  2412. xlst = syscalloc(1,sizeof(xlst_t),SYSMAGIC_XLST);
  2413. xlst->xlst_magic = SYSMAGIC_XLST;
  2414.  
  2415. dlh = XLST_DLHOF(xlst);
  2416. dlh->dlh_dlv = &xlst_dlv;
  2417.  
  2418. return xlst;
  2419. }
  2420.  
  2421. // xlstfree -- free list
  2422. xlst_p
  2423. xlstfree(xlst_p xlst)
  2424. {
  2425.  
  2426. do {
  2427. if (xlst == NULL)
  2428. break;
  2429.  
  2430. if (xlst->xlst_opt & OPTLOCK)
  2431. break;
  2432.  
  2433. _dlhfree(XLST_DLHOF(xlst));
  2434. sysfree(xlst);
  2435.  
  2436. xlst = NULL;
  2437. } while (0);
  2438.  
  2439. return xlst;
  2440. }
  2441.  
  2442. // xlstpush -- append string to end of list
  2443. xcmd_p
  2444. xlstpush(xlst_p xlst,xcmd_p xcmd)
  2445. {
  2446.  
  2447. dlkpush(XLST_DLHOF(xlst),DLKOF(xcmd));
  2448.  
  2449. return xcmd;
  2450. }
  2451.  
  2452. // xlstcut -- cut out entry and split list
  2453. xlst_p
  2454. xlstcut(xlst_p xlstrhs,xcmd_p xcmd)
  2455. {
  2456. xlst_p xlstlhs;
  2457.  
  2458. xlstlhs = xlstnew();
  2459. dlhcut(XLST_DLHOF(xlstlhs),XLST_DLHOF(xlstrhs),DLKOF(xcmd));
  2460.  
  2461. return xlstlhs;
  2462. }
  2463.  
  2464. // xlstunlink -- remove string from list
  2465. xcmd_p
  2466. xlstunlink(xlst_p xlst,xcmd_p xcmd)
  2467. {
  2468.  
  2469. dlkunlink(XLST_DLHOF(xlst),DLKOF(xcmd));
  2470.  
  2471. return xcmd;
  2472. }
  2473.  
  2474. // xlstcnt -- calculate string count
  2475. int
  2476. xlstcnt(xlst_p xlst)
  2477. {
  2478.  
  2479. return dlhcnt(XLST_DLHOF(xlst));
  2480. }
  2481.  
  2482. // xlstshow -- output a list
  2483. void
  2484. xlstshow(xlst_p xlst,const char *reason)
  2485. {
  2486.  
  2487. dlhshow(XLST_DLHOF(xlst),reason);
  2488. }
  2489. % xstr.c
  2490. // shpipe/xstr -- "smart" string "class" for C
  2491.  
  2492. #include <shpipe.h>
  2493.  
  2494. xstr_p xstrpool;
  2495.  
  2496. // xstragain -- reset string buffer
  2497. void
  2498. xstragain(xstr_p xstr)
  2499. {
  2500.  
  2501. xstr->xstr_rhs = xstr->xstr_lhs;
  2502. }
  2503.  
  2504. // xstrnew -- allocate string buffer
  2505. xstr_p
  2506. xstrnew(void)
  2507. {
  2508. xstr_p xstr;
  2509.  
  2510. do {
  2511. xstr = xstrpool;
  2512.  
  2513. if (xstr == NULL) {
  2514. xstr = syscalloc(1,sizeof(xstr_t),SYSMAGIC_XSTR);
  2515. xstr->xstr_magic = SYSMAGIC_XSTR;
  2516. break;
  2517. }
  2518.  
  2519. xstrpool = xstr->xstr_next;
  2520. xstragain(xstr);
  2521.  
  2522. xstr->xstr_prev = NULL;
  2523. xstr->xstr_next = NULL;
  2524. } while (0);
  2525.  
  2526. xstr->xstr_file = parseinfo.xstr_file;
  2527. xstr->xstr_lno = parseinfo.xstr_lno;
  2528. xstr->xstr_fpos = parseinfo.xstr_fpos;
  2529.  
  2530. xstr->xstr_bufptr = parsebuf;
  2531. xstr->xstr_bufoff = (parsecur - parsebuf) - 1;
  2532.  
  2533. xstr->xstr_type = 0;
  2534. xstr->xstr_opt = 0;
  2535.  
  2536. return xstr;
  2537. }
  2538.  
  2539. // xstrgrow -- grow string buffer
  2540. void
  2541. xstrgrow(xstr_p xstr,size_t needlen)
  2542. {
  2543. size_t curlen;
  2544. size_t newlen;
  2545. char *lhs;
  2546.  
  2547. lhs = xstr->xstr_lhs;
  2548.  
  2549. // get amount we're currently using
  2550. curlen = xstr->xstr_rhs - lhs;
  2551.  
  2552. // get amount we'll need after adding the whatever
  2553. newlen = curlen + needlen + 1;
  2554.  
  2555. // allocate more if we need it
  2556. if ((newlen + 1) >= xstr->xstr_maxlen) {
  2557. // allocate what we'll need plus a bit more so we're not called on
  2558. // each add operation
  2559. xstr->xstr_maxlen = newlen + 100;
  2560.  
  2561. // get more memory
  2562. lhs = realloc(lhs,xstr->xstr_maxlen);
  2563. xstr->xstr_lhs = lhs;
  2564.  
  2565. // adjust the append pointer
  2566. xstr->xstr_rhs = lhs + curlen;
  2567. }
  2568. }
  2569.  
  2570. // xstraddchar -- add character to string
  2571. void
  2572. xstraddchar(xstr_p xstr,int chr)
  2573. {
  2574.  
  2575. // get more space in string buffer if we need it
  2576. xstrgrow(xstr,1);
  2577.  
  2578. // add the character
  2579. *xstr->xstr_rhs++ = chr;
  2580.  
  2581. // maintain the sentinel/EOS as we go along
  2582. *xstr->xstr_rhs = 0;
  2583. }
  2584.  
  2585. // xstraddstr -- add string to string
  2586. void
  2587. xstraddstr(xstr_p xstr,const char *str)
  2588. {
  2589. size_t len;
  2590.  
  2591. len = strlen(str);
  2592.  
  2593. // get more space in string buffer if we need it
  2594. xstrgrow(xstr,len);
  2595.  
  2596. // add the string
  2597. memcpy(xstr->xstr_rhs,str,len);
  2598. xstr->xstr_rhs += len;
  2599.  
  2600. // maintain the sentinel/EOS as we go along
  2601. *xstr->xstr_rhs = 0;
  2602. }
  2603.  
  2604. // xstrclean -- clean the pool
  2605. void
  2606. xstrclean(void)
  2607. {
  2608. xstr_p cur;
  2609. xstr_p next;
  2610.  
  2611. for (cur = xstrpool; cur != NULL; cur = next) {
  2612. next = cur->xstr_next;
  2613. _xstrfree(cur);
  2614. }
  2615.  
  2616. xstrpool = NULL;
  2617. }
  2618.  
  2619. // xstrfree -- release string buffer data
  2620. xstr_p
  2621. xstrfree(xstr_p xstr)
  2622. {
  2623.  
  2624. if (xstr != NULL) {
  2625. #if XMEMCHK
  2626. _xstrfree(xstr);
  2627. #else
  2628. xstr->xstr_prev = NULL;
  2629. xstr->xstr_next = xstrpool;
  2630. xstrpool = xstr;
  2631. #endif
  2632. xstr = NULL;
  2633. }
  2634.  
  2635. return xstr;
  2636. }
  2637.  
  2638. // _xstrfree -- release string buffer data
  2639. void
  2640. _xstrfree(xstr_p xstr)
  2641. {
  2642. char *lhs;
  2643.  
  2644. if (xstr != NULL) {
  2645. lhs = xstr->xstr_lhs;
  2646.  
  2647. if (lhs != NULL)
  2648. free(lhs);
  2649.  
  2650. sysfree(xstr);
  2651. }
  2652. }
  2653.  
  2654. // xstrshow -- show string contents
  2655. void
  2656. xstrshow(xstr_p xstr)
  2657. {
  2658.  
  2659. _dbgprt("xstrshow: TOKEN %s\n",_xstrshow(xstr));
  2660. }
  2661.  
  2662. // _xstrshow -- show string contents
  2663. char *
  2664. _xstrshow(xstr_p xstr)
  2665. {
  2666. char *bp;
  2667. char *bf;
  2668.  
  2669. bf = strtmp();
  2670. bp = bf;
  2671.  
  2672. bp += sprintf(bp,"[xstr=%p",xstr);
  2673.  
  2674. if (xstr != NULL)
  2675. bp += sprintf(bp," xstr_opt=%s xstr_lhs='%s'",
  2676. strtgb(opt_tgb,xstr->xstr_opt),xstrcstr(xstr));
  2677.  
  2678. bp += sprintf(bp,"]");
  2679.  
  2680. return bf;
  2681. }
  2682.  
  2683. // xstrfree_dlv -- release string buffer data
  2684. void
  2685. xstrfree_dlv(dlk_p dlk)
  2686. {
  2687.  
  2688. xstrfree((xstr_p) dlk);
  2689. }
  2690.  
  2691. // xstrshow_dlv -- show data
  2692. void
  2693. xstrshow_dlv(dlk_p dlk,const char *reason)
  2694. {
  2695.  
  2696. xstrshow((xstr_p) dlk);
  2697. }
  2698. % shpipe.proto
  2699. // /home/cae/preserve/ovrgen/shpipe/shpipe.proto -- prototypes
  2700.  
  2701. // FILE: /home/cae/preserve/ovrbnc/shpipe/dlk.c
  2702. // shpipe/dlk -- "smart" list "class" for C
  2703.  
  2704. // dlhfree -- free list
  2705. dlh_p
  2706. dlhfree(dlh_p dlh);
  2707.  
  2708. // _dlhfree -- clean list
  2709. dlh_p
  2710. _dlhfree(dlh_p dlh);
  2711.  
  2712. // dlkpush -- append string to end of list
  2713. dlk_p
  2714. dlkpush(dlh_p dlh,dlk_p dlk);
  2715.  
  2716. // dlhcut -- cut out entry and split list
  2717. void
  2718. dlhcut(dlh_p dlhlhs,dlh_p dlhrhs,dlk_p dlk);
  2719.  
  2720. // dlkunlink -- remove item from list
  2721. dlk_p
  2722. dlkunlink(dlh_p dlh,dlk_p dlk);
  2723.  
  2724. // dlhcnt -- calculate item count
  2725. int
  2726. dlhcnt(dlh_p dlh);
  2727.  
  2728. // dlhshow -- output a list
  2729. void
  2730. dlhshow(dlh_p dlh,const char *reason);
  2731.  
  2732. // FILE: /home/cae/preserve/ovrbnc/shpipe/parse.c
  2733. // shpipe/parse -- line parser
  2734. //
  2735. // NOTE: split on "&" first before ";"
  2736.  
  2737. // parseline -- line buffer parser
  2738. xcmd_p
  2739. parseline(char *buf);
  2740.  
  2741. // parsenew -- add char
  2742. void
  2743. parsenew(int chr,int type);
  2744.  
  2745. // parsequo -- parse quoted string
  2746. void
  2747. parsequo(int quo);
  2748.  
  2749. // tokmatch1 -- find a given token based on type and prefix value
  2750. int
  2751. tokmatch1(xstr_p xstr,int type,const char *src);
  2752.  
  2753. // tokmatch2 -- find a given token based on type and exact value
  2754. int
  2755. tokmatch2(xstr_p xstr,int type,const char *src);
  2756.  
  2757. // errprt -- show parsing error
  2758. void
  2759. errprt(xlst_p xlst,xcmd_p xcmd,xstr_p xstr,const char *fmt,...) __attribute__((__format__(__printf__,4,5)));
  2760.  
  2761. // FILE: /home/cae/preserve/ovrbnc/shpipe/pipe.c
  2762. // shpipe/pipe -- pipeline control
  2763.  
  2764. // cmdpipefork -- attach pipe to given command in pipeline
  2765. int
  2766. cmdpipefork(xcmd_p xcmd,u32 popt,int pno,xcmd_p prev);
  2767.  
  2768. // cmdpipeall -- set up piped job
  2769. void
  2770. cmdpipeall(xcmd_p xcmd);
  2771.  
  2772. // cmdpipewait -- wait for pipeline to complete
  2773. void
  2774. cmdpipewait(xlst_p xlst);
  2775.  
  2776. // FILE: /home/cae/preserve/ovrbnc/shpipe/red.c
  2777. // shpipe/red -- redirection and fork/exec control
  2778.  
  2779. // cmdredall -- strip and setup redirections and fork/exec job
  2780. void
  2781. cmdredall(xcmd_p xcmd);
  2782.  
  2783. // cmdredzone -- strip and setup redirections
  2784. void
  2785. cmdredzone(xcmd_p xcmd);
  2786.  
  2787. // cmdredopen -- open redirection units in parent
  2788. void
  2789. cmdredopen(xcmd_p xcmd);
  2790.  
  2791. // cmdredfork -- fork job
  2792. void
  2793. cmdredfork(xcmd_p xcmd);
  2794.  
  2795. // cmdredclose -- close redirections and pipe units in parent
  2796. void
  2797. cmdredclose(xcmd_p xcmd,int errflg);
  2798.  
  2799. // FILE: /home/cae/preserve/ovrbnc/shpipe/shpipe.c
  2800. // shpipe/shpipe -- shell with pipes
  2801.  
  2802. // main -- main program
  2803. int
  2804. main(int argc,char **argv);
  2805.  
  2806. // cmdsemi -- run a job
  2807. void
  2808. cmdsemi(xcmd_p xcmd);
  2809.  
  2810. // cmdsplit -- split on token
  2811. void
  2812. cmdsplit(xlst_p xlst,xcmd_p xcmd,int type,char *sep,u32 opt);
  2813.  
  2814. // FILE: /home/cae/preserve/ovrbnc/shpipe/str.c
  2815. // shpipe/str -- string functions
  2816.  
  2817. // strtmp -- temporary persistent string buffer
  2818. char *
  2819. strtmp(void);
  2820.  
  2821. // strtgb -- display option mask
  2822. char *
  2823. strtgb(tgb_p tgb,u32 opt);
  2824.  
  2825. // FILE: /home/cae/preserve/ovrbnc/shpipe/sysf.c
  2826. // shpipe/sysf -- file descriptor leak detection
  2827.  
  2828. // _closeme -- close a unit
  2829. int
  2830. _closeme(int fd,const char *file,int lno);
  2831.  
  2832. // _xfdget -- get vector of currently open file descriptors
  2833. void
  2834. _xfdget(byte *vec);
  2835.  
  2836. // _xfdchk -- get vector of currently open file descriptors
  2837. void
  2838. _xfdchk(byte *stdvec);
  2839.  
  2840. // FILE: /home/cae/preserve/ovrbnc/shpipe/sysm.c
  2841. // shpipe/sysm -- memory leak detection
  2842.  
  2843. // _syscalloc -- get new list
  2844. void *
  2845. _syscalloc(size_t cnt,size_t len,sysmagic_t magno,const char *file,int lno);
  2846.  
  2847. // _sysfree -- free list
  2848. void
  2849. _sysfree(void *vp);
  2850.  
  2851. // _sysmchk -- check memory
  2852. void
  2853. _sysmchk(void);
  2854.  
  2855. // FILE: /home/cae/preserve/ovrbnc/shpipe/xcmd.c
  2856. // shpipe/xcmd -- "smart" list "class" for C
  2857.  
  2858. // xcmdnew -- get new list
  2859. xcmd_p
  2860. xcmdnew(void);
  2861.  
  2862. // xcmdfree -- free list
  2863. xcmd_p
  2864. xcmdfree(xcmd_p xcmd);
  2865.  
  2866. // xcmdargv -- convert list to argv
  2867. char **
  2868. xcmdargv(xcmd_p xcmd,char **argv);
  2869.  
  2870. // xcmdpush -- append string to end of list
  2871. xstr_p
  2872. xcmdpush(xcmd_p xcmd,xstr_p xstr);
  2873.  
  2874. // xcmdfind1 -- find a given token based on type and prefix value
  2875. xstr_p
  2876. xcmdfind1(xcmd_p xcmd,int type,const char *src);
  2877.  
  2878. // xcmdfind2 -- find a given token based on type and exact value
  2879. xstr_p
  2880. xcmdfind2(xcmd_p xcmd,int type,const char *src);
  2881.  
  2882. // xcmdcut -- cut out entry and split list
  2883. xcmd_p
  2884. xcmdcut(xcmd_p xcmdrhs,xstr_p xstr);
  2885.  
  2886. // xcmdunlink -- remove string from list
  2887. xstr_p
  2888. xcmdunlink(xcmd_p xcmd,xstr_p xstr);
  2889.  
  2890. // xcmdcnt -- calculate string count
  2891. int
  2892. xcmdcnt(xcmd_p xcmd);
  2893.  
  2894. // xcmdshow -- output a list
  2895. void
  2896. xcmdshow(xcmd_p xcmd,const char *reason);
  2897.  
  2898. // xcmdfree_dlv -- release string buffer data
  2899. void
  2900. xcmdfree_dlv(dlk_p dlk);
  2901.  
  2902. // xcmdshow_dlv -- show data
  2903. void
  2904. xcmdshow_dlv(dlk_p dlk,const char *reason);
  2905.  
  2906. // FILE: /home/cae/preserve/ovrbnc/shpipe/xlst.c
  2907. // shpipe/xlst -- "smart" list "class" for C
  2908.  
  2909. // xlstnew -- get new list
  2910. xlst_p
  2911. xlstnew(void);
  2912.  
  2913. // xlstfree -- free list
  2914. xlst_p
  2915. xlstfree(xlst_p xlst);
  2916.  
  2917. // xlstpush -- append string to end of list
  2918. xcmd_p
  2919. xlstpush(xlst_p xlst,xcmd_p xcmd);
  2920.  
  2921. // xlstcut -- cut out entry and split list
  2922. xlst_p
  2923. xlstcut(xlst_p xlstrhs,xcmd_p xcmd);
  2924.  
  2925. // xlstunlink -- remove string from list
  2926. xcmd_p
  2927. xlstunlink(xlst_p xlst,xcmd_p xcmd);
  2928.  
  2929. // xlstcnt -- calculate string count
  2930. int
  2931. xlstcnt(xlst_p xlst);
  2932.  
  2933. // xlstshow -- output a list
  2934. void
  2935. xlstshow(xlst_p xlst,const char *reason);
  2936.  
  2937. // FILE: /home/cae/preserve/ovrbnc/shpipe/xstr.c
  2938. // shpipe/xstr -- "smart" string "class" for C
  2939.  
  2940. // xstragain -- reset string buffer
  2941. void
  2942. xstragain(xstr_p xstr);
  2943.  
  2944. // xstrnew -- allocate string buffer
  2945. xstr_p
  2946. xstrnew(void);
  2947.  
  2948. // xstrgrow -- grow string buffer
  2949. void
  2950. xstrgrow(xstr_p xstr,size_t needlen);
  2951.  
  2952. // xstraddchar -- add character to string
  2953. void
  2954. xstraddchar(xstr_p xstr,int chr);
  2955.  
  2956. // xstraddstr -- add string to string
  2957. void
  2958. xstraddstr(xstr_p xstr,const char *str);
  2959.  
  2960. // xstrclean -- clean the pool
  2961. void
  2962. xstrclean(void);
  2963.  
  2964. // xstrfree -- release string buffer data
  2965. xstr_p
  2966. xstrfree(xstr_p xstr);
  2967.  
  2968. // _xstrfree -- release string buffer data
  2969. void
  2970. _xstrfree(xstr_p xstr);
  2971.  
  2972. // xstrshow -- show string contents
  2973. void
  2974. xstrshow(xstr_p xstr);
  2975.  
  2976. // _xstrshow -- show string contents
  2977. char *
  2978. _xstrshow(xstr_p xstr);
  2979.  
  2980. // xstrfree_dlv -- release string buffer data
  2981. void
  2982. xstrfree_dlv(dlk_p dlk);
  2983.  
  2984. // xstrshow_dlv -- show data
  2985. void
  2986. xstrshow_dlv(dlk_p dlk,const char *reason);
  2987. % Makefile
  2988. # shpipe/Makefile -- make file for shpipe
  2989. #
  2990. # SO: implementing input output redirection in a linux shell using c
  2991. # SO: 35569673
  2992.  
  2993. ifndef _shpipe_mk_
  2994. _shpipe_mk_ = 1
  2995.  
  2996. PGMTGT += shpipe
  2997. PGMTGT += shredir
  2998.  
  2999. OLIST-shpipe += dlk.o
  3000. OLIST-shpipe += parse.o
  3001. OLIST-shpipe += red.o
  3002. OLIST-shpipe += pipe.o
  3003. OLIST-shpipe += xcmd.o
  3004. OLIST-shpipe += xstr.o
  3005. OLIST-shpipe += xlst.o
  3006. OLIST-shpipe += str.o
  3007. OLIST-shpipe += sysm.o
  3008. OLIST-shpipe += sysf.o
  3009.  
  3010. DFLAGS += -I$(SDIR)
  3011. DFLAGS += -I$(GENDIR)
  3012.  
  3013. endif
  3014.  
  3015. OVRPUB := 1
  3016. # rules/rules.mk -- rules control
  3017. #
  3018. # options:
  3019. # GDB -- enable debug symbols
  3020. # 0 -- normal
  3021. # 1 -- use -O0 and define _USE_GDB_=1
  3022. #
  3023. # CLANG -- use clang instead of gcc
  3024. # 0 -- use gcc
  3025. # 1 -- use clang
  3026. #
  3027. # CVERBOSE -- build verbosity
  3028. # 0 -- normal
  3029. # 1 -- add -v to cc and -Wl,--verbose to ld
  3030. #
  3031. # M32 -- cross-build to 32 bit mode
  3032. # 0 -- native build
  3033. # 1 -- build for i386
  3034. #
  3035. # BNC -- enable benchmarks
  3036. # 0 -- normal mode
  3037. # 1 -- enable benchmarks for function enter/exit pairs
  3038. # 2 -- add min/max
  3039. #
  3040. # XCFLAGS -- extra command line CFLAGS
  3041. # XDFLAGS -- extra command line DFLAGS
  3042. #
  3043. # DOT_I -- generate preprocessor output
  3044. # DOT_S -- generate assembler output
  3045. #
  3046. # GLIB -- added options for glib
  3047. #
  3048. # symbols:
  3049. # DFLAGS -- -D options
  3050. # CFLAGS -- compiler options
  3051. #
  3052. # PREP -- targets to execute before ALL
  3053. # ALL -- things to build (automatically uses LIBNAME/PGMTGT)
  3054. #
  3055. # LIBNAME -- library name to build (e.g. foo.a) -- can be multiple
  3056. # OLIB -- list of .o files to build LIBNAME
  3057. # OLIB-<libname> -- list of .o files to build <libname>
  3058. #
  3059. # PGMTGT -- program to build (e.g. fludger) -- can be multiple
  3060. # OLIST -- list of .o files to build PGMTGT
  3061. # OLIST-<pgmname> -- list of .o files to build <pgmname>
  3062. #
  3063. # CLEAN -- things to clean (automatically uses a bunch of stuff)
  3064. #
  3065. # NOPROTO -- do not generate prototypes
  3066. # FINLINE -- allow gcc to inline functions automatically
  3067. # WNOERROR -- inhibit -Werror
  3068. # WEXTRA -- add -Wextra
  3069.  
  3070. ifdef OVRPUB
  3071. ifndef SDIR
  3072. SDIR := $(shell pwd)
  3073. STAIL := $(notdir $(SDIR))
  3074. endif
  3075.  
  3076. ifndef GENTOP
  3077. GENTOP := $(dir $(SDIR))
  3078. endif
  3079.  
  3080. ifndef GENDIR
  3081. GENDIR := $(GENTOP)/$(STAIL)
  3082. endif
  3083.  
  3084. ifndef ODIR
  3085. ODIR := $(GENDIR)
  3086. endif
  3087.  
  3088. NOPROTO := 1
  3089. endif
  3090.  
  3091. # disable prototype generation
  3092. ifdef NOPROTO
  3093. PROTOLST := true
  3094. PROTOGEN := @true
  3095. else
  3096. PROTOLST := qproto
  3097. PROTOGEN := @qproto
  3098. PROTOALL := proto
  3099. endif
  3100.  
  3101. ifndef SDIR
  3102. $(error rules: SDIR not defined)
  3103. endif
  3104. ifndef ODIR
  3105. $(error rules: ODIR not defined)
  3106. endif
  3107. ifndef GENDIR
  3108. $(error rules: GENDIR not defined)
  3109. endif
  3110. ifndef GENTOP
  3111. $(error rules: GENTOP not defined)
  3112. endif
  3113.  
  3114. ifndef _rules_mk_
  3115. _rules_mk_ = 1
  3116.  
  3117. ALL += $(LIBNAME) $(PGMTGT)
  3118. CLEAN += $(LIBNAME) $(PGMTGT)
  3119.  
  3120. ifndef NOPROTO
  3121. CLEAN += *.proto
  3122. endif
  3123.  
  3124. CLEAN += *.a
  3125. CLEAN += *.o
  3126. CLEAN += *.i
  3127. CLEAN += *.dis
  3128. CLEAN += *.TMP
  3129.  
  3130. QPROTO := $(shell $(PROTOLST) -i -l -O$(GENTOP) $(SDIR)/*.c $(CPROTO))
  3131. HDEP += $(QPROTO)
  3132.  
  3133. ###VPATH += $(GENDIR)
  3134. ###VPATH += $(SDIR)
  3135.  
  3136. ifdef INCLUDE_MK
  3137. -include $(INCLUDE_MK)
  3138. endif
  3139.  
  3140. ifdef M32
  3141. CFLAGS += -m32
  3142. endif
  3143.  
  3144. ifdef CVERBOSE
  3145. CFLAGS += -v
  3146. endif
  3147.  
  3148. ifdef GSYM
  3149. CFLAGS += -gdwarf-2
  3150. endif
  3151.  
  3152. ifdef GDB
  3153. CFLAGS += -gdwarf-2
  3154. DFLAGS += -D_USE_GDB_
  3155. else
  3156. CFLAGS += -O2
  3157. endif
  3158.  
  3159. ifdef DEBUG
  3160. DFLAGS += -DDEBUG=$(DEBUG)
  3161. endif
  3162.  
  3163. ifndef ZPRT
  3164. DFLAGS += -D_USE_ZPRT_=0
  3165. endif
  3166.  
  3167. ifdef BNC
  3168. DFLAGS += -D_USE_BNC_=$(BNC)
  3169. endif
  3170.  
  3171. ifdef GLIB
  3172. _GLIB = glib-2.0
  3173. DFLAGS += $(shell pkg-config --cflags $(_GLIB))
  3174. STDLIB += $(shell pkg-config --libs $(_GLIB))
  3175. endif
  3176.  
  3177. ifdef CLANG
  3178. CC := clang
  3179. CXX := clang++
  3180. else
  3181. ifdef CPLUS
  3182. ifeq ($(STDLIB),)
  3183. STDLIB += -lstdc++
  3184. endif
  3185. endif
  3186. endif
  3187.  
  3188. ifdef MPI
  3189. export PATH := /usr/lib64/openmpi/bin:$(PATH)
  3190. CC := mpicc
  3191. CXX := mpicxx
  3192. endif
  3193.  
  3194. DFLAGS += -I$(GENTOP)
  3195. DFLAGS += -I$(OVRTOP)
  3196. DFLAGS += -I$(OVRBNC)
  3197.  
  3198. CFLAGS += -Wall
  3199. ifndef WNOERROR
  3200. CFLAGS += -Werror
  3201. endif
  3202. ifdef WEXTRA
  3203. CFLAGS += -Wextra
  3204. endif
  3205. CFLAGS += -Wno-unknown-pragmas
  3206. CFLAGS += -Wempty-body
  3207. CFLAGS += -fno-diagnostics-color
  3208.  
  3209. ifdef DOT_I
  3210. NOLDC := @true
  3211. COPTS += -E -P
  3212. O := i
  3213. endif
  3214.  
  3215. ifdef DOT_S
  3216. NOLDC := @true
  3217. COPTS += -S
  3218. O := s
  3219. endif
  3220.  
  3221. ifndef COPTS
  3222. COPTS += -c
  3223. O := o
  3224. endif
  3225.  
  3226. ifndef FINLINE
  3227. # NOTE: we now need this to prevent inlining (enabled at -O2)
  3228. ifndef CLANG
  3229. CFLAGS += -fno-inline-small-functions
  3230. endif
  3231.  
  3232. # NOTE: we now need this to prevent inlining (enabled at -O3)
  3233. CFLAGS += -fno-inline-functions
  3234. endif
  3235.  
  3236. ifndef LDC
  3237. ifdef CPLUS
  3238. LDC = $(CXX)
  3239. else
  3240. LDC = $(CC)
  3241. endif
  3242. endif
  3243.  
  3244. # FIXME/CAE -- gold wiki page says use -Wl but it seems to have no effect
  3245. ifndef CLANG
  3246. ###LDC += -Wl,-fuse-ld=ld.blah
  3247. endif
  3248.  
  3249. ifdef CVERBOSE
  3250. LDC += -Wl,-verbose=2
  3251. endif
  3252.  
  3253. CFLAGS += $(XCFLAGS)
  3254. DFLAGS += $(XDFLAGS)
  3255.  
  3256. CFLAGS += $(DFLAGS)
  3257. endif
  3258.  
  3259. all: $(PREP) $(PROTOALL) $(ALL)
  3260.  
  3261. # C
  3262. %.o: %.c $(HDEP)
  3263. $(CC) $(CFLAGS) $(COPTS) -o $*.$(O) $<
  3264.  
  3265. %.i: %.c
  3266. cpp $(DFLAGS) -P $*.c > $*.i
  3267.  
  3268. %.s: %.c
  3269. $(CC) $(CFLAGS) -S -o $*.s $<
  3270.  
  3271. # C++
  3272. %.o: %.cpp $(HDEP)
  3273. $(CXX) $(CFLAGS) $(COPTS) -o $*.$(O) $<
  3274.  
  3275. %.i: %.cpp
  3276. cpp $(DFLAGS) -P $*.cpp > $*.i
  3277.  
  3278. %.s: %.cpp
  3279. $(CXX) $(CFLAGS) -S -o $*.s $<
  3280.  
  3281. # asm
  3282. %.o: %.s $(HDEP)
  3283. $(AS) $(AFLAGS) -o $*.$(O) $<
  3284.  
  3285. %.o: %.S $(HDEP)
  3286. $(CC) $(CFLAGS) $(COPTS) -o $*.$(O) $<
  3287.  
  3288. .SECONDEXPANSION:
  3289.  
  3290. # build a library (type (2) build)
  3291. $(LIBNAME):: $(OLIB) $$(OLIB-$$@)
  3292. $(NOLDC) ar rv $@ $^
  3293.  
  3294. # build programs
  3295. $(PGMTGT):: [email protected] $(OLIST) $$(OLIST-$$@) $(LIBLIST)
  3296. $(NOLDC) $(LDC) $(CFLAGS) -o $@ $^ $(STDLIB)
  3297.  
  3298. .PHONY: proto
  3299. proto::
  3300. $(PROTOGEN) -i -v -O$(GENTOP) $(SDIR)/*.c $(CPROTO)
  3301.  
  3302. .PHONY: clean
  3303. clean::
  3304. rm -f $(CLEAN)
  3305.  
  3306. .PHONY: help
  3307. help::
  3308. egrep '^#' Makefile
Advertisement
Add Comment
Please, Sign In to add comment