home *** CD-ROM | disk | FTP | other *** search
/ The UNIX CD Bookshelf / OREILLY_TUCB_UNIX_CD.iso / upt / examples / SOURCES / GRABCHAR / PART01.Z / PART01
Encoding:
Text File  |  1998-07-24  |  49.3 KB  |  1,980 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v12i049: Grabchars 1.9, get keystrokes direct from user BSD/SYSV part 1
  3. From: daniel@island.UUCP (Dan Smith "Happy Birthday James Brown G.O.S.")
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 12, Issue 49
  7. Submitted-by: daniel@island.UUCP (Dan Smith "Happy Birthday James Brown G.O.S.")
  8. Archive-name: grabchars-1.9/part01
  9.  
  10.     Here is a long overdue update to grabchars.  I now have
  11. SYS V support.  Grabchars lets you write highly interactive shell
  12. scripts, by allowing you to grab one or more keystrokes. See the
  13. README for more.  I have also included a script which allows you
  14. to generate csh menu-based scripts; you lay out the menu in your
  15. favorite editor, it writes the skeleton script.  Enjoy!
  16.  
  17.             Daniel
  18.  
  19.    dansmith@well.sf.ca.us   daniel@island.uu.net   unicom!daniel@pacbell.com
  20. ph: (415) 332 3278 (h), 491 1000 (w) disclaimer: Island's coffee was laced :-)
  21.  
  22.  
  23. #! /bin/sh
  24.  
  25. # Make a new directory for the grabchars sources, cd to it, and run kits 1
  26. # thru 2 through sh.  When all 2 kits have been run, read README.
  27.  
  28. echo "This is grabchars 1.9 kit 1 (of 2).  If kit 1 is complete, the line"
  29. echo '"'"End of kit 1 (of 2)"'" will echo at the end.'
  30. echo ""
  31. export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
  32. mkdir web 2>/dev/null
  33. echo Extracting README
  34. sed >README <<'!STUFFY!FUNK!' -e 's/X//'
  35. X                            Grabchars 1.9
  36. X
  37. X        Copyright (c) 1988, 1989, 1990, Dan Smith
  38. X
  39. X        daniel@island.uu.net dansmith@well.sf.ca.us
  40. X            unicom!daniel@pacbell.com
  41. X
  42. XWhat this is:
  43. X
  44. X    "grabchars" gets one or more keystrokes from the user, without
  45. Xrequiring them to hit return.  It was written to make all types of shell
  46. Xscripts more interactive.
  47. X
  48. X    I know that it works fine on Suns running SUN OS 3.2-4.0.3,
  49. Xan Apollo 4500 running 10.2, and a Vax 11/750 running Mt. Xinu 4.3
  50. XBSD.  System V support is there, except for the erase routine.
  51. XI'd like to see support for this on VMS, MS-DOS, OS/2, and
  52. Xwhatever else you find yourself using :-)  Tell a friend, send
  53. Xme patches.
  54. X
  55. X    You'll find uses for this in all sorts of places.  A prime
  56. Xcandidate is in your .login file, it's easy to use this to select different
  57. Xoptions.  I've provided a "demo" csh script which runs through many of the
  58. Xoptions.  For the most part, grabchars can replace the use of "$<" in
  59. Xcsh scripts and "read" in sh scripts, and offer filtering, timeouts, and
  60. Xdefault answers.  I've also provided a directory that will show
  61. Xyou an simple way to generate interactive scripts: you lay out
  62. Xthe menu, and it writes a script based on the menu - after that
  63. Xyou just fill in the details.
  64. X
  65. XPutting this together:
  66. X
  67. X    Run Config; it will figure out where you might want to
  68. Xput the executable and the man page.  It will also put you into an
  69. Xeditor with the Makefile, and then it will run a "make clean",
  70. X"make depend", and a "make release".  You will need getopt (3)
  71. Xto compile this program.  If you're not sure if you have this, try
  72. X"nm /lib/libc.a | grep getopt".  Get a Public Domain version if you
  73. Xdon't (write me if you get really stuck, I have it).
  74. X
  75. XUsage: (see the man page for more...)
  76. X
  77. X    grabchars            gets one keystroke
  78. X    grabchars -b            output to stdout and stderr
  79. X    grabchars -c<valid characters>  only <valid chars> are returned
  80. X    grabchars -d<char(s)>        default char or string to return
  81. X    grabchars -e            output to stderr instead of stdout
  82. X    grabchars -f            flush any previous input
  83. X    grabchars -h            help screen
  84. X    grabchars -n<number>        number of characters to read
  85. X    grabchars -p<prompt>        prompt to help user
  86. X    grabchars -q<prompt>        prompt to help user (through stderr)
  87. X    grabchars -r            RETURN exits (use with -n)
  88. X    grabchars -s            silent, just return status
  89. X    grabchars -t<seconds>        timeout after <seconds>
  90. X    grabchars -E            erase/kill character processing
  91. X
  92. X    examples: (values to arguments can be in the same word or the next one)
  93. X
  94. X    grabchars -caeiou     or
  95. X    grabchars -c aeiou        get one of the vowels
  96. X    grabchars -c i            get the letter 'i'
  97. X    grabchars '-penter a letter '    print the prompt "enter a letter "
  98. X    grabchars '-qenter a letter '    print the prompt ('q' for question)
  99. X                    "enter a letter " through stderr...
  100. X    grabchars -n4            get four characters
  101. X    grabchars -t2            timeout after two seconds
  102. X
  103. X    print a prompt and grab three characters...
  104. X    grabchars -p 'enter three characters >> ' -n 3
  105. X
  106. X    get two numbers with a ten second timeout...
  107. X    grabchars -c 0123456789 -n2 -t10
  108. X
  109. X    note that arguments like "-n4" or "-n 4" are handled the same way
  110. X
  111. X    grabchars -h            will give a usage screen...
  112. X
  113. XLegal paragraph:
  114. X
  115. X    Use and copy Grabchars.  Please send me any modifications
  116. Xthat you make so that I may post official patches.  Don't remove my
  117. Xheaders.  Don't say you wrote it.  I am not responsible for mishaps
  118. Xarising out of the use of this program, on the other hand, I haven't
  119. Xrun into any problems with this.  Lastly, do not use any part of
  120. Xgrabchars in any product for profit (electronic, paper, or any other
  121. Xmedia) without obtaining my written permission.
  122. X
  123. XPatches and things like that:
  124. X
  125. X    "Help! Save The World!" (LW)...if you make any modifications
  126. Xto grabchars, please send me a diff suitable for use with the patch program.
  127. XI don't want ten different versions of this running around.  The
  128. XTODO file outlines some ideas I have for grabchars.
  129. X
  130. XWhere to reach me:
  131. X
  132. X    Dan Smith
  133. X    Island Graphics
  134. X    4000 Civic Center Drive
  135. X    San Rafael, Ca 94903
  136. X    +1 (415) 491 1000 (w), 491 0402 (fax)
  137. X
  138. X    daniel@island.uu.net or    
  139. X    {pixar,grenada,ucbvax!ucbcad,unicom,well,sun,uunet}!island!daniel
  140. X
  141. X    unicom!daniel@pacbell.com
  142. X
  143. X    {apple,lll-crg}!well!dansmith
  144. X
  145. !STUFFY!FUNK!
  146. echo Extracting web/README
  147. sed >web/README <<'!STUFFY!FUNK!' -e 's/X//'
  148. X
  149. X    This directory contains:
  150. X
  151. Xgensource        called by mkmenu
  152. Xmkmenu            use to generate scripts that source each other
  153. Xscript.template        example of a menuing script (self contained)
  154. X
  155. X    The idea here is to show two ways of writing scripts
  156. Xthat use menus.  They call grabchars.
  157. X
  158. X    "script.template" is pretty straightforward.  It can be used
  159. Xas the basis of csh program contained within one file.  I show
  160. Xthe use of three aliases:  push_point, pop_point, and local_point,
  161. Xwhich allow you to break csh scripts into "functions".
  162. X
  163. X    "mkmenu" and "gensource" go further.  They allow you to have
  164. Xa directory, "menus", which contains csh files that can source each
  165. Xother.  You can set up some program with, say, 2 or 3 files, and then
  166. Xgo ahead and start using it...but, you can also write a new routine
  167. Xor two that call routines from the first program, and so on.  Eventually
  168. Xyou'll have a directory full of routines, and putting together a new
  169. X"program" would be a matter of defining a menu that ties the right
  170. Xroutines together.
  171. X
  172. !STUFFY!FUNK!
  173. echo Extracting grabchars.c
  174. sed >grabchars.c <<'!STUFFY!FUNK!' -e 's/X//'
  175. X/*
  176. X**    $Header: grabchars.c,v 1.9 89/12/29 21:14:48 daniel grabchars_1_9 $
  177. X**
  178. X**    grabchars.c    - get characters directly from the user
  179. X**
  180. X**    Dan Smith (daniel@island.uu.net), October 23, 1988
  181. X**
  182. X**    This program grabs characters from the user as they are
  183. X**    typed in, without having to wait for the return key to
  184. X**    be pressed.  Among other things, this allows shell scripts
  185. X**    to be written with highly interactive menus...
  186. X**
  187. X**    [to jump right to the code, search for "start of grabchars"]
  188. X**
  189. X**    Usage rundown:
  190. X**
  191. X**    grabchars            gets one keystroke
  192. X**    grabchars -b            output to stdout and stderr
  193. X**    grabchars -c<valid characters>  only <valid chars> are returned
  194. X**    grabchars -d<char(s)>        default char or string to return
  195. X**    grabchars -e            output to stderr instead of stdout
  196. X**    grabchars -f            flush any previous input
  197. X**    grabchars -h            help screen
  198. X**    grabchars -n<number>        number of characters to read
  199. X**    grabchars -p<prompt>        prompt to help user
  200. X**    grabchars -q<prompt>        prompt to help user (through stderr)
  201. X**    grabchars -r            RETURN key exits (use with -n)
  202. X**    grabchars -s            silent, just return status
  203. X**    grabchars -t<seconds>        timeout after <seconds>
  204. X**    grabchars -E            erase/kill character processing
  205. X**    grabchars -L            lower case mapping of chars
  206. X**    grabchars -U            upper case mapping of chars
  207. X**
  208. X**    examples: (values to arguments can be in the same word or the next one)
  209. X**
  210. X**    grabchars -caeiou     or
  211. X**    grabchars -c aeiou        get one of the vowels
  212. X**    grabchars -c i            get the letter 'i'
  213. X**    grabchars '-penter a letter '    print the prompt "enter a letter "
  214. X**    grabchars '-qenter a letter '    print the prompt ('q' for question)
  215. X**                    "enter a letter " through stderr...
  216. X**    grabchars -n4            get four characters
  217. X**    grabchars -t2            timeout after two seconds
  218. X**
  219. X**    print a prompt and grab three characters...
  220. X**    grabchars -p 'enter three characters >> ' -n 3
  221. X**
  222. X**    get two numbers with a ten second timeout...
  223. X**    grabchars -c 0123456789 -n2 -t10
  224. X**
  225. X**    map 5 characters to upper case, or default to "HELP"
  226. X**    grabchars -d "HELP" -n5 -U
  227. X**
  228. X**    note that arguments like "-n4" or "-n 4" are handled the same way
  229. X**
  230. X**    History:
  231. X**    
  232. X**    Oct 1988: versions 1.0 - 1.1
  233. X**
  234. X**    November 6, 1988 (1.15)
  235. X**    added -f flag to flush input, default is to use    TIOCSETN instead
  236. X**    of TIOCSETP
  237. X**
  238. X**    November 22, 1988 (1.16)
  239. X**    added -d flag for a default character or string to use if the
  240. X**    user hits return first thing or times out.  handle_default ()
  241. X**    was added at this time
  242. X**
  243. X**    November 23, 1988 (1.19)
  244. X**    added -r flag to exit when RETURN is hit.  This was suggested by
  245. X**    David Vezie.
  246. X**
  247. X**    November 29, 1988 (1.2)
  248. X**    Disaster strikes...I was updating Makefile.dist, and copied SRCS
  249. X**    to OBJS, and forgot to change grabchars.c to grabchars.o, and
  250. X**    then (after Config) did a "make clean"!  I realized that I did not
  251. X**    have a backup, but fortunately had David Vezie's hack of grabchars.c
  252. X**    from a few days ago (he had added erase/line kill character processing)
  253. X**    ...moral: use RCS, check your Makefiles!  Used this as an opportunity
  254. X**    to split things up into grabchars.h, globals.c,    and sys.c
  255. X**    Got -c to handle ranges (via re_comp() and re_exec())
  256. X**
  257. X**    December 12, 1988 (1.3.1)
  258. X**    This finally appeared on the net.  Grabbed it and added -U and
  259. X**    -L to do upper/lower case mapping
  260. X**
  261. X**    August 17, 1989 (1.5)
  262. X**    Finally integrated Randy's changes in for Sys V.
  263. X*/
  264. X
  265. X/*
  266. X * Changes made to allow compilation and operation under Unix System V
  267. X * Release 2 or 3 on 6/30/89 by R. J. Davis, ocrjd.att.com!randy
  268. X */
  269. X
  270. X/*    start of grabchars... */
  271. X#include <stdio.h>
  272. X#include <signal.h>
  273. X#include <ctype.h>
  274. X#include "grabchars.h"
  275. X
  276. X/*    see globals.c */
  277. Xextern FILE *outfile, *otherout;
  278. Xextern FLAG *flags;
  279. Xextern int exit_stat;
  280. Xextern char *usage_statement[];
  281. X
  282. X/*
  283. X**    David Vezie (unicom!dv) took a great shot at putting in
  284. X**    erase/kill processing.  I need to test this some more, and I'll
  285. X**    most likely change it a bit.  I put DV_ERASE in the Makefile
  286. X**    as a default; take it out if it misbehaves :-)
  287. X*/
  288. X#ifdef DV_ERASE
  289. Xextern char *erase_buf;    /* DV: Malloc'ed later */
  290. X#endif
  291. X
  292. Xmain (argc, argv)
  293. Xint argc;
  294. Xregister char **argv;
  295. X{
  296. X    /* two signal/wrapup handling routines in sys.c */
  297. X    int lets_go (), overtime ();
  298. X
  299. X    /* for -d option */
  300. X    void handle_default ();
  301. X
  302. X    /* for getopt () */
  303. X    extern int optind, opterr;
  304. X    extern char *optarg;
  305. X    char comarg;
  306. X
  307. X    int how_many = 1;    /* how many chars to read */
  308. X    int num_read;        /* how many we have read... */
  309. X    int timeout;        /* and an optional time to do it in... */
  310. X    int i;            /* for usage_statement if we need it.. */
  311. X
  312. X    /*
  313. X    **    re_comp (), re_exec () let us do things
  314. X    **    like "grabchars -c '[a-d]'" or "grabchars -c '[^a-z]'"...
  315. X    */
  316. X    char *re_comp (), *re_error;
  317. X    extern char valid_chars[128], default_string[128];
  318. X    char ch, check_str[2];
  319. X
  320. X    alarm (0);
  321. X    opterr = 0;
  322. X    exit_stat = -1;    /* if we're interrupted, exit with this status */
  323. X
  324. X    outfile = stdout;
  325. X    otherout = stderr;
  326. X    if ((flags = (FLAG *) malloc (sizeof (FLAG))) == (FLAG *) NULL) {
  327. X        fprintf (stderr, "can't find enough memory...bye!\n");
  328. X        exit (exit_stat);    /* we don't need lets_go () for this */
  329. X    }
  330. X
  331. X    init_flags ();
  332. X    init_signal ();
  333. X
  334. X    while ((comarg = getopt (argc, argv,  "befrsELUc:d:n:p:q:t:")) != EOF) {
  335. X        switch (comarg) {
  336. X            case 'b':
  337. X                flags->both = 1;
  338. X                break;
  339. X            case 'c':
  340. X                flags->check = 1;
  341. X                strcpy (valid_chars, optarg);
  342. X                if (strlen (optarg) == 0) {
  343. X                    fprintf (stderr, "-c option: must have at least one valid character\n");
  344. X                    exit (-1);
  345. X                }
  346. X                /*
  347. X                ** most of the time, grabchars can be
  348. X                ** called safely with things like
  349. X                ** "a-z", because we can check to
  350. X                ** see if we need to add brackets...
  351. X                */
  352. X                if (valid_chars[0] != '[' && 
  353. X                valid_chars[strlen (valid_chars) - 1] != ']')
  354. X                    sprintf (valid_chars, "%c%s%c",
  355. X                        '[', optarg, ']');
  356. X
  357. X                if ((re_error = re_comp (valid_chars))
  358. X                                != NULL) {
  359. X                    fprintf (stderr,
  360. X                        "-c option: %s\n", re_error);
  361. X                    exit (-1);
  362. X                }
  363. X                break;
  364. X            case 'd':
  365. X                flags->dflt = 1;
  366. X                strcpy (default_string, optarg);
  367. X                if (strlen (optarg) == 0) {
  368. X                fprintf (stderr, "-d option: must have at least one character for default\n");
  369. X                    exit (-1);
  370. X                }
  371. X                break;
  372. X            case 'e':
  373. X                outfile = stderr;
  374. X                otherout = stdout;
  375. X                break;
  376. X            case 'f':
  377. X                flags->flush = 1;
  378. X                break;
  379. X            case 'n':
  380. X                how_many = atoi (optarg);
  381. X                if (how_many <= 0) {
  382. X                    fprintf (stderr, "-n option: number of characters to read must be greater than zero\n");
  383. X                    exit (-1);
  384. X                }
  385. X                break;
  386. X            case 'p':
  387. X                fprintf (stdout, "%s", optarg);
  388. X                break;
  389. X            case 'q':
  390. X                fprintf (stderr, "%s", optarg);
  391. X                break;
  392. X            case 'r':
  393. X                flags->ret_key = 1;
  394. X                break;
  395. X            case 's':
  396. X                flags->silent = 1;
  397. X                break;
  398. X            case 't':
  399. X                timeout = atoi (optarg);
  400. X                if (timeout <= 0) {
  401. X                    fprintf (stderr, "-t option: number of seconds to timeout must be greater than zero\n");
  402. X                    exit (-1);
  403. X                }
  404. X
  405. X                /*
  406. X                ** we must have some valid time >0 seconds to
  407. X                ** get here, so we'll set an alarm...
  408. X                */
  409. X                (SIGRET) signal (SIGALRM, overtime);
  410. X                alarm ((unsigned int) timeout);
  411. X                break;
  412. X            case 'E':    /* DV: honor erase/kill flag */
  413. X#ifdef DV_ERASE
  414. X                flags->erase = 1;
  415. X#else
  416. X                fprintf (stderr, "-E is disabled\n");
  417. X                exit (-1);
  418. X#endif
  419. X                break;
  420. X
  421. X                /*
  422. X                ** upper/lower case mapping...if both
  423. X                ** are specified on the command line,
  424. X                ** the last one wins out for sanity's
  425. X                ** sake...
  426. X                */
  427. X            case 'L':
  428. X                flags->lower = 1;
  429. X                flags->upper = 0;
  430. X                break;
  431. X            case 'U':
  432. X                flags->upper = 1;
  433. X                flags->lower = 0;
  434. X                break;
  435. X
  436. X                /*
  437. X                ** I bet I could leave out "default", but
  438. X                ** I also bet that all getopt () routines
  439. X                ** are not created equal, so in it stays!
  440. X                */
  441. X            case '?':
  442. X            default:
  443. X                i = 0;
  444. X                while (usage_statement[i])
  445. X                    puts (usage_statement[i++]);
  446. X                exit (-1);
  447. X        }
  448. X    }
  449. X
  450. X    /* we're still here, really running...now change the tty... */
  451. X    init_term ();
  452. X
  453. X#ifdef DV_ERASE
  454. X    /* DV: malloc (okay, well calloc) space for the erase buffer */
  455. X    if (flags->erase) {
  456. X        /* We can't do it up in the switch, because we don't know
  457. X        ** how many is how_many
  458. X        */
  459. X        erase_buf = (char *)calloc (1, how_many);
  460. X        if (erase_buf == NULL) {
  461. X            fprintf (stderr,
  462. X            "Error:  Couldn't malloc space for erase buffer\n");
  463. X            exit_stat = -1;
  464. X            lets_go();
  465. X        }
  466. X    }
  467. X#endif
  468. X
  469. X    for (num_read = 0; num_read < how_many; num_read++) {
  470. X        ch = getchar ();
  471. X
  472. X        /* use default_string, this does *not* return */
  473. X        if (ch == '\n' && flags->dflt && num_read == 0)
  474. X            handle_default ();
  475. X
  476. X        /*
  477. X        ** set by -r, a RETURN key gets us out (use with -n)
  478. X        ** suggested by David Vezie
  479. X        */
  480. X        if (ch == '\n' && flags->ret_key)
  481. X            break;
  482. X
  483. X        /*    filter chars... */
  484. X        /*
  485. X        ** known bug.... need to check the erase/kill keys somehow
  486. X        ** the workaround is to make them part of the allowable
  487. X        ** string of chars that can be input
  488. X        */
  489. X        if (flags->check) {
  490. X            sprintf (check_str, "%c", ch);
  491. X            if (re_exec (check_str) != 1) {
  492. X                num_read--;
  493. X                continue;
  494. X            }
  495. X        }
  496. X
  497. X        /* upper/lower case mapping, added 12/12/88 */
  498. X        if (flags->upper)
  499. X            ch = mk_upper (ch);
  500. X        if (flags->lower)
  501. X            ch = mk_lower (ch);
  502. X
  503. X        /*
  504. X        ** if we're just looking for a return status
  505. X        ** then have flags->silent set (-s)
  506. X        **
  507. X        ** DV: Also, we don't want to output yet,
  508. X        ** if we're processing erase/kill charfacters.
  509. X        */
  510. X#ifdef DV_ERASE
  511. X        if (! flags->silent && ! flags->erase) {
  512. X#else
  513. X        if (! flags->silent) { 
  514. X#endif
  515. X            putc (ch, outfile);
  516. X            if (flags->both)
  517. X                putc (ch, otherout);
  518. X        }
  519. X
  520. X#ifdef DV_ERASE
  521. X        if (flags->erase)
  522. X            handle_erase (ch, &num_read);
  523. X#endif
  524. X    }
  525. X
  526. X#ifdef DV_ERASE
  527. X    if (flags->erase) {
  528. X        fprintf (outfile, "%s", erase_buf);
  529. X        if (flags->both)
  530. X            fprintf (otherout, "%s", erase_buf);
  531. X    }
  532. X#endif
  533. X
  534. X    exit_stat = num_read;
  535. X    lets_go ();
  536. X}
  537. !STUFFY!FUNK!
  538. echo Extracting web/mkmenu
  539. sed >web/mkmenu <<'!STUFFY!FUNK!' -e 's/X//'
  540. X#!/bin/csh -f
  541. X
  542. X
  543. Xgoto basic_setup
  544. X
  545. X#    start of mkscript_main_menu_routines
  546. X
  547. Xmkscript_main_menu_routines:
  548. X
  549. Xonintr mkscript_main_menu_routines
  550. X
  551. Xcat << menu_screen
  552. X`clear`
  553. X
  554. X        Mkscript Main Menu
  555. X
  556. X    !    shell
  557. X    ?    help
  558. X    a    add a menu
  559. X    e    edit a routine
  560. X    l    list menus and routines
  561. X    r    run it!
  562. X
  563. X    q    quit
  564. X
  565. Xmenu_screen
  566. X
  567. X    set noglob
  568. X    set choice=`$grabchars -q "    your choice >> " | cat -v`
  569. X    if ($choice =~ '?') set choice=help
  570. X    switch ($choice)
  571. X        case "!":
  572. X            sh
  573. X            breaksw
  574. X        case "help":
  575. X            echo -n "help..."
  576. X            push_point help_menu_routines
  577. X            breaksw
  578. X        case "a":
  579. X            echo -n "add..."
  580. X            push_point add_menu_routines
  581. X            breaksw
  582. X        case "e":
  583. X            echo -n "edit..."
  584. X            push_point edit_a_routine
  585. X            breaksw
  586. X        case "l":
  587. X            echo -n "list..."
  588. X            push_point list_routines
  589. X            breaksw
  590. X        case "r":
  591. X            echo "test run...hit ^C to exit..."
  592. X            push_point run_routines
  593. X            breaksw
  594. X        case "q":
  595. X            echo "quit..."
  596. X            exit
  597. X            breaksw
  598. X        default:
  599. X            if ($ret_pos > 1) then
  600. X                echo -n "    back..."
  601. X                pop_point
  602. X            else
  603. X                echo no such option...
  604. X            endif
  605. X            breaksw
  606. X    endsw
  607. X    goto mkscript_main_menu_routines
  608. X
  609. X#    end of mkscript_main_menu_routines
  610. X
  611. X#    start of add_menu_routines
  612. X
  613. Xadd_menu_routines:
  614. X
  615. X    echo ""
  616. X    ../gensource
  617. X    unset noglob
  618. X    set known_routines=(`ls -t *menu`)
  619. X    if (! $?real_proj_name) then
  620. X        set real_proj_name=`echo $known_routines[1]:r`
  621. X    endif
  622. X    pop_point
  623. X
  624. X#    end of add_menu_routines
  625. X
  626. X#    start of edit_a_routine
  627. Xedit_a_routine:
  628. X    echo nothing yet...
  629. X    pop_point
  630. X
  631. X#    end of edit_a_routine
  632. X
  633. X
  634. X#    start of list_routines
  635. Xlist_routines:
  636. X
  637. X    unset noglob
  638. X    set known_routines=(`ls -t *menu`)
  639. X    foreach rout ($known_routines)
  640. X        echo ""
  641. X        echo the menu "$rout:r" has these entries:
  642. X        grep 'source' $rout | awk '{ print $2 }'
  643. X        echo ""
  644. X    end
  645. X    $grabchars -s -t 30 -q 'press any key...'
  646. X
  647. X    pop_point
  648. X
  649. X#    end of list_routines
  650. X
  651. X
  652. X#    start of run_routines
  653. Xrun_routines:
  654. X
  655. X    if ( ! $?real_proj_name) then
  656. X        echo hey\! nothing to run...
  657. X        sleep 2
  658. X        pop_point
  659. X    endif
  660. X    echo name of project: $real_proj_name
  661. X    sleep 3
  662. X
  663. X    set proj_name=${real_proj_name}_run
  664. X    cp /dev/null $proj_name && chmod 755 $proj_name
  665. X
  666. X    cat << +++ >> $proj_name
  667. X#! /bin/csh -f
  668. X
  669. Xgoto basic_setup
  670. X
  671. X+++
  672. X
  673. X    cat $real_proj_name >> $proj_name
  674. X
  675. X    echo adding basic startup routine...
  676. X    cat << +++ >> $proj_name
  677. X
  678. X`echo basic_setup:`
  679. X    set base_dir=$cwd
  680. X    set menu_loop=""
  681. X
  682. X    #    these three aliases allow me to make a very flexible menu
  683. X    #    structure...you "push" every menu you go to, and pop out
  684. X    #    to get back to where you came from..
  685. X
  686. X    alias push_point 'set return_point=(\$return_point[1-\$ret_pos] \!*); @ ret_pos++; goto \!*; if (\$?pverbose) echo push_point produces \$return_point'
  687. X
  688. X    alias pop_point 'set back_pos=\$return_point[\$ret_pos]; @ ret_pos--; goto \$return_point[\$ret_pos]; if (\$?pverbose) echo push_point produces \$return_point'
  689. X
  690. X    alias local_point '@ ret_pos--; set return_point=(\$return_point[1-\$ret_pos] \!*); @ ret_pos++; if (\$?pverbose) echo local point produces \$return_point'
  691. X
  692. X    #    initialize this, just in case it gets hit...
  693. X    set back_pos=$real_proj_name
  694. X    set return_point=$real_proj_name
  695. X    @ ret_pos=0
  696. X
  697. X
  698. X    if (! \$?EDITOR) setenv EDITOR /usr/ucb/vi
  699. X    if (! \$?PAGER) setenv PAGER /usr/ucb/more
  700. X
  701. X    set this_host=\`hostname\`
  702. X    set grabchars=/usr/local/bin/grabchars
  703. X    set grab_opts=""
  704. X
  705. X    push_point $real_proj_name
  706. X
  707. X+++
  708. X    $proj_name
  709. X    pop_point
  710. X
  711. X#    end of run_routines
  712. X
  713. X
  714. X#    start of help_menu_routines
  715. X
  716. Xhelp_menu_routines:
  717. X
  718. Xcat << the_end_of_help | $PAGER
  719. X`clear`
  720. X
  721. X    Hello $USER,
  722. X
  723. X    This is only scanty documentation for what should be
  724. Xconsidered as a "work in progress", ok?
  725. X
  726. X    The main menu looks like this:
  727. X
  728. X---
  729. X        Mkscript Main Menu
  730. X
  731. X    !    shell
  732. X    ?    help
  733. X    a    add a menu
  734. X    e    edit a routine
  735. X    l    list menus and routines
  736. X    r    run it!
  737. X
  738. X    q    quit
  739. X
  740. X---
  741. X    '!' will push a shell...
  742. X    '?' got you to here
  743. X    'a' means that you are going to define a menu, this is
  744. X        accomplished by calling the script "gensource".
  745. X        What happens in that script is that you lay out
  746. X        a menu in an editor (currently $EDITOR),
  747. X        and then a csh "routine" is generated based
  748. X        on the menu.  This gives you a working menu
  749. X        to play with...afterwards you go into the
  750. X        resulting file and add whatever functionality
  751. X        you need in the routine.
  752. X    'e' is unimplemented, what it should do is allow you
  753. X        to edit an existing routine.
  754. X    'l' displays known routines and what routines are called
  755. X        from them...you would use this so that you
  756. X        could keep track of what needed to be defined in 
  757. X        an application with many menus.
  758. X    'r' ties things together and lets you do a test run on
  759. X        what you have defined.  You should hit ^C
  760. X        (or whatever you normally use as a Break character)
  761. X        to get out of your test run.  Further:  what
  762. X        'r' does is figure out what your "project" is
  763. X        by using the name of the first "routine" you've
  764. X        defined, and builds a wrapper around that routine.
  765. X        Look in the "menus" directory and you'll see that
  766. X        your main routine has a "_run" copy.  There's
  767. X        a good reason why it's a copy, you may call your
  768. X        main menu as a "submenu" in some other "application".
  769. X        Aha!  The whole idea is that you write routines,
  770. X        and can link them together by defining other
  771. X        routines, and so on... a "change directory" routine
  772. X        might be called from many different "applications".
  773. X        It's all accomplished by using the csh source
  774. X        builtin...don't go more than 20 routines deep.
  775. X        
  776. Xthe_end_of_help
  777. X    ckpager
  778. X    pop_point
  779. X
  780. X#    end of help_menu_routines
  781. X
  782. X
  783. Xbasic_setup:
  784. X    set base_dir=$cwd
  785. X
  786. X    #    these three aliases allow me to make a very flexible menu
  787. X    #    structure...you "push" every menu you go to, and pop out
  788. X    #    to get back to where you came from..
  789. X
  790. X    alias push_point 'set return_point=($return_point[1-$ret_pos] \!*); @ ret_pos++; goto \!*; if ($?pverbose) echo push_point produces $return_point'
  791. X
  792. X    alias pop_point 'set back_pos=$return_point[$ret_pos]; @ ret_pos--; goto $return_point[$ret_pos]; if ($?pverbose) echo push_point produces $return_point'
  793. X
  794. X    alias local_point '@ ret_pos--; set return_point=($return_point[1-$ret_pos] \!*); @ ret_pos++; if ($?pverbose) echo local point produces $return_point'
  795. X
  796. X    #    initialize this, just in case it gets hit...
  797. X    set back_pos="mkscript_main_menu_routines"
  798. X    set return_point="mkscript_main_menu_routines"
  799. X    @ ret_pos=0
  800. X
  801. X
  802. X    if (! $?EDITOR) setenv EDITOR /usr/ucb/vi
  803. X    if (! $?PAGER) setenv PAGER /usr/ucb/more
  804. X    alias     ckpager 'if ($PAGER =~ *more*) $grabchars -f -p "...press any key..."'
  805. X
  806. X    set this_host=`hostname`
  807. X    set grabchars=grabchars # this should be /usr/local/bin/grabchars
  808. X    set grab_opts=""
  809. X
  810. X    setenv RUNNING_MKSCRIPT
  811. X    set known_routines=""
  812. X
  813. X    if ( ! -d menus) then
  814. X        echo creating menu dir...
  815. X        mkdir menus
  816. X    endif
  817. X    cd menus
  818. X
  819. X    push_point mkscript_main_menu_routines
  820. !STUFFY!FUNK!
  821. echo Extracting sys.c
  822. sed >sys.c <<'!STUFFY!FUNK!' -e 's/X//'
  823. X/*
  824. X**    $Header: sys.c,v 1.9 89/12/29 21:14:55 daniel grabchars_1_9 $
  825. X**
  826. X**    sys.c - terminal routines for grabchars
  827. X**
  828. X**    Dan Smith (daniel@island.uu.net), November 29, 1988
  829. X**
  830. X**    History:
  831. X**
  832. X**    December 2, 1988
  833. X**    made #ifdefs for DV_ERASE and BSD, wrote notes in handle_erase ()
  834. X**    for changes and improvements
  835. X**
  836. X**    May 11, 1989
  837. X**    Started to add SYS_V code
  838. X**
  839. X**    December 26, 1989
  840. X**    added flush/no flush for System V
  841. X*/
  842. X
  843. X#include <stdio.h>
  844. X#include <signal.h>
  845. X#include "grabchars.h"
  846. X
  847. X
  848. X#ifdef BSD
  849. X#    include <sgtty.h>
  850. X    struct sgttyb orig, new;
  851. X#endif /* BSD */
  852. X
  853. X#ifdef SYS_V
  854. X#    include <termio.h>
  855. X    struct termio orig, new;
  856. X#endif /* SYS_V */
  857. X
  858. X
  859. X/* all declared in globals.c */
  860. Xextern FILE *outfile, *otherout;
  861. Xextern FLAG *flags;
  862. Xextern int exit_stat;
  863. Xextern char default_string[128];
  864. X
  865. X#ifdef DV_ERASE
  866. Xextern char *erase_buf;
  867. X#endif
  868. X
  869. X/* initialize global flags */
  870. Xinit_flags ()
  871. X{
  872. X    flags->both = 0;
  873. X    flags->check = 0;
  874. X    flags->dflt = 0;
  875. X    flags->flush = 0;
  876. X    flags->ret_key = 0;
  877. X    flags->silent = 0;
  878. X    flags->erase = 0;
  879. X    flags->lower = 0;
  880. X    flags->upper = 0;
  881. X}
  882. X
  883. X/*
  884. X**    initialize tty
  885. X*/
  886. Xinit_term ()
  887. X{
  888. X    /*    play havoc with the terminal :-) */
  889. X
  890. X#ifdef BSD
  891. X    ioctl (0, TIOCGETP, &orig);
  892. X    new = orig;
  893. X    new.sg_flags &= ~ECHO;
  894. X    new.sg_flags |= CBREAK;
  895. X
  896. X    (flags->flush) ? ioctl (0, TIOCSETP, &new) :    /* to flush... */
  897. X        ioctl (0, TIOCSETN, &new);        /* ...or not to flush */
  898. X#endif
  899. X
  900. X#ifdef SYS_V
  901. X    ioctl(0, TCGETA, &orig);           /* Added 6/30/89 for Sys V - rjd */
  902. X    new = orig;                      /* Added 6/30/89 for Sys V - rjd */
  903. X    new.c_iflag = 0;                   /* Added 6/30/89 for Sys V - rjd */
  904. X    new.c_iflag |= ICRNL | ISTRIP;     /* Added 6/30/89 for Sys V - rjd */
  905. X    new.c_lflag &= ~(ISIG | ICANON | ECHO);  /* Added 6/30/89 for Sys V - rjd */
  906. X    new.c_cc[4] = new.c_cc[5] = '\001';  /* Added 6/30/89 for Sys V - rjd */
  907. X
  908. X    /* 12/26/89....flush for SYS V...daniel */
  909. X    (flags->flush) ? ioctl(0, TCSETAF, &new) :
  910. X        ioctl(0, TCSETA, &new);
  911. X
  912. X#endif /* SYS_V */
  913. X
  914. X}
  915. X
  916. X/* handle the outside world */
  917. Xinit_signal ()
  918. X{
  919. X    int lets_go ();
  920. X
  921. X#ifdef BSD
  922. X    (SIGRET) signal (SIGTSTP, lets_go);
  923. X#endif
  924. X    (SIGRET) signal (SIGINT, lets_go);
  925. X    (SIGRET) signal (SIGQUIT, lets_go);
  926. X}
  927. X
  928. X/*
  929. X**    something's up with the user...give a useful exit status so
  930. X**    we can ask things like "do you need help?"
  931. X*/
  932. Xint overtime ()
  933. X{
  934. X    int lets_go ();
  935. X    void handle_default ();
  936. X
  937. X    /* does not return */
  938. X    if (exit_stat == -1 && flags->dflt)
  939. X        handle_default ();
  940. X
  941. X    exit_stat = -2;
  942. X    lets_go ();
  943. X}
  944. X
  945. X/*
  946. X**    the default_flag is set, and the user either typed a return
  947. X**    or timed out.  This routine does not return.
  948. X*/
  949. Xvoid handle_default ()
  950. X{
  951. X    int lets_go ();
  952. X
  953. X    if (! flags->silent) {
  954. X        fputs (default_string, outfile);
  955. X        if (flags->both || flags->ret_key)
  956. X            fputs (default_string, otherout);
  957. X    }
  958. X    exit_stat = strlen (default_string);
  959. X    lets_go ();
  960. X}
  961. X
  962. X/*    clean up and get out of here... */
  963. Xint lets_go ()
  964. X{
  965. X#ifdef BSD
  966. X    ioctl (0, TIOCSETP, &orig);
  967. X#endif
  968. X
  969. X#ifdef SYS_V
  970. X    ioctl(0, TCSETA, &orig);        /* Added 6/30/89 for Sys V - rjd */
  971. X#endif
  972. X    exit (exit_stat);
  973. X}
  974. X
  975. X#ifdef DV_ERASE
  976. X
  977. X/*
  978. X**    December 2, 1988
  979. X**    in progress notes for changing this...
  980. X**
  981. X**    first time through processing should be called as its' own
  982. X**    function from the -E case in the main (getopt ()) switch...
  983. X**
  984. X**    stdout and stderr should never be affected by any erasures...
  985. X**    (they probably are not now, I haven't thoroughly tested this...)
  986. X**
  987. X**    I need to drag in my word erase routine; never can tell how
  988. X**    long some people are going to want their lines with -n! :-)
  989. X**
  990. X**    If someone wants a control char (via literal (^V)), we should
  991. X**    give it to them...this would be more compatible with $< (csh)
  992. X**    and read (sh)... grabchars almost completely replaces these
  993. X**    now.
  994. X**
  995. X**    we can also be sensitive to pipe/no pipe via isatty ()...
  996. X*/
  997. X
  998. X/*    DV: handle erase characters, kill characters, etc. */
  999. Xhandle_erase (ch, cnt)
  1000. Xchar ch;
  1001. Xint *cnt;
  1002. X{
  1003. X    static char first = 1;
  1004. X    static char erasec, killc, werasec, lnextc, rprntc;
  1005. X    static char lnextflg = 0;
  1006. X    static char *cp;
  1007. X    static FILE *tty;
  1008. X    int i;
  1009. X
  1010. X    if (first) {
  1011. X        /* initialize static things */
  1012. X        struct sgttyb sb;
  1013. X        struct ltchars ltc;
  1014. X
  1015. X        first = 0;
  1016. X        cp = erase_buf;
  1017. X        tty = fopen ("/dev/tty", "w");
  1018. X
  1019. X        /* this isn't going to do... what if -e is set?...dan */
  1020. X        if (tty == NULL)
  1021. X            tty = stderr;
  1022. X        ioctl (0, TIOCGETP, &sb);
  1023. X        ioctl (0, TIOCGLTC, <c);
  1024. X        erasec = sb.sg_erase;
  1025. X        killc = sb.sg_kill;
  1026. X        werasec = ltc.t_werasc;
  1027. X        lnextc = ltc.t_lnextc;
  1028. X        rprntc = ltc.t_rprntc;
  1029. X    }
  1030. X
  1031. X    if (lnextflg) {
  1032. X        ch |= 0x80;
  1033. X        lnextflg = 0;
  1034. X    }
  1035. X    (*cnt) --;
  1036. X    if (ch == erasec) {
  1037. X        if (*cnt < 0)
  1038. X            return;
  1039. X        fprintf (tty, "\b \b");
  1040. X        (*cnt) --;
  1041. X        *--cp = 0;
  1042. X    } else if (ch == killc) {
  1043. X        while (*cnt >= 0) {
  1044. X            fprintf (tty, "\b \b");
  1045. X            (*cnt) --;
  1046. X            *--cp = 0;
  1047. X        }
  1048. X    } else if (ch == werasec) {
  1049. X        if (*cnt < 0)
  1050. X            return;
  1051. X        while ((cp[-1] == ' ' || cp[-1] == '\t') && (*cnt) >= 0) {
  1052. X            fprintf (tty, "\b");
  1053. X            (*cnt) --;
  1054. X            *--cp = 0;
  1055. X        }
  1056. X        while (cp[-1] != ' ' && cp[-1] != '\t' && (*cnt) >= 0) {
  1057. X            fprintf (tty, "\b \b");
  1058. X            (*cnt) --;
  1059. X            *--cp = 0;
  1060. X        }
  1061. X    } else if (ch == lnextc) {
  1062. X        lnextflg = 1;
  1063. X        fprintf (tty, "^\b");
  1064. X    } else if (ch == rprntc) {
  1065. X        for (i = strlen (erase_buf); i > 0; i--)
  1066. X            putc ('\b', tty);
  1067. X        fprintf (tty, "%s", erase_buf);
  1068. X    } else {
  1069. X        ch &= 0x7f;
  1070. X        fprintf (tty, "%c", ch);
  1071. X        *cp++ = ch;
  1072. X        (*cnt) ++;
  1073. X    }
  1074. X    fflush (tty);
  1075. X    return;
  1076. X}
  1077. X#endif
  1078. !STUFFY!FUNK!
  1079. echo Extracting grabchars.1
  1080. sed >grabchars.1 <<'!STUFFY!FUNK!' -e 's/X//'
  1081. X''' Man page for grabchars, uses Larry Wall's "patch" man page as
  1082. X''' a template.
  1083. X.de Sh
  1084. X.br
  1085. X.ne 5
  1086. X.PP
  1087. X\fB\\$1\fR
  1088. X.PP
  1089. X..
  1090. X.de Sp
  1091. X.if t .sp .5v
  1092. X.if n .sp
  1093. X..
  1094. X'''
  1095. X'''     Set up \*(-- to give an unbreakable dash;
  1096. X'''     string Tr holds user defined translation string.
  1097. X'''     Bell System Logo is used as a dummy character.
  1098. X'''
  1099. X.ie n \{\
  1100. X.tr \(bs-\*(Tr
  1101. X.ds -- \(bs-
  1102. X.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
  1103. X.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
  1104. X.ds L" ""
  1105. X.ds R" ""
  1106. X.ds L' '
  1107. X.ds R' '
  1108. X'br\}
  1109. X.el\{\
  1110. X.ds -- \(em\|
  1111. X.tr \*(Tr
  1112. X.ds L" ``
  1113. X.ds R" ''
  1114. X.ds L' `
  1115. X.ds R' '
  1116. X'br\}
  1117. X.TH GRABCHARS 1 LOCAL
  1118. X.SH NAME
  1119. Xgrabchars - get keystrokes directly from user
  1120. X.SH SYNOPSIS
  1121. X.B grabchars
  1122. X[options]
  1123. X.SH DESCRIPTION
  1124. X\fBGrabchars\fP gets characters from the user as they are
  1125. Xtyped in, without having to wait for the return key to
  1126. Xbe pressed.  Among other things, this allows shell scripts
  1127. Xto be written with highly interactive menus.
  1128. X.PP
  1129. XBy default,
  1130. X.I grabchars
  1131. Xwill obtain one character from stdin, echo that character to stdout,
  1132. Xand return with a status of one; meaning one character read.
  1133. X.TP 5
  1134. X.B \-b
  1135. XBoth
  1136. X.I stdout
  1137. Xand
  1138. X.I stderr
  1139. Xare used for output.  This is useful for setting a variable in
  1140. Xa shell script and echoing a keystroke to the screen at the
  1141. Xsame time.
  1142. X.TP 5
  1143. X.B \-c<valid characters>
  1144. XOnly characters in
  1145. X.I <valid characters>
  1146. Xare accepted.  Regular expressions such as [a-z]
  1147. Xmay be used to specify ranges.  All other characters are ignored.
  1148. X.TP 5
  1149. X.B \-d<char(s)>
  1150. XDefault char or string to output if the user hits
  1151. X.B RETURN
  1152. Xor lets
  1153. X.B grabchars
  1154. Xtimeout.  The status that is returned is the same as if the user had
  1155. Xtyped in the character or string, so this option may be used with
  1156. Xthe
  1157. X.B \-s
  1158. X(silent) flag.
  1159. X.TP 5
  1160. X.B \-e
  1161. XOutput goes to
  1162. X.I stderr
  1163. Xrather than
  1164. X.I stdout.
  1165. X.TP 5
  1166. X.B \-f
  1167. XFlush any previous input.  By default,
  1168. X.I grabchars
  1169. Xwill see any characters present in
  1170. X.I stdin,
  1171. Xwhich allows for some typeahead in shell scripts.
  1172. X.TP 5
  1173. X.B \-h
  1174. XHelp/usage screen.
  1175. X.TP 5
  1176. X.B \-p<prompt>
  1177. XSets up a prompt for the user.  See
  1178. X.I EXAMPLES.
  1179. X.TP 5
  1180. X.B \-q<prompt>
  1181. XSets up a prompt for the user, except it is printed to
  1182. X.I stderr
  1183. Xrather than
  1184. X.I stdout.
  1185. X.TP 5
  1186. X.B \-r
  1187. XThe
  1188. X.B RETURN
  1189. Xkey exits.  Use this with the -n option to allow for variable
  1190. Xnumbers of characters to be typed in.
  1191. X.TP 5
  1192. X.B \-n<number>
  1193. XNumber of characters to read.  By default,
  1194. X.I grabchars
  1195. Xlooks for one character.
  1196. X.TP 5
  1197. X.B \-s
  1198. XSilent.  Do not output anything. Just return a status.
  1199. X.TP 5
  1200. X.B \-t<seconds>
  1201. XTime to allow the user to respond.  By default, the user
  1202. Xcan take as long as he or she wants to.  The timeout option allows
  1203. Xyou to write shell scripts where you can offer some assistance
  1204. Xif it's obvious that the user might be stuck.
  1205. X.TP 5
  1206. X.B \-E
  1207. XErase/kill processing is done.  You have use of the keys (usually
  1208. XDELETE and ^U or ^X) that you would normally have from the
  1209. Xshell for deleting characters.  This is useful with the
  1210. X.B \-n
  1211. Xoption, where many characters are being typed in.  This code hasn't
  1212. Xbeen thoroughly tested, and currently only applies to a BSD compiled
  1213. Xversion.
  1214. X.TP 5
  1215. X.B \-L
  1216. XMap characters to lower case.
  1217. X.TP 5
  1218. X.B \-L
  1219. XMap characters to upper case.  Note that if \fB-U\fP and \fB-L\fP
  1220. Xare both specified on the command line, the last one that occurs
  1221. Xwill win out.  This is because it doesn't make sense to try to do
  1222. Xboth at once.
  1223. X.SH EXAMPLES
  1224. X.TP 5
  1225. X.B grabchars
  1226. Xgets one keystroke
  1227. X.TP 5
  1228. X.B grabchars \-caeiou
  1229. Xget one of the vowels
  1230. X.TP 5
  1231. X.B grabchars -c i
  1232. Xget the letter 'i'
  1233. X.TP 5
  1234. X.B grabchars '\-penter a letter '
  1235. Xprint the prompt "enter a letter "
  1236. X.TP 5
  1237. X.B grabchars '\-qenter a letter '
  1238. Xprint the prompt ('q' for question) "enter a letter " through
  1239. X.I stderr.
  1240. X.TP 5
  1241. X.B grabchars \-n4
  1242. Xget four characters.
  1243. X.TP 5
  1244. X.B grabchars \-d a
  1245. XIf the first character typed is a
  1246. X.B RETURN,
  1247. Xexpand it to 'a'.
  1248. X.TP 5
  1249. X.B grabchars \-d gumby
  1250. XIf the first character typed is a
  1251. X.B RETURN,
  1252. Xexpand it to "gumby".
  1253. X.TP 5
  1254. X.B grabchars \-r
  1255. XThe
  1256. X.B RETURN
  1257. Xkey will exit
  1258. X.I grabchars.  You would use this with the
  1259. X.B -n
  1260. Xoption, so that variable numbers of characters may be entered.
  1261. X.TP
  1262. X.B grabchars \-n 4 \-r \-t 10
  1263. XAccept up to four characters, or exit when
  1264. X.B RETURN
  1265. Xis hit, or exit when 10 seconds have elapsed.
  1266. X.TP 5
  1267. X.B grabchars \-t2
  1268. Xtimeout after two seconds.
  1269. X.TP 5
  1270. X.B grabchars \-d gumby \-t2
  1271. XIf the first character typed is a
  1272. X.B RETURN,
  1273. Xor if two seconds have gone by,
  1274. Xpretend that the user typed in "gumby".
  1275. X.TP 5
  1276. X.B grabchars \-n3 \-p 'initials: '
  1277. Xprint a prompt and grab three characters.
  1278. X.TP 5
  1279. X.B grabchars \-c 0123456789 \-n2 \-t10
  1280. Xget two numbers with a ten second timeout.
  1281. X.PP
  1282. Xnote that arguments like "-n4" or "-n 4" are handled the same way
  1283. X.SH SEE ALSO
  1284. Xcsh(1) and sh(1)
  1285. Xfor syntax of
  1286. X.I csh
  1287. Xand
  1288. X.I sh
  1289. Xscripts, respectively.
  1290. XSee "The Unix Csh Field Guide", by Gail and Paul Anderson (Prentice Hall),
  1291. Xfor an excellent tour of csh and good examples of writing csh scripts.
  1292. X.SH DIAGNOSTICS
  1293. X.I
  1294. XGrabchars
  1295. Xreturns
  1296. X.B \-2
  1297. Xif it times out, or
  1298. X.B \-1
  1299. Xif it gives a usage statement.  Otherwise, it
  1300. Xreturns the number of characters successfully read.
  1301. X.SH AUTHOR
  1302. X.nf
  1303. XDan Smith (daniel@island.uu.net or {ucbvax!ucbcad,well,sun}!island!daniel)
  1304. !STUFFY!FUNK!
  1305. echo Extracting web/gensource
  1306. sed >web/gensource <<'!STUFFY!FUNK!' -e 's/X//'
  1307. X#! /bin/csh -f
  1308. X
  1309. Xcat << +++ >! $$.menu
  1310. X        XXX Menu
  1311. X
  1312. X#    change XXX to the name of the menu, if it is the main menu then
  1313. X#    it is a good idea to indicate it, such as "Gumby Main Menu".
  1314. X#    The first word will become the name of the routine.
  1315. X#    now, put all of the options for this menu here, (or if you are just
  1316. X#    generating a template for a routine, leave it blank)... There is
  1317. X#    some documentation below for reference...
  1318. X#
  1319. X#    Your options (common ones at the end can just be uncommented):
  1320. X
  1321. X
  1322. X#    now that you are done specifying options, save the file
  1323. X#    and quit the editor, and your routine will be worked on...
  1324. X
  1325. X#    Documentation/Reference:
  1326. X#
  1327. X#    Lines can look like:
  1328. X#
  1329. X#    f    file
  1330. X#    s    sort - sort all of the info
  1331. X#    ?    help - help menu
  1332. X#
  1333. X#    General Rules:
  1334. X#        one character for the action, followed by a one word
  1335. X#        description, which will help form the name of the
  1336. X#        routine that will get called when that character is
  1337. X#        pressed...everything after is just description for the
  1338. X#        user
  1339. X#
  1340. X#        the menu will appear in alphabetical order no matter
  1341. X#        what you put at this point, you can edit that later...
  1342. X#
  1343. X#        don't put something like:
  1344. X#        s save
  1345. X#        s sort
  1346. X#        every character gets bound to a routine...
  1347. X#
  1348. X#        always try to use '?' for help to be consistent.
  1349. X
  1350. X#    Common Options:
  1351. X#    These are just suggestions for some menu entries, just uncomment
  1352. X#    them (remember, you can only use a letter once in the same menu)
  1353. X#    to use them...
  1354. X
  1355. X#    !    shell
  1356. X#    ?    help
  1357. X#    a    add
  1358. X#    c    config - change parameters
  1359. X#    D    default
  1360. X#    d    database
  1361. X#    d    display
  1362. X#    d    dump
  1363. X#    e    edit
  1364. X#    f    file
  1365. X#    f    forward
  1366. X#    f    format
  1367. X#    h    help
  1368. X#    i    init
  1369. X#    j    join
  1370. X#    k    kill - stop a process
  1371. X#    l    load
  1372. X#    l    list
  1373. X#    m    mail/messages
  1374. X#    m    merge
  1375. X#    m    main - go to main menu
  1376. X#    n    new
  1377. X#    o    open
  1378. X#    p    print
  1379. X#    q    quit
  1380. X#    r    reset
  1381. X#    r    restore
  1382. X#    s    start
  1383. X#    s    shell
  1384. X#    t    tape
  1385. X#    t    tar
  1386. X#    u    undo
  1387. X#    v    verbose
  1388. X#    w    write
  1389. X
  1390. X+++
  1391. X
  1392. Xecho going to $EDITOR...
  1393. X
  1394. X$EDITOR $$.menu
  1395. Xsed -n -e '/^[$#]/d' -e '/[a-zA-Z0-9]/p' $$.menu >! foo.$$ ;  mv -f foo.$$ $$.menu
  1396. Xsed -n -e 's/^[     ]*//p'  $$.menu >! foo.$$ ;  mv -f foo.$$ $$.menu
  1397. Xecho -n finding title...
  1398. Xset first_line=(`head -1 $$.menu`)
  1399. Xset title=`head -1 $$.menu | tr '     A-Z' '__a-z'`
  1400. Xecho -n "($title)..."
  1401. X
  1402. X@ num_lines=`wc -l $$.menu | awk ' { print $1 } '`
  1403. X@ num_lines--
  1404. Xecho -n scanning file...
  1405. Xtail -${num_lines} $$.menu | sed -e 's/^[     ]*//' | tr '/' '_'  | sort -u >! foo.$$; mv -f foo.$$ $$.menu
  1406. X
  1407. Xset noglob
  1408. Xset menu_entries=`awk ' { if ($NF >= 2) print $1 } ' $$.menu `
  1409. Xset menu_routines=`awk ' { if ($NF >= 2) print $2 } ' $$.menu `
  1410. X
  1411. Xecho setup...
  1412. X
  1413. Xset output=$title
  1414. Xcp /dev/null $output
  1415. X
  1416. Xcat << +++ >> $output
  1417. X#    start of $title
  1418. X
  1419. X${title}:
  1420. X
  1421. Xcat << menu_screen
  1422. X\`clear\`
  1423. X
  1424. X        $first_line
  1425. X
  1426. X+++
  1427. X
  1428. Xecho body of menu...
  1429. Xawk ' { printf ("\t%s\n", $0) }' $$.menu >> $output
  1430. X
  1431. Xecho switch statement...
  1432. Xcat << +++ >> $output
  1433. X
  1434. Xmenu_screen
  1435. X
  1436. X    set noglob
  1437. X    set choice=\`\$grabchars -q "    your choice >> " | cat -v\`
  1438. X    if (\$choice =~ '?') set choice=help
  1439. X    switch (\$choice)
  1440. X+++
  1441. X
  1442. X@ count=1
  1443. Xforeach item ( $menu_entries)
  1444. X    echo -n $item...
  1445. X    if ($item =~ '?') set item=help
  1446. X    cat << +++ >> $output
  1447. X        case "$item":
  1448. X            echo -n "    $menu_routines[$count]..."
  1449. X            @ ret_pos++
  1450. X            source ${menu_routines[$count]}_menu
  1451. X            @ ret_pos--
  1452. X            breaksw
  1453. X+++
  1454. X    @ count++
  1455. Xend
  1456. X
  1457. Xecho default statement...
  1458. Xcat << +++ >> $output
  1459. X        case "^L":
  1460. X        case "^R":
  1461. X            echo -n redraw...
  1462. X            breaksw
  1463. X        default:
  1464. X            if (\$ret_pos > 1) then
  1465. X                echo -n "    back..."
  1466. X                set menu_loop="false"
  1467. X            else
  1468. X                echo no such option...
  1469. X            endif
  1470. X            breaksw
  1471. X    endsw
  1472. X
  1473. X    \$menu_loop goto $title
  1474. X    set menu_loop=""
  1475. X
  1476. X#    end of ${title} 
  1477. X
  1478. X+++
  1479. Xecho cleanup....
  1480. X
  1481. Xrm $$.menu
  1482. !STUFFY!FUNK!
  1483. echo Extracting web/script.template
  1484. sed >web/script.template <<'!STUFFY!FUNK!' -e 's/X//'
  1485. X#!/bin/csh -f
  1486. X#
  1487. X#    This script is a template for csh programs that are contained
  1488. X#    within one file.  It demonstrates the use of aliases to push
  1489. X#    and pop "routines".  This is a different method from that used
  1490. X#    by mkmenu/gensource, which produce modules that source each other.
  1491. X#    Enjoy!
  1492. X#
  1493. X#    daniel@island.uu.net
  1494. X
  1495. Xgoto basic_setup
  1496. X
  1497. X#    start of template_main_menu_routines
  1498. X
  1499. Xtemplate_main_menu_routines:
  1500. X
  1501. Xonintr template_main_menu_routines
  1502. X
  1503. Xcat << menu_screen
  1504. X`clear`
  1505. X
  1506. X        Template Main Menu
  1507. X
  1508. X    !    shell
  1509. X    ?    help
  1510. X    e    edit
  1511. X    l    list
  1512. X
  1513. X    q    quit
  1514. X
  1515. Xmenu_screen
  1516. X
  1517. X    set noglob
  1518. X    set choice=`$grabchars -q "    your choice >> " | cat -v`
  1519. X    if ($choice =~ '?') set choice=help
  1520. X    switch ($choice)
  1521. X        case "!":
  1522. X            sh
  1523. X            breaksw
  1524. X        case "help":
  1525. X            echo -n "help..."
  1526. X            push_point help_menu_routines
  1527. X            breaksw
  1528. X        case "e":
  1529. X            echo -n "edit..."
  1530. X            push_point edit_routines
  1531. X            breaksw
  1532. X        case "l":
  1533. X            echo -n "list..."
  1534. X            push_point list_routines
  1535. X            breaksw
  1536. X        case "q":
  1537. X            echo "quit..."
  1538. X            exit
  1539. X            breaksw
  1540. X        default:
  1541. X            if ($ret_pos > 1) then
  1542. X                echo -n "    back..."
  1543. X                pop_point
  1544. X            else
  1545. X                echo no such option...
  1546. X            endif
  1547. X            breaksw
  1548. X    endsw
  1549. X    goto template_main_menu_routines
  1550. X
  1551. X#    end of template_main_menu_routines
  1552. X
  1553. X#    start of edit_routines
  1554. Xedit_routines:
  1555. X    cat << +++
  1556. X`clear`
  1557. X`ls -l`
  1558. X
  1559. X+++
  1560. X    set which_file=`$grabchars -b -d "a_new_file" -t 60 -n 80 -r -q 'enter a filename or just hit return >> '`
  1561. X    echo " "
  1562. X    echo going to \"$EDITOR\" with \"$which_file\"...
  1563. X    $EDITOR $which_file
  1564. X    pop_point
  1565. X
  1566. X#    end of edit_routines
  1567. X
  1568. X#    start of list_routines
  1569. Xlist_routines:
  1570. X
  1571. X    #    this demonstrates the use of local points, which
  1572. X    #    are used to break up huge "functions" up into
  1573. X    #    smaller ones..
  1574. X
  1575. X    local_point list_1
  1576. X    push_point do_list
  1577. Xlist_1:
  1578. X    echo done with list...
  1579. X    pop_point
  1580. X
  1581. X#    end of list_routines
  1582. X
  1583. X#    start of do_list
  1584. Xdo_list:
  1585. X    ls -l | $PAGER
  1586. X    $ckpager $grabchars -s -t 30 -q 'press any key...'
  1587. X    pop_point
  1588. X
  1589. X#    end of do_list
  1590. X
  1591. X#    start of help_menu_routines
  1592. X
  1593. Xhelp_menu_routines:
  1594. X
  1595. Xcat << the_end_of_help | $PAGER
  1596. X`clear`
  1597. X
  1598. X    Hello $USER,
  1599. X
  1600. X    A sample help screen
  1601. X
  1602. X    The main menu looks like this:
  1603. X
  1604. X---
  1605. X        Template Main Menu
  1606. X
  1607. X    !    shell
  1608. X    ?    help
  1609. X    e    edit
  1610. X    l    list
  1611. X
  1612. X    q    quit
  1613. X
  1614. X---
  1615. X    '!' will push a shell...
  1616. X    '?' got you to here
  1617. X    'e' edit a file
  1618. X    'l' ls -l files here
  1619. X    'q' leave
  1620. X        
  1621. Xthe_end_of_help
  1622. X    $ckpager $grabchars -f -p "...press any key..."
  1623. X    pop_point
  1624. X
  1625. X#    end of help_menu_routines
  1626. X
  1627. X
  1628. Xbasic_setup:
  1629. X    set base_dir=$cwd
  1630. X
  1631. X    #    these three aliases allow me to make a very flexible menu
  1632. X    #    structure...you "push" every menu you go to, and pop out
  1633. X    #    to get back to where you came from..
  1634. X
  1635. X    alias push_point 'set return_point=($return_point[1-$ret_pos] \!*); @ ret_pos++; goto \!*; if ($?pverbose) echo push_point produces $return_point'
  1636. X
  1637. X    alias pop_point 'set back_pos=$return_point[$ret_pos]; @ ret_pos--; goto $return_point[$ret_pos]; if ($?pverbose) echo push_point produces $return_point'
  1638. X
  1639. X    alias local_point '@ ret_pos--; set return_point=($return_point[1-$ret_pos] \!*); @ ret_pos++; if ($?pverbose) echo local point produces $return_point'
  1640. X
  1641. X    #    initialize this, just in case it gets hit...
  1642. X    set back_pos="template_main_menu_routines"
  1643. X    set return_point="template_main_menu_routines"
  1644. X    @ ret_pos=0
  1645. X
  1646. X
  1647. X    if (! $?EDITOR) setenv EDITOR /usr/ucb/vi
  1648. X    if (! $?PAGER) setenv PAGER /usr/ucb/more
  1649. X
  1650. X    set ckpager=false
  1651. X    if ($PAGER =~ *more*) then
  1652. X        set ckpager=""    # we'll need it...
  1653. X    endif
  1654. X
  1655. X    set this_host=`hostname`
  1656. X    set grabchars=grabchars # this should be /usr/local/bin/grabchars
  1657. X    set grab_opts=""
  1658. X
  1659. X    setenv RUNNING_TEMPLATE
  1660. X
  1661. X    push_point template_main_menu_routines
  1662. !STUFFY!FUNK!
  1663. echo Extracting Config
  1664. sed >Config <<'!STUFFY!FUNK!' -e 's/X//'
  1665. X#!/bin/csh -f
  1666. X#
  1667. X#    $Header: Config,v 1.9 89/12/29 21:14:18 daniel grabchars_1_9 $
  1668. X#
  1669. X#    Config - set up Makefile for grabchars
  1670. X#
  1671. X#    Dan Smith (daniel@island.uu.net), November 1988, April 1990
  1672. X#
  1673. X#    Config file for grabchars... must be csh, no attempt
  1674. X#    made to be eunice (i.e. echo " ") compatible...
  1675. X#
  1676. Xclear
  1677. Xcat << GUMBY
  1678. X
  1679. X    Config for grabchars
  1680. X
  1681. X    This csh script will figure out a few things about your
  1682. Xsystem, and then will run a "make clean", a "make depend", and
  1683. Xa "make release".  You should then try out grabchars, and, once assured
  1684. Xthat it's behaving itself, you should run a "make install"
  1685. X
  1686. XGUMBY
  1687. Xecho -n 'press return to start...'
  1688. Xset ignore=$<
  1689. X
  1690. X#    figure out where to put this when the user types
  1691. X#    "make install"...we'll try in three likely places...
  1692. X
  1693. Xforeach try_bin (/usr/local{/bin,} /usr/public/bin)
  1694. X    echo -n looking at $try_bin...
  1695. X    if (-w $try_bin) then
  1696. X        set bin_dir=$try_bin && echo yep... && break
  1697. X    endif
  1698. X    echo ""
  1699. Xend
  1700. X
  1701. X#    figure out where to put the man pages when the user
  1702. X#    "make install"...a few places come to mind...
  1703. X
  1704. Xforeach try_man (/usr/{,local/,public/}man/man1)
  1705. X    echo -n looking at $try_man...
  1706. X    if (-w $try_man) then
  1707. X        set man_dir=$try_man && echo yep... && break
  1708. X    endif
  1709. X    echo ""
  1710. Xend
  1711. X
  1712. Xif ($?bin_dir) then
  1713. X    echo BIN_DIR looks like it will be $bin_dir
  1714. Xelse
  1715. X    echo BIN_DIR is unknown...check the Makefile when it comes up...
  1716. X    set bin_dir=""
  1717. Xendif
  1718. X
  1719. Xif ($?man_dir) then
  1720. X    echo MAN_DIR looks like it will be $man_dir
  1721. Xelse
  1722. X    echo MAN_DIR is unknown...check the Makefile when it comes up...
  1723. X    set man_dir=""
  1724. Xendif
  1725. X
  1726. Xset myedit=vi
  1727. Xif ($?EDITOR) then
  1728. X    set myedit=$EDITOR
  1729. Xendif
  1730. X
  1731. Xoh_really:
  1732. X    if (! -e $myedit) then
  1733. X        echo -n "I don't see a $myedit...where is your editor? "
  1734. X        set myedit=$<
  1735. X        echo ok...
  1736. X    endif
  1737. X
  1738. Xecho editor of choice seems to be \"$myedit\"...
  1739. X
  1740. Xif  (-e Makefile) mv Makefile{,.old} >& /dev/null
  1741. X
  1742. Xecho making makefile...
  1743. Xsed    -e "s+^BIN_DIR.*+BIN_DIR = $bin_dir+" \
  1744. X    -e "s+^MAN_DIR.*+MAN_DIR = $man_dir+" \
  1745. X    -e "s+^EDITOR.*+EDITOR = $myedit+" \
  1746. X    < Makefile.dist > Makefile
  1747. X
  1748. Xecho going to $myedit with Makefile for you to check out..
  1749. Xecho -n press return...
  1750. Xset ignore=$<
  1751. X$myedit Makefile || \
  1752. X    echo where is your editor\?\!\!  && goto oh_really
  1753. X
  1754. Xecho " "
  1755. Xecho clean up any residue from before, doing a \"make clean\"
  1756. Xsleep 2
  1757. Xmake clean
  1758. X
  1759. Xecho " "
  1760. Xecho going to run a \"make depend\"...
  1761. Xsleep 2
  1762. Xmake depend
  1763. X
  1764. Xecho " "
  1765. Xecho ok, let\'s try to make this with \"make release\"
  1766. Xsleep 2
  1767. Xmake release
  1768. Xecho you can try this out with:
  1769. Xecho demo
  1770. !STUFFY!FUNK!
  1771. echo Extracting TODO
  1772. sed >TODO <<'!STUFFY!FUNK!' -e 's/X//'
  1773. XTODO file...
  1774. X
  1775. X    [Author's request:  if you implement any of this, please
  1776. X    send me a patch!  I'd appreciate it]
  1777. X
  1778. X    add support for arrow keys
  1779. X    handle control characters better...
  1780. X
  1781. X    I'm not sure what would constitute reasonable
  1782. X    return values (have negative values? values greater than 128?)
  1783. X    Is there a canonical return value list for keyboard events?
  1784. X
  1785. X
  1786. X    KEY BINDINGS/ABBREVATIONS
  1787. X
  1788. X    This can be handled in one step.  Command lines could be
  1789. X    specified as "a=1 b=2 c=3 d=error ex=expand".  This would map
  1790. X    the letter a to "1", "b" to "2", "c" to "3", "d" to "error", and
  1791. X    "ex" to "expand".
  1792. X
  1793. X    INPUT MAPPING
  1794. X
  1795. X    The present input mapping is primitive.  It would be better
  1796. X    to map on a character by character basis.  I haven't worked
  1797. X    out a complete syntax.  One possibilty is:
  1798. X
  1799. X    "Ulllnnn"
  1800. X
  1801. X    which would be an uppercase character, followed by three
  1802. X    lowercase characters, followed by three numbers.  Also:
  1803. X
  1804. X    "[aeiou]lllWUUU"
  1805. X
  1806. X    would be a vowel for the first character, followed by
  1807. X    a whitespace char (space or tab), followed by three uppercase
  1808. X    characters.
  1809. X
  1810. X    It would be good to introduce more flexibility into this:
  1811. X
  1812. X    "Ul*WUl*"
  1813. X
  1814. X    would be an uppercase character, followed by ZERO or More
  1815. X    lowercase characters, whitespace, then upper and ZERO
  1816. X    or more lowers.
  1817. X
  1818. X    c    character [A-Za-z]
  1819. X    U    uppercase char
  1820. X    l    lowercase char
  1821. X    n    number 0-9
  1822. X    p    punctuation
  1823. X    W    whitespace (SPC or TAB)
  1824. X    []    group ("c" would be [Ul])
  1825. X    *    zero or more 
  1826. X
  1827. X
  1828. X    stronger erase/kill processing...
  1829. X        check isatty ()...
  1830. X        this needs to be implemented for SYS V
  1831. X
  1832. X    default should/could occur with whitespace...not limited to return.
  1833. X        rather than add yet another flag, I think I will
  1834. X        extend the -r flag, so that you can say "-rw" or
  1835. X        "-r w" and have an *initial* whitespace (such as a TAB,
  1836. X        and aside from a RETURN, which would continue to work
  1837. X        anywhere) give the same effect as if RETURN had been typed...
  1838. X        a "-rW" or "-r W" would give you the ability to finish
  1839. X        input as soon as any whitespace had been typed...
  1840. X
  1841. X    give an option where the status returned is a count of seconds
  1842. X    that it took to answer, rather than the count of characters
  1843. X    entered....could be useful for some people
  1844. X
  1845. X    When some/all of this is implemented, and support for other
  1846. Xmachines starts coming together, I'll cobble together a 2.0.
  1847. X
  1848. X    better Makefile and Config :-)
  1849. X
  1850. X    Thatzit for now...
  1851. !STUFFY!FUNK!
  1852. echo Extracting Makefile.dist
  1853. sed >Makefile.dist <<'!STUFFY!FUNK!' -e 's/X//'
  1854. X#    $Header: Makefile.dist,v 1.9 89/12/29 21:14:31 daniel grabchars_1_9 $
  1855. X#
  1856. X#       Makefile for grabchars
  1857. X#
  1858. X#    Dan Smith (daniel@island.uu.net), November 1988, April 1990
  1859. X#
  1860. X#    defines...
  1861. X#
  1862. X#    BSD or SYS_V, if you port to something else, add a comment
  1863. X#    here, #ifdef the source and please send me the patches, thanks!
  1864. X#
  1865. X#    DV_ERASE is a stab at putting erase/kill processing
  1866. X#    in this, it will only work under BSD at the moment 
  1867. X#
  1868. X#    Use -DSIGRET=void for Sun OS 4.X...
  1869. X#
  1870. X#    Uncomment the one that applies...
  1871. XDEFS = -DBSD -DDV_ERASE -DSIGRET=void
  1872. X#DEFS = -DSYS_V
  1873. X
  1874. XSRCS =    globals.c grabchars.c sys.c
  1875. XOBJS =    globals.o grabchars.o sys.o
  1876. XHDRS =    grabchars.h
  1877. XMAN_PAGE = grabchars.1
  1878. XOTHERS = README Config TODO Makefile.dist demo
  1879. XALL_TEXT = $(OTHERS) $(MAN_PAGE) $(SRCS) $(HDRS)
  1880. X
  1881. X#    where to put things...
  1882. XBIN_DIR =
  1883. XMAN_DIR =
  1884. X
  1885. X#    for rcs...
  1886. XSTATE = grabchars_1_9
  1887. XVERSION = 1.9
  1888. X
  1889. X#    change to suit...
  1890. XPRINTER = -Pceylonlw
  1891. XEDITOR = /usr/ucb/vi
  1892. X
  1893. X#    if you have this, check the path.  If you don't, leave it alone...
  1894. XMKID = mkid
  1895. XSHAR = shar -v
  1896. X
  1897. XCC = cc
  1898. XCFLAGS = -O
  1899. X
  1900. X#    force this, leave csh out of it...
  1901. XSHELL=/bin/sh
  1902. X
  1903. X.c.o:
  1904. X    $(CC) -c $(CFLAGS) $(DEFS) $*.c
  1905. X
  1906. Xall: grabchars
  1907. X
  1908. Xrelease:
  1909. X    @make CFLAGS=-O all
  1910. X
  1911. Xgrabchars: $(OBJS)
  1912. X    - mv grabchars grabchars.old 2>/dev/null
  1913. X    @echo loading...
  1914. X    $(CC) $(CFLAGS) $(OBJS)  -o grabchars
  1915. X    @echo done...
  1916. X
  1917. Xinstall: release
  1918. X    - cp grabchars $(BIN_DIR)
  1919. X    - cp grabchars.1 $(MAN_DIR) && echo "preparing man page" \
  1920. X    && man grabchars
  1921. Xid: $(SRCS) $(HDRS)
  1922. X    - $(MKID) $(SRCS) $(HDRS) || echo $(MKID) not available...
  1923. X
  1924. Xe: $(SRCS) $(HDRS)
  1925. X    $(EDITOR) $(SRCS) $(HDRS) Makefile
  1926. X
  1927. Xpgrind:
  1928. X    @echo pgrinding out sources...
  1929. X    lpq $(PRINTER)
  1930. X    pgrind $(SRCS) $(HDRS) Makefile
  1931. X
  1932. Xrcs:
  1933. X    @echo checking grabchars in to RCS...
  1934. X    ci -s$(STATE) -r$(VERSION) -f -u $(ALL_TEXT)
  1935. X
  1936. Xshar:
  1937. X    @echo bundling up grabchars for transit...
  1938. X    $(SHAR) $(ALL_TEXT) > grabchars.shar
  1939. X
  1940. Xclean: id tags
  1941. X    - touch $(OBJS) grabchars
  1942. X    - /bin/rm $(OBJS) grabchars
  1943. X
  1944. Xdepend: 
  1945. X    @echo making dependencies...
  1946. X    sed -n '1,/^#    lines after this point/p' Makefile >.depends &&\
  1947. X    cc -M $(SRCS) | grep -v "/usr/include" | \
  1948. X    tee /dev/tty >> .depends && mv .depends Makefile
  1949. X
  1950. Xtags: $(SRCS)
  1951. X    ctags $(SRCS)
  1952. X
  1953. X#       lines after this point produced with cc -M, leave this line here
  1954. !STUFFY!FUNK!
  1955. echo ""
  1956. echo "End of kit 1 (of 2)"
  1957. cat /dev/null >kit1isdone
  1958. run=''
  1959. config=''
  1960. for iskit in 1 2; do
  1961.     if test -f kit${iskit}isdone; then
  1962.     run="$run $iskit"
  1963.     else
  1964.     todo="$todo $iskit"
  1965.     fi
  1966. done
  1967. case $todo in
  1968.     '')
  1969.     echo "You have run all your kits.  Please read README and then type Config."
  1970.     chmod 755 Config
  1971.     ;;
  1972.     *)  echo "You have run$run."
  1973.     echo "You still need to run$todo."
  1974.     ;;
  1975. esac
  1976. : Someone might mail this, so...
  1977. exit
  1978.  
  1979.