home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume06 / filta < prev    next >
Encoding:
Text File  |  1991-08-27  |  25.0 KB  |  1,022 lines

  1. Path: wugate!wucs1!uunet!allbery
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Newsgroups: comp.sources.misc
  4. Subject: v06i070: filta - a filter builder.
  5. Message-ID: <51364@uunet.UU.NET>
  6. Date: 22 Mar 89 05:30:31 GMT
  7. Sender: allbery@uunet.UU.NET
  8. Reply-To: tcjones@watdragon.waterloo.edu (speedboat jones)
  9. Organization: U. of Waterloo, Ontario
  10. Lines: 1009
  11. Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  12.  
  13. Posting-number: Volume 6, Issue 70
  14. Submitted-by: tcjones@watdragon.waterloo.edu (speedboat jones)
  15. Archive-name: filta
  16.  
  17. [Personally, I use "perl" -- except on uunet, which doesn't have a binary
  18. despite having source, and on ncoast, where perl is a real pig.  Oh, well.
  19. ;-)  ++bsa]
  20.  
  21. I (think) am leaving the net world soon and have decided to post a few
  22. silly things to comp.sources.misc. This code is not wonderful or
  23. beautiful etc, but it does work and is fun. I don't think I'll be
  24. around for more than a couple more months at most and so wont be doing
  25. much in the way of bug hunting etc.
  26.  
  27. This is called "filta" and it is a filter builder. It writes C programs
  28. to carry out simple filtering tasks. It is not intended to compete with
  29. awk or sed or perl or other such things, but it does make many things
  30. easier and faster, and it gives you C code to play with. I use it very
  31. often when I want to do the same filtering job over and over again
  32. (this produces an a.out file for you), or when I want to write a
  33. special purpose filter for large amounts of input that I don't feel
  34. like feeding to something that is an interpreter.
  35.  
  36. See the README for details. This will probably only work on BSD-like
  37. systems.
  38.  
  39. Terry Jones
  40.  
  41.     Department Of Computer Science,  University Of Waterloo
  42.     Waterloo Ontario Canada N2L 3G1. Phone: 1-519-8884674
  43.     UUCP:                    ...!watmath!watdragon!tcjones
  44.     CSNET, Internet, CDNnet: tcjones@dragon.waterloo.{cdn,edu}
  45.     BITNET:                  tcjones@WATER.bitnet
  46.     Canadian domain:         tcjones@dragon.uwaterloo.ca
  47.  
  48.  
  49.  
  50. #! /bin/sh
  51. # This is a shell archive.  Remove anything before this line, then unpack
  52. # it by saving it into a file and typing "sh file".  To overwrite existing
  53. # files, type "sh file -c".  You can also feed this as standard input via
  54. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  55. # will see the following message at the end:
  56. #        "End of archive 1 (of 1)."
  57. # Contents:  filta filta/Makefile filta/README filta/filta.c
  58. #   filta/filta.h filta/tags
  59. # Wrapped by tcjones@watdragon on Wed Mar 15 12:17:34 1989
  60. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  61. if test ! -d 'filta' ; then
  62.     echo shar: Creating directory \"'filta'\"
  63.     mkdir 'filta'
  64. fi
  65. if test -f 'filta/Makefile' -a "${1}" != "-c" ; then 
  66.   echo shar: Will not clobber existing file \"'filta/Makefile'\"
  67. else
  68. echo shar: Extracting \"'filta/Makefile'\" \(67 characters\)
  69. sed "s/^X//" >'filta/Makefile' <<'END_OF_FILE'
  70. CFLAGS = -O
  71. X
  72. filta: filta.o filta.h
  73. X    cc $(CFLAGS) -o filta filta.o
  74. END_OF_FILE
  75. if test 67 -ne `wc -c <'filta/Makefile'`; then
  76.     echo shar: \"'filta/Makefile'\" unpacked with wrong size!
  77. fi
  78. # end of 'filta/Makefile'
  79. fi
  80. if test -f 'filta/README' -a "${1}" != "-c" ; then 
  81.   echo shar: Will not clobber existing file \"'filta/README'\"
  82. else
  83. echo shar: Extracting \"'filta/README'\" \(4915 characters\)
  84. sed "s/^X//" >'filta/README' <<'END_OF_FILE'
  85. What I have often wanted was some semi-automated way to produce filters
  86. written in C. That way, with some little language, one could produce a
  87. filter, compile it and run it repeatedly. Not only that, adding to the
  88. produced filter would be possible, since you would have the C code.
  89. Plus it would run quickly. I wrote enough small filters do do
  90. specialised little tasks to be sick of doing it, and so I wrote "filta"
  91. to do the job.
  92. X
  93. The language of filta is currently very small. I'd go so far as to say
  94. it's tiny. But I have found it very useful - which is more than I can
  95. say for some of the other things I've done. Here are the only tokens
  96. recognised in the language...
  97. X
  98. X
  99. X== = != < > && || if else ( ) { } f# $# n t s "string" split
  100. X
  101. Like awk, filta splits all input lines by white space (' ' and TAB).
  102. This can be changed or even turned off. The only action available is to
  103. print. The only other things you can do are comparisons and
  104. line-splitting. In the above, # refers to a positive integer. f# is
  105. equivalent to $# and refers to the #'th field on the current input
  106. line. f0 (and $0) refer to the whole line, f$ (and $$) refer to the
  107. last field.
  108. X
  109. A string enclosed in double quotes is printed - C character
  110. representations ("\n", "\t" etc etc) may be used. n, t and s are
  111. equivalent to "\n", "\t" and " " respectively. (n = newline, t = tab, s
  112. X= space).
  113. X
  114. if, else, (, ), {, }, &&, ||, ==, !=, <, and > are all used as in C. 
  115. X= is entirely equivalent to ==.
  116. X
  117. The word "split" should be followed by a string of characters that the
  118. input line should be split up on. Thus split " \t" splits on white
  119. space, split ":" splits on colons. split "" does nothing. In
  120. particular, if the first command in a filta program is a split, then
  121. the default splitting on white space is not done. So to turn off
  122. splitting altogether one does split "" first off.
  123. X
  124. There is no need to separate commands with white space. Thus f1f2 means
  125. print field one and field two, as does f1 f2 and $1$2 and $1 $2.
  126. X
  127. Here is a simple use of filta.
  128. X
  129. X    cat file | filta 'f1 "\n"'
  130. X
  131. which prints the first white space separated field of each line and
  132. then a newline. This could have also been done more simply as "filta
  133. f1n".  Here is a more complicated example.
  134. X
  135. X    cat file | filta 'if (f1 = f2) f3 else f4'
  136. X
  137. And you can probably work out what this does. Of course this could have
  138. been written as filta 'if(f1=f2)f3elsef4' for those that don't like
  139. spaces. Note the hard single quotes around the program to hide the
  140. parentheses (or double quotes) from the shell.
  141. X
  142. X    cat /etc/passwd | 
  143. X    filta 'split":" if (f1 = "tcjones") "Terry's home directory is " f6n'
  144. X
  145. etc. It is possible to leave out the "if" as well. Thus the above could
  146. have started off filta 'split":" (f1="tcjones")' etc etc.
  147. X
  148. It is also possible to split a line more than once. For example
  149. X(assuming my encrypted password contains no commas!)
  150. X
  151. X    cat /etc/passwd 
  152. X    | filta -s 'split":" if ($1="tcjones") {split"," "my office is " f2n}'
  153. X
  154. And so on.
  155. X
  156. X
  157. So what does filta actually do? Your small program is read and parsed
  158. and a simple (usually 50 odd lines) C program is produced. This is then
  159. executed by filta and as a result gets the standard input that filta
  160. was supplied with. By necessity the resulting a.out file is left in the
  161. current directory (if possible) and can (and SHOULD) be re-used. By
  162. default the source is removed before the a.out file is executed. You
  163. can arrange for the source to be kept with the -s flag.  So
  164. X
  165. X    cat file | filta -s f1 s f2n
  166. X
  167. is a filter that prints the first field, a space, the second field and
  168. a newline BUT in addition you get to keep the C source. If you want to
  169. run it again you just say
  170. X
  171. X    cat file | a.out
  172. X
  173. The source is placed in Filta.c in the current directory (if
  174. possible).  The filter program that is built can handle input lines of
  175. length up to 4K with up to 20 fields. But that's easily changed, seeing
  176. as -s gives you the source.
  177. X
  178. If you just type
  179. X
  180. X    filta -s
  181. X
  182. filta will wait for you to enter a program. This will be translated
  183. into C, the resulting code will be compiled but NOT executed. Saying
  184. X
  185. X    filta -s f1n
  186. X
  187. is not the same. This will write the C program, compile it and execute
  188. it (and will therefore sit there waiting for you to type input at it).
  189. X
  190. If filta is unable to write the current directory it puts the source in
  191. strangely named files in under /tmp and tells you where they may be found.
  192. X
  193. Also valid is 
  194. X
  195. X    filta -f <filename>
  196. X
  197. which reads the program from the file <filename>.
  198. X
  199. X
  200. X
  201. Anyway I'm not going to go any more. There are more details it is handy
  202. to know, but if you want them send me mail or read the code. filta is
  203. not meant to be an awk replacement, it just makes it easier to do some
  204. things with greater speed, and easier and MUCH faster to repeat (using
  205. the a.out produced).  It is also very useful as a starting point for
  206. the writing of your own special purpose filters. Have fun.
  207. END_OF_FILE
  208. if test 4915 -ne `wc -c <'filta/README'`; then
  209.     echo shar: \"'filta/README'\" unpacked with wrong size!
  210. fi
  211. # end of 'filta/README'
  212. fi
  213. if test -f 'filta/filta.c' -a "${1}" != "-c" ; then 
  214.   echo shar: Will not clobber existing file \"'filta/filta.c'\"
  215. else
  216. echo shar: Extracting \"'filta/filta.c'\" \(13179 characters\)
  217. sed "s/^X//" >'filta/filta.c' <<'END_OF_FILE'
  218. X/*
  219. X**
  220. X** filta.c
  221. X**
  222. X** Build filters and things. See filta.doc
  223. X** This code is something of a hack - I was just looking for an excuse 
  224. X** to write code one night. As a result it's not very easy to add to the 
  225. X** language. Comments are scarce too. Whatever.
  226. X**
  227. X** Terry Jones. (tcjones@watdragon)
  228. X**
  229. X*/
  230. X
  231. X#include "filta.h"
  232. X#include <stdio.h>
  233. X#include <errno.h>
  234. X#include <sys/types.h>
  235. X#include <sys/stat.h>
  236. X#include <sys/file.h>
  237. X#include <ctype.h>
  238. X
  239. void do_header();
  240. void do_tailer();
  241. void do_splitter();
  242. void finish_printf();
  243. void emit();
  244. int do_args();
  245. void usage();
  246. int lex();
  247. int start_lex();
  248. int fill_buf();
  249. void lex_err();
  250. int skip_white();
  251. extern FILE *fopen();
  252. extern char *index();
  253. X
  254. XFILE *in_f;
  255. XFILE *cmp_f;
  256. char *source = "Filta.c";
  257. char *object = "a.out";
  258. char *argline;
  259. char *myname;
  260. int saved_string = 0;
  261. int saved_field = 0;
  262. char args[1024];
  263. char compile_cmd[100];
  264. int input;
  265. int auto_split = 1;
  266. int lp_count = 0;
  267. int save_source = 0;
  268. int auto_exec = 1;
  269. char buf[1024];
  270. char *bufp = buf;
  271. char lexeme[1024];
  272. int end_of_file = 0;
  273. int first_tok = 1;
  274. X
  275. X
  276. main(argc, argv)
  277. int argc;
  278. char **argv;
  279. X{
  280. X    int lexval;
  281. X    int in_if = 0;
  282. X    int in_printf = 0;
  283. X    int indent = 2;
  284. X    int saved_indent;
  285. X    int just_seen_if = 0;
  286. X    char saved_args[1024];
  287. X    int comp_type;
  288. X
  289. X    myname = *argv++;
  290. X    argline = args;
  291. X    saved_args[0] = '\0';
  292. X    input = do_args(argc, argv);
  293. X    if (save_source)
  294. X        start_save_compile();
  295. X    else
  296. X        start_fast_compile();
  297. X
  298. X    do_header();
  299. X
  300. X    if (start_lex() == AUTO_SPLIT) 
  301. X        emit(indent, cmp_f, "f_count = splitter(\" \\t\");\n");
  302. X
  303. X    while((lexval = lex()) != EOF){
  304. X        switch (lexval){
  305. X
  306. X            case QUOTE:{
  307. X                if (just_seen_if == 1){
  308. X                    lp_count++;
  309. X                    emit(0, cmp_f, "\"%s\"", lexeme);
  310. X                    just_seen_if = 0;
  311. X                }
  312. X                else if (in_if == 1){
  313. X                    emit(0, cmp_f, "\"%s\"", lexeme);
  314. X                }
  315. X                else if (in_printf == 0){
  316. X                    emit(indent, cmp_f, "printf(\"%s", lexeme);
  317. X                    in_printf = 1;
  318. X                }
  319. X                else{
  320. X                    emit(0, cmp_f, "%s", lexeme);
  321. X                }
  322. X                saved_string = 1;
  323. X                saved_field = 0;
  324. X                break;
  325. X            }
  326. X
  327. X            case LPAREN:{
  328. X                if (just_seen_if != 1){   /* Let them omit the keyword "if" */
  329. X                    emit(indent, cmp_f, "if (strcmp(");
  330. X                    indent++;
  331. X                    in_if = 1;
  332. X                }
  333. X                else
  334. X                    just_seen_if = 0;
  335. X                lp_count++;
  336. X                break;
  337. X            }
  338. X
  339. X            case RPAREN:{
  340. X                char comp[3];
  341. X
  342. X                if (in_if != 1 && in_printf != 1){
  343. X                    fprintf(stderr, "%s: ) not inside an if.\n", myname);
  344. X                    exit(1);
  345. X                }
  346. X
  347. X                lp_count--;
  348. X
  349. X                if (lp_count < 0){
  350. X                    fprintf(stderr, "%s: Too many )'s\n", myname);
  351. X                    exit(1);
  352. X                }
  353. X
  354. X                if (in_printf == 1){
  355. X                    finish_printf(saved_args);
  356. X                    in_printf = 0;
  357. X                    break;
  358. X                }
  359. X
  360. X                comp[2] = '\0';
  361. X                switch (comp_type){
  362. X                    case EQ: case EQEQ: comp[0] = comp[1] = '='; break;
  363. X                    case NEQ: comp[0] = '!'; comp[1] = '='; break;
  364. X                    case LT: comp[0] = '<'; comp[1] = '\0'; break;
  365. X                    case GT: comp[0] = '>'; comp[1] = '\0'; break;
  366. X                }
  367. X
  368. X                if (lp_count == 0){
  369. X                    saved_string = saved_field = 0;
  370. X                    emit(0, cmp_f, ") %s 0)\n", comp);
  371. X                    in_if = 0;
  372. X                }
  373. X                else{
  374. X                     emit(0, cmp_f, ") %s 0", comp);
  375. X                }
  376. X
  377. X                break;
  378. X            }
  379. X
  380. X            case LBRACE:{
  381. X                emit(indent - 1, cmp_f, "{\n");
  382. X                saved_indent = indent - 1;
  383. X                break;
  384. X            }
  385. X
  386. X            case RBRACE:{
  387. X                if (in_printf == 1){
  388. X                    finish_printf(saved_args);
  389. X                    in_printf = 0;
  390. X                }
  391. X                indent = saved_indent;
  392. X                emit(indent, cmp_f, "}\n");
  393. X                break;
  394. X            }
  395. X
  396. X            case IF:{
  397. X                if (in_printf == 1){
  398. X                    finish_printf(saved_args);
  399. X                    in_printf = 0;
  400. X                }
  401. X                emit(indent, cmp_f, "if (strcmp(");
  402. X                indent++;
  403. X                just_seen_if = 1;
  404. X                in_if = 1;
  405. X                break;
  406. X            }
  407. X
  408. X            case ELSE:{
  409. X                if (in_printf == 1){
  410. X                    finish_printf(saved_args);
  411. X                    in_printf = 0;
  412. X                }
  413. X
  414. X                emit(indent - 1, cmp_f, "else\n");
  415. X                break;
  416. X            }
  417. X
  418. X            case NEQ:
  419. X            case LT:
  420. X            case GT:
  421. X            case EQ:
  422. X            case EQEQ:{
  423. X                if (saved_string != 1 && saved_field != 1){
  424. X                    fprintf(stderr, "%s: == without left operand.\n", myname);
  425. X                    exit(1);
  426. X                }
  427. X                comp_type = lexval;
  428. X                emit(0, cmp_f, ", ");
  429. X                break;
  430. X            }
  431. X
  432. X            case AND:{
  433. X                char comp[3];
  434. X                comp[2] = '\0';
  435. X                switch (comp_type){
  436. X                    case EQ: case EQEQ: comp[0] = comp[1] = '='; break;
  437. X                    case NEQ: comp[0] = '!'; comp[1] = '='; break;
  438. X                    case LT: comp[0] = '<'; comp[1] = '\0'; break;
  439. X                    case GT: comp[0] = '>'; comp[1] = '\0'; break;
  440. X                }
  441. X                if (saved_string == 1 || saved_field == 1){
  442. X                     emit(0, cmp_f, ") %s 0", comp);
  443. X                }
  444. X                emit(0, cmp_f, " && strcmp(");
  445. X                break;
  446. X            }
  447. X
  448. X            case OR:{
  449. X                char comp[3];
  450. X                comp[2] = '\0';
  451. X                switch (comp_type){
  452. X                    case EQ: case EQEQ: comp[0] = comp[1] = '='; break;
  453. X                    case NEQ: comp[0] = '!'; comp[1] = '='; break;
  454. X                    case LT: comp[0] = '<'; comp[1] = '\0'; break;
  455. X                    case GT: comp[0] = '>'; comp[1] = '\0'; break;
  456. X                }
  457. X                if (saved_string == 1 || saved_field == 1){
  458. X                     emit(0, cmp_f, ") %s 0", comp);
  459. X                }
  460. X                emit(0, cmp_f, " || strcmp(");
  461. X                break;
  462. X            }
  463. X
  464. X            case SPLIT:{
  465. X                if (lex() != QUOTE){
  466. X                    fprintf(stderr, "%s: Split must be followed by a string\n",
  467. X                        myname);
  468. X                    exit(1);
  469. X                }
  470. X
  471. X                if (in_if == 1){
  472. X                    fprintf(stderr, "\n%s: split inside an if?\n", myname);
  473. X                    exit(1);
  474. X                }
  475. X
  476. X                if (in_printf == 1){
  477. X                    finish_printf(saved_args);
  478. X                    in_printf = 0;
  479. X                }
  480. X
  481. X                if (strlen(lexeme) == 0) break;
  482. X                emit(indent, cmp_f, "f_count = splitter(\"%s\");\n", lexeme);
  483. X                break;
  484. X            }
  485. X
  486. X            default:{
  487. X                /* Field spec. */
  488. X
  489. X                char fld_str[100];
  490. X
  491. X                if (lexval == FIELD + LASTFIELD){
  492. X                    sprintf(fld_str, "f[f_count]");
  493. X                }
  494. X                else{
  495. X                    sprintf(fld_str, "f[%d]", lexval - FIELD);
  496. X                }
  497. X
  498. X                if (in_if == 1){
  499. X                    emit(0, cmp_f, "%s", fld_str);
  500. X                }
  501. X                else{
  502. X                    if (in_printf == 0){
  503. X                        emit(indent, cmp_f, "printf(\"%%s");
  504. X                        sprintf(saved_args, ", %s", fld_str);
  505. X                        in_printf = 1;
  506. X                    }
  507. X                    else{
  508. X                        emit(0, cmp_f, "%%s");
  509. X                        sprintf(saved_args, "%s, %s", saved_args, fld_str);
  510. X                    }
  511. X                }
  512. X                saved_field = 1;
  513. X                break;
  514. X            }
  515. X        }
  516. X    }
  517. X
  518. X    if (in_if == 1){
  519. X        fprintf(stderr, "\n%s: EOF inside an if?\n", myname);
  520. X        exit(1);
  521. X    }
  522. X
  523. X    if (in_printf == 1){
  524. X        finish_printf(saved_args);
  525. X    }
  526. X
  527. X    do_tailer();
  528. X    do_splitter();
  529. X    if (save_source)
  530. X        do_save_compile();
  531. X    else
  532. X        do_fast_compile();
  533. X    return 0;
  534. X}
  535. X
  536. void
  537. do_header()
  538. X{
  539. X    fprintf(cmp_f,"#include <stdio.h>\n\n#define MAXLINE 4096\n");
  540. X    fprintf(cmp_f,"#define MAXFLDS 20\n\n");
  541. X    fprintf(cmp_f, "char line[MAXLINE];\nchar copy[MAXLINE];\n");
  542. X    fprintf(cmp_f, "char *f[MAXFLDS + 1];\n\n");
  543. X    fprintf(cmp_f, "main(argc, argv)\nint argc;\nchar **argv;\n{\n");
  544. X    fprintf(cmp_f, "\tregister int f_count;\n");
  545. X    fprintf(cmp_f, "\tint i;\n\n\tfor (i = 0; i <= MAXFLDS; i++)");
  546. X    fprintf(cmp_f, "f[i] = NULL;\n");
  547. X    fprintf(cmp_f, "\twhile (gets(line))\n\t{\n\t\tf[0] = line;\n");
  548. X}
  549. X
  550. void
  551. do_tailer()
  552. X{
  553. X    fprintf(cmp_f, "\t}\n}\n");
  554. X}
  555. X
  556. void
  557. do_splitter()
  558. X{
  559. X    fprintf(cmp_f, 
  560. X        "\n\nsplitter(sep)\nchar *sep;\n");
  561. X    fprintf(cmp_f, "{\n\textern char *index();\n");
  562. X    fprintf(cmp_f, "\tchar *tmp = copy;\n\tregister int fld;\n\n");
  563. X    fprintf(cmp_f, "\tfor (fld = 1; fld <= MAXFLDS; fld++) f[fld] = NULL;\n");
  564. X    fprintf(cmp_f, "\tif (!strlen(sep) || !strlen(line)) return 0;\n");
  565. X    fprintf(cmp_f, "\tfld = 1;\n\tsprintf(copy, \"%%s\", line);\n");
  566. X    fprintf(cmp_f, "\twhile (fld < MAXFLDS){\n\t\twhile (index(sep, *tmp))\n");
  567. X    fprintf(cmp_f, "\t\t\tif (!*++tmp) return fld;\n");
  568. X    fprintf(cmp_f, "\t\tf[fld++] = tmp++;\n\t\twhile (!index(sep, *tmp))\n");
  569. X    fprintf(cmp_f, "\t\t\tif (!*++tmp) return fld;\n");
  570. X    fprintf(cmp_f, "\t\t*tmp++ = '\\0';\n\t}\n\treturn fld;\n}\n");
  571. X}
  572. X
  573. X
  574. X/* VARARGS1 */
  575. void
  576. emit(in, dest, fmt, a, b, c, d, e, f, g)
  577. int in;
  578. XFILE *dest;
  579. char *fmt, *a, *b, *c, *d, *e, *f, *g;
  580. X{
  581. X    register int i;
  582. X
  583. X    for (i=0; i<in; i++) putc('\t', dest);
  584. X    fprintf(dest, fmt, a, b, c, d, e, f, g);
  585. X}
  586. X
  587. X
  588. void
  589. finish_printf(save)
  590. char *save;
  591. X{
  592. X    if (*save){
  593. X        emit(0, cmp_f, "\"%s);\n", save);
  594. X        *save = '\0';
  595. X    }
  596. X    else{
  597. X        emit(0, cmp_f, "\");\n");
  598. X    }
  599. X    saved_string = 0;
  600. X}
  601. X
  602. int
  603. do_args(argc, argv)
  604. int argc;
  605. char **argv;
  606. X{
  607. X    if (argc == 2 && !strcmp(*argv, "-s")){
  608. X        save_source = 1;
  609. X        auto_exec = 0;
  610. X        in_f = stdin;
  611. X        return IN_FILE;
  612. X    }
  613. X
  614. X    if (argc == 1){
  615. X        usage();
  616. X        exit(1);
  617. X    }
  618. X
  619. X    if (!strcmp(*argv, "-s")){
  620. X        save_source = 1;
  621. X        argc--;
  622. X        argv++;
  623. X    }
  624. X
  625. X    if (argc == 3 && !strcmp(*argv, "-f")){
  626. X        in_f = fopen(*++argv, "r");
  627. X        if (!in_f){
  628. X            fprintf(stderr, "%s: Could not open %s\n", myname, *argv);
  629. X            exit(1);
  630. X        }
  631. X        return IN_FILE;
  632. X    }
  633. X
  634. X    /* Must be a program on the argument line. */
  635. X
  636. X    args[0] = '\0';
  637. X    while (--argc)
  638. X        sprintf(args, "%s %s", args, *argv++);
  639. X    return IN_ARGLINE;
  640. X}
  641. X
  642. void
  643. usage()
  644. X{
  645. X    fprintf(stderr, 
  646. X    "Usage: %s [-s] [-f file | program]\n", myname, myname, myname);
  647. X}
  648. X
  649. X
  650. start_save_compile()
  651. X{
  652. X    extern char *mktemp();
  653. X    char *tsrc = "/tmp/.__compile.srcXXXXXX";
  654. X    char *obj = "/tmp/.__compile.objXXXXXX";
  655. X    static char src[100];
  656. X    struct stat sbuf;
  657. X    extern int errno;
  658. X    FILE *fopen();
  659. X
  660. X    cmp_f = fopen("Filta.c", "w");
  661. X
  662. X    if (!cmp_f){
  663. X        /* Have to use our own names in /tmp */
  664. X        if (mktemp(tsrc) == (char *)-1){
  665. X            fprintf(stderr, "Could not mktemp()\n");
  666. X            exit(1);
  667. X        }
  668. X        sprintf(src, "%s.c", tsrc);
  669. X
  670. X        errno = 0;
  671. X        if (!(stat(src, sbuf) == -1 && errno == ENOENT)){
  672. X            fprintf(stderr, "Could not mktemp()\n");
  673. X            exit(1);
  674. X        }
  675. X
  676. X        if (mktemp(obj) == (char *)-1){
  677. X            fprintf(stderr, "Could not mktemp()\n");
  678. X            exit(1);
  679. X        }
  680. X
  681. X        cmp_f = fopen(src, "w");
  682. X
  683. X        if (!cmp_f){
  684. X            fprintf(stderr, "Could not fopen()\n");
  685. X            exit(1);
  686. X        }
  687. X
  688. X        source = src;
  689. X        object = obj;
  690. X
  691. X        sprintf(compile_cmd, "cd /tmp && /bin/cc -O -o %s %s", obj, src);
  692. X        fprintf(stderr, "%s source is in \"%s\"\n", myname, source);
  693. X        fprintf(stderr, "%s object is in \"%s\"\n", myname, object);
  694. X    }
  695. X    else{
  696. X        sprintf(compile_cmd, "/bin/cc -O Filta.c");
  697. X    }
  698. X}
  699. X
  700. do_save_compile()
  701. X{
  702. X    fclose(cmp_f);
  703. X    if (system(compile_cmd) == 0){
  704. X        if (auto_exec == 1){
  705. X            execl(object, 0);
  706. X            fprintf(stderr, "Could not execl(%s, 0)\n", object);
  707. X            exit(1);
  708. X        }
  709. X    }
  710. X    else{
  711. X        fprintf(stderr, "%s: Compilation did not suceed!\n", myname);
  712. X        exit(1);
  713. X    }
  714. X}
  715. X
  716. X
  717. X
  718. start_fast_compile()
  719. X{
  720. X    extern char *mktemp();
  721. X    char *tsrc = "/tmp/.__compile.srcXXXXXX";
  722. X    static char src[100];
  723. X    extern int errno;
  724. X    struct stat sbuf;
  725. X    FILE *popen();
  726. X    register int fd;
  727. X
  728. X    if (mktemp(tsrc) == (char *)-1){
  729. X        fprintf(stderr, "Could not mktemp()\n");
  730. X        exit(1);
  731. X    }
  732. X    sprintf(src, "%s.c", tsrc);
  733. X
  734. X    errno = 0;
  735. X    if (!(stat(src, sbuf) == -1 && errno == ENOENT)){
  736. X        fprintf(stderr, "Could not mktemp()\n");
  737. X        exit(1);
  738. X    }
  739. X
  740. X    if ((fd = open(src, O_CREAT | O_WRONLY, 0666)) == -1){
  741. X        fprintf(stderr, "%s: Could not open() %s\n", myname, src);
  742. X        exit(1);
  743. X    }
  744. X
  745. X    if (write(fd, "#include \"/dev/stdin\"\n", 22) != 22){
  746. X        fprintf(stderr, "%s: Could not write() %s\n", myname, src);
  747. X        exit(1);
  748. X    }
  749. X
  750. X    if (close(fd) == -1){
  751. X        fprintf(stderr, "%s: Could not close() %s\n", myname, src);
  752. X        exit(1);
  753. X    }
  754. X
  755. X    source = src;
  756. X
  757. X    sprintf(compile_cmd, "/bin/cc -O %s", src);
  758. X    cmp_f = popen(compile_cmd, "w");
  759. X
  760. X    if (!cmp_f){
  761. X        fprintf(stderr, "Could not popen(%s)\n", compile_cmd);
  762. X        exit(1);
  763. X    }
  764. X}
  765. X
  766. do_fast_compile()
  767. X{
  768. X    pclose(cmp_f); /* This waits for the cc to complete. */
  769. X    if (unlink(source) == -1)
  770. X        fprintf(stderr, "%s: Warning! could not unlink %s\n", myname, source);
  771. X    execl(object, 0);
  772. X    fprintf(stderr, "Could not execl(%s, 0)\n", object);
  773. X    exit(1);
  774. X}
  775. X
  776. X
  777. X
  778. int
  779. start_lex()
  780. X{
  781. X    if (input == IN_FILE){
  782. X        if (fill_buf(in_f) == 0)
  783. X            return EOF;
  784. X    }
  785. X    else{
  786. X        sprintf(buf, "%s", argline);
  787. X    }
  788. X
  789. X    if (skip_white() == 0) return EOF;
  790. X
  791. X    if (!strncmp(buf, tokens[SPLIT], strlen(tokens[SPLIT]))){
  792. X        return NO_AUTO_SPLIT;
  793. X    }
  794. X
  795. X    return AUTO_SPLIT;
  796. X}
  797. X
  798. int
  799. lex()
  800. X{
  801. X    register int tok;
  802. X    
  803. X    if (end_of_file == 1) return EOF;
  804. X    if (skip_white() == 0) return EOF;
  805. X    
  806. X    for (tok = 0; tok < TOKENS; tok++){
  807. X        register int tmp = strlen(tokens[tok]);
  808. X        if (strncmp(bufp, tokens[tok], tmp) == 0){
  809. X            bufp += tmp;
  810. X            if (tok != QUOTE && skip_white() == 0) end_of_file = 1;
  811. X
  812. X            switch (tok){
  813. X                case QUOTE:{
  814. X                    register char *q = index(bufp, '"');
  815. X
  816. X                    if (!q){
  817. X                        fprintf(stderr, "%s: Unmatched \" in string.\n",myname);
  818. X                        exit(1);
  819. X                    }
  820. X                    lexeme[0] = '\0';
  821. X                    strncat(lexeme, bufp, q - bufp);
  822. X                    bufp = q + 1;
  823. X                    return QUOTE;
  824. X                }
  825. X
  826. X                default:{
  827. X                    return tok;
  828. X                }
  829. X            }
  830. X
  831. X        }
  832. X    }
  833. X
  834. X    if ((*bufp == 'f' || *bufp == '$') && isdigit(*(bufp + 1))){
  835. X
  836. X        int field_no;
  837. X
  838. X        bufp++;
  839. X        field_no = atoi(bufp);
  840. X        if (field_no > MAX_FIELDS){
  841. X            fprintf(stderr, "%s: Maximum number of fields (%d) exceeeded.\n",
  842. X                myname, MAX_FIELDS);
  843. X            fprintf(stderr, "Line was \n%s\n", buf);
  844. X            exit(1);
  845. X        }
  846. X        while (isdigit(*bufp)) bufp++;
  847. X        return(FIELD + field_no);
  848. X    }
  849. X
  850. X    if ((*bufp == 'f' || *bufp == '$') && *(bufp + 1) == '$'){
  851. X        bufp += 2;
  852. X        return FIELD + LASTFIELD;
  853. X    }
  854. X
  855. X    if (*bufp == 'n'){
  856. X        sprintf(lexeme, "\\n");
  857. X        bufp++;
  858. X        return QUOTE;
  859. X    }
  860. X
  861. X    if (*bufp == 't'){
  862. X        sprintf(lexeme, "\\t");
  863. X        bufp++;
  864. X        return QUOTE;
  865. X    }
  866. X
  867. X    if (*bufp == 's'){
  868. X        sprintf(lexeme, " ");
  869. X        bufp++;
  870. X        return QUOTE;
  871. X    }
  872. X
  873. X
  874. X    lex_err();
  875. X    exit(1);
  876. X
  877. X}
  878. X
  879. int
  880. fill_buf()
  881. X{
  882. X    char *nl;
  883. X    if (fgets(buf, 1024, in_f) == NULL) return 0;
  884. X    if ((nl = index(buf, '\n'))) *nl = '\0';
  885. X    bufp = buf;
  886. X    return 1;
  887. X}
  888. X
  889. void
  890. lex_err()
  891. X{
  892. X    fprintf(stderr, "%s: Could not lex input line\n%s\n", myname, buf);
  893. X    fprintf(stderr, "Lex broke at %s\n", bufp);
  894. X}
  895. X
  896. int
  897. skip_white()
  898. X{
  899. X    while (*bufp == ' ' || *bufp == '\t') bufp++;
  900. X
  901. X    if (*bufp == '\0'){
  902. X        if (input == IN_ARGLINE) return 0;
  903. X        if (fill_buf() == 0) 
  904. X            return 0;
  905. X        if (skip_white() == 0) return 0;
  906. X    }
  907. X
  908. X    return 1;
  909. X}
  910. END_OF_FILE
  911. if test 13179 -ne `wc -c <'filta/filta.c'`; then
  912.     echo shar: \"'filta/filta.c'\" unpacked with wrong size!
  913. fi
  914. # end of 'filta/filta.c'
  915. fi
  916. if test -f 'filta/filta.h' -a "${1}" != "-c" ; then 
  917.   echo shar: Will not clobber existing file \"'filta/filta.h'\"
  918. else
  919. echo shar: Extracting \"'filta/filta.h'\" \(1061 characters\)
  920. sed "s/^X//" >'filta/filta.h' <<'END_OF_FILE'
  921. X#define TOKENS       15
  922. static char *tokens[TOKENS] = {   
  923. X                                  "\"",
  924. X                                  "(",
  925. X                                  ")", 
  926. X                                  "{", 
  927. X                                  "}", 
  928. X                                  "if", 
  929. X                                  "else", 
  930. X                                  "==", 
  931. X                                  "=", 
  932. X                                  "!=",
  933. X                                  "<",
  934. X                                  ">",
  935. X                                  "&&", 
  936. X                                  "||", 
  937. X                                  "split"
  938. X                              };
  939. X
  940. X#define MAX_FIELDS   20
  941. X
  942. X#define NO_AUTO_SPLIT -1000
  943. X#define AUTO_SPLIT -1001
  944. X
  945. X#define IN_ARGLINE 1
  946. X#define IN_FILE    2
  947. X
  948. X/*
  949. X *  Make sure that these names refer to the right spots in the array 
  950. X#define LASTFIELD    1000000
  951. X */
  952. X
  953. X#define QUOTE        0
  954. X#define LPAREN       1
  955. X#define RPAREN       2
  956. X#define LBRACE       3
  957. X#define RBRACE       4
  958. X#define IF           5
  959. X#define ELSE         6
  960. X#define EQEQ         7
  961. X#define EQ           8
  962. X#define NEQ          9
  963. X#define LT           10
  964. X#define GT           11
  965. X#define AND          12
  966. X#define OR           13
  967. X#define SPLIT        14
  968. X
  969. X#define FIELD        1000
  970. X#define LASTFIELD    1000000
  971. END_OF_FILE
  972. if test 1061 -ne `wc -c <'filta/filta.h'`; then
  973.     echo shar: \"'filta/filta.h'\" unpacked with wrong size!
  974. fi
  975. # end of 'filta/filta.h'
  976. fi
  977. if test -f 'filta/tags' -a "${1}" != "-c" ; then 
  978.   echo shar: Will not clobber existing file \"'filta/tags'\"
  979. else
  980. echo shar: Extracting \"'filta/tags'\" \(662 characters\)
  981. sed "s/^X//" >'filta/tags' <<'END_OF_FILE'
  982. Mfilta    filta.c    /^main(argc, argv)$/
  983. do_args    filta.c    /^do_args(argc, argv)$/
  984. do_fast_compile    filta.c    /^do_fast_compile()$/
  985. do_header    filta.c    /^do_header()$/
  986. do_save_compile    filta.c    /^do_save_compile()$/
  987. do_splitter    filta.c    /^do_splitter()$/
  988. do_tailer    filta.c    /^do_tailer()$/
  989. emit    filta.c    /^emit(in, dest, fmt, a, b, c, d, e, f, g)$/
  990. fill_buf    filta.c    /^fill_buf()$/
  991. finish_printf    filta.c    /^finish_printf(save)$/
  992. lex    filta.c    /^lex()$/
  993. lex_err    filta.c    /^lex_err()$/
  994. skip_white    filta.c    /^skip_white()$/
  995. start_fast_compile    filta.c    /^start_fast_compile()$/
  996. start_lex    filta.c    /^start_lex()$/
  997. start_save_compile    filta.c    /^start_save_compile()$/
  998. usage    filta.c    /^usage()$/
  999. END_OF_FILE
  1000. if test 662 -ne `wc -c <'filta/tags'`; then
  1001.     echo shar: \"'filta/tags'\" unpacked with wrong size!
  1002. fi
  1003. # end of 'filta/tags'
  1004. fi
  1005. echo shar: End of archive 1 \(of 1\).
  1006. cp /dev/null ark1isdone
  1007. MISSING=""
  1008. for I in 1 ; do
  1009.     if test ! -f ark${I}isdone ; then
  1010.     MISSING="${MISSING} ${I}"
  1011.     fi
  1012. done
  1013. if test "${MISSING}" = "" ; then
  1014.     echo You have the archive.
  1015.     rm -f ark[1-9]isdone
  1016. else
  1017.     echo You still need to unpack the following archives:
  1018.     echo "        " ${MISSING}
  1019. fi
  1020. ##  End of shell archive.
  1021. exit 0
  1022.