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

  1. From decwrl!hplabs!hpda!hpwala!cfisun!ima!mirror!necntc!ncoast!allbery Sat Dec 17 21:43:52 PST 1988
  2. Article 755 of comp.sources.misc:
  3. Path: granite!decwrl!hplabs!hpda!hpwala!cfisun!ima!mirror!necntc!ncoast!allbery
  4. From: daniel@island.UUCP (Dan Smith, Release 28.0)
  5. Newsgroups: comp.sources.misc
  6. Subject: v05i073: grabchars 1.3, get/filter keystrokes directly from user (BSD)
  7. Message-ID: <8812060537.AA03805@island.uucp >
  8. Date: 7 Dec 88 00:43:23 GMT
  9. Sender: allbery@ncoast.UUCP
  10. Reply-To: daniel@island.UUCP (Dan Smith, Release 28.0)
  11. Lines: 1368
  12. Approved: allbery@ncoast.UUCP
  13.  
  14. Posting-number: Volume 5, Issue 73
  15. Submitted-by: "Dan Smith, Release 28.0" <daniel@island.UUCP>
  16. Archive-name: grabchars1.3
  17.  
  18.     "grabchars" gets one or more keystrokes from the user, without
  19. requiring them to hit return.  It was written to make shell scripts
  20. (doesn't matter what type) more interactive.
  21.  
  22.     I know that it works fine on Suns running SUN OS 3.2-3.5,
  23. and a Vax 11/750 running Mt. Xinu 4.3 BSD.  I don't have support
  24. for SYS V or VMS or anything else like that yet; send me patches...
  25. Installation should be pretty straighforward, read the README and
  26. run Config.
  27.  
  28.     You'll find uses for this in all sorts of places.  The prime
  29. candidate is in your .login file, it's easy to use this to select different
  30. options.  I've provided a "demo" csh script which runs through many of the
  31. options.  For the most part, grabchars can replace the use of "$<" in
  32. csh scripts and "read" in sh scripts, and offer filtering, timeouts, and
  33. default answers - the exception at the moment is in trying to read control
  34. characters.
  35.  
  36.     Enjoy, and send me your comments/suggestions.  2.0 will provide
  37. SYS V support.
  38.  
  39.                 dan
  40.  
  41. DanSmith IslandGraphics 4000CivicCenterDr SanRafael MarinCo CA 94903 4154911000
  42. 415 332 FAST(h) 491 0402(Fax)|d: Nobodys' fault but mine| UnixFeastsMusicFilm
  43. daniel@island.uu.net   unicom!daniel@pacbell.com  {lll-crg,apple}!well!dansmith
  44.  
  45. ------------------------ snip -------- cut ------- chop ---------
  46. #! /bin/sh
  47. # This is a shell archive, meaning:
  48. # 1. Remove everything above the #! /bin/sh line.
  49. # 2. Save the resulting text in a file.
  50. # 3. Execute the file with /bin/sh (not csh) to create:
  51. #    README
  52. #    Config
  53. #    TODO
  54. #    Makefile.dist
  55. #    demo
  56. #    grabchars.1
  57. #    globals.c
  58. #    grabchars.c
  59. #    sys.c
  60. #    grabchars.h
  61. # This archive created: Mon Dec  5 19:52:34 1988
  62. # By:    Dan "Bucko" Smith ()
  63. export PATH; PATH=/bin:/usr/bin:$PATH
  64. echo shar: "extracting 'README'" '(3940 characters)'
  65. if test -f 'README'
  66. then
  67.        echo shar: "will not over-write existing file 'README'"
  68. else
  69. cat << \SHAR_EOF > 'README'
  70.                        Grabchars 1.3
  71.  
  72.         Copyright (c) 1988, Dan Smith
  73.  
  74. What this is:
  75.  
  76.     "grabchars" gets one or more keystrokes from the user, without
  77. requiring them to hit return.  It was written to make shell scripts
  78. (doesn't matter what type) more interactive.
  79.  
  80.     I know that it works fine on Suns running SUN OS 3.2-3.5,
  81. and a Vax 11/750 running Mt. Xinu 4.3 BSD.  I don't have support
  82. for SYS V or VMS or anything else like that yet; send me patches...
  83.  
  84.     You'll find uses for this in all sorts of places.  The prime
  85. candidate is in your .login file, it's easy to use this to select different
  86. options.  I've provided a "demo" csh script which runs through many of the
  87. options.  For the most part, grabchars can replace the use of "$<" in
  88. csh scripts and "read" in sh scripts, and offer filtering, timeouts, and
  89. default answers - the exception at the moment is in trying to read control
  90. characters.
  91.  
  92. Putting this together:
  93.  
  94.     Run Config; it will figure out where you might want to
  95. put the executable and the man page.  It will also put you into an
  96. editor with the Makefile, and then it will run a "make clean",
  97. "make depend", and a "make release".  You will need getopt (3)
  98. to compile this program.  If you're not sure if you have this, try
  99. "nm /lib/libc.a | grep getopt".  Get a Public Domain version if you
  100. don't (write me if you get really stuck, I have it).
  101.  
  102. Usage: (see the man page for more...)
  103.  
  104.     grabchars            gets one keystroke
  105.     grabchars -b            output to stdout and stderr
  106.     grabchars -c<valid characters>  only <valid chars> are returned
  107.     grabchars -d<char(s)>        default char or string to return
  108.     grabchars -e            output to stderr instead of stdout
  109.     grabchars -f            flush any previous input
  110.     grabchars -h            help screen
  111.     grabchars -n<number>        number of characters to read
  112.     grabchars -p<prompt>        prompt to help user
  113.     grabchars -q<prompt>        prompt to help user (through stderr)
  114.     grabchars -r            RETURN exits (use with -n)
  115.     grabchars -s            silent, just return status
  116.     grabchars -t<seconds>        timeout after <seconds>
  117.     grabchars -E            erase/kill character processing
  118.  
  119.     examples: (values to arguments can be in the same word or the next one)
  120.  
  121.     grabchars -caeiou     or
  122.     grabchars -c aeiou        get one of the vowels
  123.     grabchars -c i            get the letter 'i'
  124.     grabchars '-penter a letter '    print the prompt "enter a letter "
  125.     grabchars '-qenter a letter '    print the prompt ('q' for question)
  126.                     "enter a letter " through stderr...
  127.     grabchars -n4            get four characters
  128.     grabchars -t2            timeout after two seconds
  129.  
  130.     print a prompt and grab three characters...
  131.     grabchars -p 'enter three characters >> ' -n 3
  132.  
  133.     get two numbers with a ten second timeout...
  134.     grabchars -c 0123456789 -n2 -t10
  135.  
  136.     note that arguments like "-n4" or "-n 4" are handled the same way
  137.  
  138.     grabchars -h            will give a usage screen...
  139.  
  140. Legal paragraph:
  141.  
  142.     Grabchars may be freely copied, changed, and used, in whole or
  143. in part.  Don't try to make any money off of it.  Don't remove my headers.
  144. Don't say you wrote it.  This kit should be kept freely available, disk
  145. space permitting.  Not responsible for mishaps arising out of the use
  146. of this program, on the other hand, I haven't run into any problems with
  147. this. Lastly, Do not use any part of grabchars in any commercial product.
  148. Let's change the subject :-)
  149.  
  150. Patches and things like that:
  151.  
  152.     "Help! Save The World!" (LW)...if you make any modifications
  153. to grabchars, send me a diff suitable for use with the patch program.
  154. I don't want ten different versions of this running around.  I need to
  155. know what changes need to be made to get this to run on Sys V and other
  156. Unix (or other) variants.  I don't use them, so at this point I don't
  157. know!
  158.  
  159. Where to reach me:
  160.  
  161.     Dan Smith
  162.     Island Graphics
  163.     4000 Civic Center Drive
  164.     San Rafael, Ca 94903
  165.     +1 (415) 491 1000 (w), 491 0402 (fax), 332 3278 (h)
  166.  
  167.     daniel@island.uu.net or    
  168.     {pixar,grenada,ucbvax!ucbcad,unicom,well,sun,uunet}!island!daniel
  169.  
  170.     unicom!daniel@pacbell.com
  171.  
  172.     {apple,lll-crg}!well!dansmith
  173.  
  174. SHAR_EOF
  175. fi
  176. echo shar: "extracting 'Config'" '(2396 characters)'
  177. if test -f 'Config'
  178. then
  179.        echo shar: "will not over-write existing file 'Config'"
  180. else
  181. cat << \SHAR_EOF > 'Config'
  182. #!/bin/csh -f
  183. #
  184. #    $Header: Config,v 1.3 88/12/05 19:45:39 daniel grabchars_1_3 $
  185. #
  186. #    Config - set up Makefile for grabchars
  187. #
  188. #    Dan Smith (daniel@island.uu.net), November 1988
  189. #
  190. #    Config file for grabchars... must be csh, no attempt
  191. #    made to be eunice (i.e. echo " ") compatible...
  192. #
  193. clear
  194. cat << GUMBY
  195.  
  196.     Config for grabchars
  197.  
  198.     This csh script will figure out a few things about your
  199. system, and then will run a "make clean", a "make depend", and
  200. a "make release".  You should then try out grabchars, and, once assured
  201. that it's behaving itself, you should run a "make install"
  202.  
  203. GUMBY
  204. echo -n 'press return to start...'
  205. set ignore=$<
  206.  
  207. #    figure out where to put this when the user types
  208. #    "make install"...we'll try in three likely places...
  209.  
  210. foreach try_bin (/usr/local{/bin,} /usr/public/bin)
  211.     echo -n looking at $try_bin...
  212.     if (-w $try_bin) then
  213.         set bin_dir=$try_bin && echo yep... && break
  214.     endif
  215.     echo ""
  216. end
  217.  
  218. #    figure out where to put the man pages when the user
  219. #    "make install"...a few places come to mind...
  220.  
  221. foreach try_man (/usr/{,local/,public/}man/man1)
  222.     echo -n looking at $try_man...
  223.     if (-w $try_man) then
  224.         set man_dir=$try_man && echo yep... && break
  225.     endif
  226.     echo ""
  227. end
  228.  
  229. if ($?bin_dir) then
  230.     echo BIN_DIR looks like it will be $bin_dir
  231. else
  232.     echo BIN_DIR is unknown...check the Makefile when it comes up...
  233.     set bin_dir=""
  234. endif
  235.  
  236. if ($?man_dir) then
  237.     echo MAN_DIR looks like it will be $man_dir
  238. else
  239.     echo MAN_DIR is unknown...check the Makefile when it comes up...
  240.     set man_dir=""
  241. endif
  242.  
  243. set myedit=vi
  244. if ($?EDITOR) then
  245.     set myedit=$EDITOR
  246. endif
  247.  
  248. oh_really:
  249.     if (! -e $myedit) then
  250.         echo -n "I don't see a $myedit...where is your editor? "
  251.         set myedit=$<
  252.         echo ok...
  253.     endif
  254.  
  255. echo editor of choice seems to be \"$myedit\"...
  256.  
  257. if  (-e Makefile) mv Makefile{,.old} >& /dev/null
  258.  
  259. echo making makefile...
  260. sed    -e "s+^BIN_DIR.*+BIN_DIR = $bin_dir+" \
  261.     -e "s+^MAN_DIR.*+MAN_DIR = $man_dir+" \
  262.     -e "s+^EDITOR.*+EDITOR = $myedit+" \
  263.     < Makefile.dist > Makefile
  264.  
  265. echo going to $myedit with Makefile for you to check out..
  266. echo -n press return...
  267. set ignore=$<
  268. $myedit Makefile || \
  269.     echo where is your editor\?\!\!  && goto oh_really
  270.  
  271. echo " "
  272. echo clean up any residue from before, doing a \"make clean\"
  273. sleep 2
  274. make clean
  275.  
  276. echo " "
  277. echo going to run a \"make depend\"...
  278. sleep 2
  279. make depend
  280.  
  281. echo " "
  282. echo ok, let\'s try to make this with \"make release\"
  283. sleep 2
  284. make release
  285. SHAR_EOF
  286. chmod +x 'Config'
  287. fi
  288. echo shar: "extracting 'TODO'" '(403 characters)'
  289. if test -f 'TODO'
  290. then
  291.        echo shar: "will not over-write existing file 'TODO'"
  292. else
  293. cat << \SHAR_EOF > 'TODO'
  294. TODO file...
  295.  
  296.     add SYS V code...
  297.  
  298.     add support for arrow keys handle control characters better...
  299.  
  300.     I have the code for this in my "phonemail" program (to be
  301.     posted soon).  I'm not sure what would constitute reasonable
  302.     return values (have negative values? values greater than 128?)
  303.     Is there a canonical return value list for keyboard events?
  304.  
  305.     stronger erase/kill processing...
  306.  
  307.     Thatzit for now...
  308.  
  309. SHAR_EOF
  310. fi
  311. echo shar: "extracting 'Makefile.dist'" '(2088 characters)'
  312. if test -f 'Makefile.dist'
  313. then
  314.        echo shar: "will not over-write existing file 'Makefile.dist'"
  315. else
  316. cat << \SHAR_EOF > 'Makefile.dist'
  317. #    $Header: Makefile.dist,v 1.3 88/12/05 19:45:47 daniel grabchars_1_3 $
  318. #
  319. #       Makefile for grabchars
  320. #
  321. #    Dan Smith (daniel@island.uu.net), November 1988
  322. #
  323. SRCS =    globals.c grabchars.c sys.c
  324. OBJS =    globals.o grabchars.o sys.o
  325. HDRS =    grabchars.h
  326. MAN_PAGE = grabchars.1
  327. OTHERS = README Config TODO Makefile.dist demo
  328. ALL_TEXT = $(OTHERS) $(MAN_PAGE) $(SRCS) $(HDRS)
  329.  
  330. #    where to put things...
  331. BIN_DIR =
  332. MAN_DIR =
  333.  
  334. #    for rcs...
  335. STATE = grabchars_1_3
  336. VERSION = 1.3
  337.  
  338. #    change to suit...
  339. PRINTER = -Pislandlw
  340. EDITOR = /usr/ucb/vi
  341.  
  342. #    if you have this, check the path.  If you don't, leave it alone...
  343. MKID = mkid
  344. SHAR = shar -v
  345.  
  346. CC = cc
  347. CFLAGS = -g
  348.  
  349. #    defines...
  350. #
  351. #    BSD is mandatory for now...if you patch for SYS V please
  352. #    #ifdef for "SYS_V" in init_term (), handle_erase (),
  353. #    and lets_go ()...
  354. #
  355. #    DV_ERASE is my friends stab at putting erase/kill processing
  356. #    in this.  I haven't thoroughly tested it (-E option)
  357. DEFS = -DBSD -DDV_ERASE
  358.  
  359. #    force this, leave csh out of it...
  360. SHELL=/bin/sh
  361.  
  362. .c.o:
  363.     $(CC) -c $(CFLAGS) $(DEFS) $*.c
  364.  
  365. all: grabchars
  366.  
  367. release:
  368.     @make CFLAGS=-O all
  369.  
  370. grabchars: $(OBJS)
  371.     - mv grabchars grabchars.old 2>/dev/null
  372.     @echo loading...
  373.     $(CC) $(CFLAGS) $(OBJS)  -o grabchars
  374.     @echo done...
  375.  
  376. install: release
  377.     - cp grabchars $(BIN_DIR)
  378.     - cp grabchars.1 $(MAN_DIR) && echo "preparing man page" \
  379.     && man grabchars
  380.  
  381. id: $(SRCS) $(HDRS)
  382.     - $(MKID) $(SRCS) $(HDRS) || echo $(MKID) not available...
  383.  
  384. e: $(SRCS) $(HDRS)
  385.     $(EDITOR) $(SRCS) $(HDRS) Makefile
  386.  
  387. pgrind:
  388.     @echo pgrinding out sources...
  389.     lpq $(PRINTER)
  390.     pgrind $(SRCS) $(HDRS) Makefile
  391.  
  392. rcs:
  393.     @echo checking grabchars in to RCS...
  394.     ci -s$(STATE) -r$(VERSION) -f -u $(ALL_TEXT)
  395.  
  396. shar:
  397.     @echo bundling up grabchars for transit...
  398.     $(SHAR) $(ALL_TEXT) > grabchars.shar
  399.  
  400. clean: id tags
  401.     - touch $(OBJS) grabchars
  402.     - /bin/rm $(OBJS) grabchars
  403.  
  404. depend: 
  405.     @echo making dependencies...
  406.     sed -n '1,/^#    lines after this point/p' Makefile >.depends &&\
  407.     cc -M $(SRCS) | tee /dev/tty >> .depends && mv .depends Makefile
  408.  
  409. tags: $(SRCS)
  410.     ctags $(SRCS)
  411.  
  412. #       lines after this point produced with cc -M, leave this line here
  413. SHAR_EOF
  414. fi
  415. echo shar: "extracting 'demo'" '(1881 characters)'
  416. if test -f 'demo'
  417. then
  418.        echo shar: "will not over-write existing file 'demo'"
  419. else
  420. cat << \SHAR_EOF > 'demo'
  421. #!/bin/csh -f
  422. clear
  423. cat << GUMBY
  424.  
  425.     Grabchars demo...
  426.  
  427.     get one character with "grabchars"
  428. GUMBY
  429. grabchars
  430. echo " status returned was $status"
  431.  
  432. cat << POKEY
  433.  
  434.     grab a vowel with "grabchars -caeiou"
  435.  
  436.     Type something that isn't a vowel at first...
  437.  
  438. POKEY
  439. grabchars -caeiou
  440. echo " status returned was $status"
  441.  
  442. cat << WILMA
  443.  
  444.     prompt the user  with "grabchars -p 'give me any character >> '"
  445. WILMA
  446. grabchars -p 'give me any character >> '
  447. echo " status returned was $status"
  448.  
  449. cat << FRED
  450.  
  451.     prompt through stderr  with "grabchars -q 'give me any character >> '",
  452. so that we can set the variable "user_char"...
  453. FRED
  454. set user_char=`grabchars -q 'give me any character >> '`
  455. echo " status returned was $status"
  456. echo '$user_char = '$user_char
  457.  
  458. cat << BETTY
  459.  
  460.     enter three characters...  "grabchars -n3"
  461.  
  462. BETTY
  463. grabchars -n3
  464. echo " status returned was $status"
  465.  
  466. cat <<  BARNEY
  467.  
  468.     enter 10 characters within 3 seconds... "grabchars -n10 -t3"
  469.  
  470.  
  471. BARNEY
  472. grabchars -n10 -t3
  473. set really_typed=$status
  474. if ($really_typed == 10) then
  475.     echo 'hey\! you got 10\!?'
  476. else
  477.     echo "    $really_typed returned...means that grabchars timed out..."
  478. endif
  479.  
  480. def_test:
  481. cat << RADRED
  482.  
  483.     let the user pick a default...
  484.     using "grabchars -d yes -p 'just hit return '...
  485.  
  486. RADRED
  487. #    the '-f' here is used to flush any previous input...
  488. grabchars -f -d yes -p 'just hit return '
  489. if ($status != 3) then
  490.     echo whoops\!  Let\'s try that again...
  491.     goto def_test
  492. endif
  493.  
  494. cat << MUSKRAT
  495.  
  496.     same idea, but let this timeout in four seconds...
  497.     using "grabchars -f -d always -t 4"
  498.  
  499.     (don't type anything...)
  500.  
  501. MUSKRAT
  502. grabchars -f -d always -t 4
  503.  
  504. cat << PEBBLES
  505.  
  506.  
  507.     The last one...  get two numbers with a ten second timeout...
  508.     trying "grabchars -c 0123456789 -n2 -t10 -p 'give me 2 numbers >> '
  509.  
  510. PEBBLES
  511. grabchars -c 0123456789 -n2 -t10 -p 'give me 2 numbers >> '
  512. echo " status returned was $status"
  513. echo ""
  514. echo test/demo done...enjoy\!
  515. SHAR_EOF
  516. chmod +x 'demo'
  517. fi
  518. echo shar: "extracting 'grabchars.1'" '(4786 characters)'
  519. if test -f 'grabchars.1'
  520. then
  521.        echo shar: "will not over-write existing file 'grabchars.1'"
  522. else
  523. cat << \SHAR_EOF > 'grabchars.1'
  524. ''' Man page for grabchars, uses Larry Wall's "patch" man page as
  525. ''' a template.
  526. .de Sh
  527. .br
  528. .ne 5
  529. .PP
  530. \fB\\$1\fR
  531. .PP
  532. ..
  533. .de Sp
  534. .if t .sp .5v
  535. .if n .sp
  536. ..
  537. '''
  538. '''     Set up \*(-- to give an unbreakable dash;
  539. '''     string Tr holds user defined translation string.
  540. '''     Bell System Logo is used as a dummy character.
  541. '''
  542. .ie n \{\
  543. .tr \(bs-\*(Tr
  544. .ds -- \(bs-
  545. .if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
  546. .if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
  547. .ds L" ""
  548. .ds R" ""
  549. .ds L' '
  550. .ds R' '
  551. 'br\}
  552. .el\{\
  553. .ds -- \(em\|
  554. .tr \*(Tr
  555. .ds L" ``
  556. .ds R" ''
  557. .ds L' `
  558. .ds R' '
  559. 'br\}
  560. .TH GRABCHARS 1 LOCAL
  561. .SH NAME
  562. grabchars - get keystrokes directly from user
  563. .SH SYNOPSIS
  564. .B grabchars
  565. [options]
  566. .SH DESCRIPTION
  567. \fBGrabchars\fP gets characters from the user as they are
  568. typed in, without having to wait for the return key to
  569. be pressed.  Among other things, this allows shell scripts
  570. to be written with highly interactive menus.
  571. .PP
  572. By default,
  573. .I grabchars
  574. will obtain one character from stdin, echo that character to stdout,
  575. and return with a status of one; meaning one character read.
  576. .TP 5
  577. .B \-b
  578. Both
  579. .I stdout
  580. and
  581. .I stderr
  582. are used for output.  This is useful for setting a variable in
  583. a shell script and echoing a keystroke to the screen at the
  584. same time.
  585. .TP 5
  586. .B \-c<valid characters>
  587. Only characters in
  588. .I <valid characters>
  589. are accepted.  Regular expressions such as [a-z]
  590. may be used to specify ranges.  All other characters are ignored.
  591. .TP 5
  592. .B \-d<char(s)>
  593. Default char or string to output if the user hits
  594. .B RETURN
  595. or lets
  596. .B grabchars
  597. timeout.  The status that is returned is the same as if the user had
  598. typed in the character or string, so this option may be used with
  599. the
  600. .B \-s
  601. (silent) flag.
  602. .TP 5
  603. .B \-e
  604. Output goes to
  605. .I stderr
  606. rather than
  607. .I stdout.
  608. .TP 5
  609. .B \-f
  610. Flush any previous input.  By default,
  611. .I grabchars
  612. will see any characters present in
  613. .I stdin,
  614. which allows for some typeahead in shell scripts.
  615. .TP 5
  616. .B \-h
  617. Help/usage screen.
  618. .TP 5
  619. .B \-p<prompt>
  620. Sets up a prompt for the user.  See
  621. .I EXAMPLES.
  622. .TP 5
  623. .B \-q<prompt>
  624. Sets up a prompt for the user, except it is printed to
  625. .I stderr
  626. rather than
  627. .I stdout.
  628. .TP 5
  629. .B \-r
  630. The
  631. .B RETURN
  632. key exits.  Use this with the -n option to allow for variable
  633. numbers of characters to be typed in.
  634. .TP 5
  635. .B \-n<number>
  636. Number of characters to read.  By default,
  637. .I grabchars
  638. looks for one character.
  639. .TP 5
  640. .B \-s
  641. Silent.  Do not output anything. Just return a status.
  642. .TP 5
  643. .B \-t<seconds>
  644. Time to allow the user to respond.  By default, the user
  645. can take as long as he or she wants to.  The timeout option allows
  646. you to write shell scripts where you can offer some assistance
  647. if it's obvious that the user might be stuck.
  648. .TP 5
  649. .B \-E
  650. Erase/kill processing is done.  You have use of the keys (usually
  651. DELETE and ^U or ^X) that you would normally have from the
  652. shell for deleting characters.  This is useful with the
  653. .B \-n
  654. option, where many characters are being typed in.  This code hasn't
  655. been thoroughly tested.
  656. .SH EXAMPLES
  657. .TP 5
  658. .B grabchars
  659. gets one keystroke
  660. .TP 5
  661. .B grabchars \-caeiou
  662. get one of the vowels
  663. .TP 5
  664. .B grabchars -c i
  665. get the letter 'i'
  666. .TP 5
  667. .B grabchars '\-penter a letter '
  668. print the prompt "enter a letter "
  669. .TP 5
  670. .B grabchars '\-qenter a letter '
  671. print the prompt ('q' for question) "enter a letter " through
  672. .I stderr.
  673. .TP 5
  674. .B grabchars \-n4
  675. get four characters.
  676. .TP 5
  677. .B grabchars \-d a
  678. If the first character typed is a
  679. .B RETURN,
  680. pretend it was an 'a'.
  681. .TP 5
  682. .B grabchars \-d gumby
  683. If the first character typed is a
  684. .B RETURN,
  685. pretend that the user typed in "gumby".
  686. .TP 5
  687. .B grabchars \-r
  688. The
  689. .B RETURN
  690. key will exit
  691. .I grabchars.  You would use this with the
  692. .B -n
  693. option, so that variable numbers of characters may be entered.
  694. .TP
  695. .B grabchars \-n 4 \-r \-t 10
  696. Accept up to four characters, or exit when
  697. .B RETURN
  698. is hit, or exit when 10 seconds have elapsed.
  699. .TP 5
  700. .B grabchars \-t2
  701. timeout after two seconds.
  702. .TP 5
  703. .B grabchars \-d gumby \-t2
  704. If the first character typed is a
  705. .B RETURN,
  706. or if two seconds have gone by,
  707. pretend that the user typed in "gumby".
  708. .TP 5
  709. .B grabchars \-n3 \-p 'initials: '
  710. print a prompt and grab three characters.
  711. .TP 5
  712. .B grabchars \-c 0123456789 \-n2 \-t10
  713. get two numbers with a ten second timeout.
  714. .PP
  715. note that arguments like "-n4" or "-n 4" are handled the same way
  716. .SH SEE ALSO
  717. csh(1) and sh(1)
  718. for syntax of
  719. .I csh
  720. and
  721. .I sh
  722. scripts, respectively.
  723. See "The Unix Csh Field Guide", by Gail and Paul Anderson (Prentice Hall),
  724. for an excellent tour of csh and good examples of writing csh scripts.
  725. .SH DIAGNOSTICS
  726. .I
  727. Grabchars
  728. returns
  729. .B \-2
  730. if it times out, or
  731. .B \-1
  732. if it gives a usage statement.  Otherwise, it
  733. returns the number of characters successfully read.
  734. .SH AUTHOR
  735. .nf
  736. Dan Smith (daniel@island.uu.net or {ucbvax!ucbcad,well,sun}!island!daniel)
  737. SHAR_EOF
  738. fi
  739. echo shar: "extracting 'globals.c'" '(1778 characters)'
  740. if test -f 'globals.c'
  741. then
  742.        echo shar: "will not over-write existing file 'globals.c'"
  743. else
  744. cat << \SHAR_EOF > 'globals.c'
  745. /*
  746. **    $Header: globals.c,v 1.3 88/12/05 19:46:01 daniel grabchars_1_3 $
  747. **
  748. **    globals.c - declare global variables for grabchars
  749. **
  750. **    Dan Smith (daniel@island.uu.net), November 29, 1988
  751. */
  752. #include <stdio.h>
  753. #include "grabchars.h"    /* where we typedef FLAGS */
  754.  
  755. FILE *outfile, *otherout;
  756. FLAG *flags;
  757.  
  758. int exit_stat;
  759. char valid_chars[128], default_string[128];
  760.  
  761. #ifdef DV_ERASE
  762. char *erase_buf;    /* DV: Malloc'ed later */
  763. #endif
  764.  
  765. /*
  766. **    this gets in the way sitting in grabchars.c, so I moved it here.
  767. **    If you add anything, keep in mind that you're trying to squeeze
  768. **    everything onto a 24 line window/terminal... The "-h" doc
  769. **    is just a convenience, any option that grabchars doesn't already
  770. **    use will give the help screen...
  771. */
  772. char *usage_statement[] = {
  773. "usage: grabchars        gets one keystroke",
  774. "    -b            output to stdout and stderr",
  775. "    -c<valid characters>    only <valid chars> are returned",
  776. "    -d<char(s)>        default char or string to return",
  777. "    -e            output to stderr instead of stdout",
  778. "    -f            flush any previous input before reading",
  779. "    -h            help screen",
  780. "    -n<number>        number of characters to read",
  781. "    -p<prompt>        prompt to help user",
  782. "    -q<prompt>        prompt to help user (through stderr)",
  783. "    -r            RETURN key exits (use with -n)",
  784. "    -s            silent, just return status",
  785. "    -t<seconds>        timeout after <seconds>",
  786. "    -E            honor erase/kill characters", /* DV */
  787. "examples: (values to arguments can be in the same word or the next one)",
  788. "grabchars -c aeiou        get one of the vowels",
  789. "grabchars -c i            get the letter 'i'",
  790. "grabchars '-penter a letter '    print the prompt \"enter a letter \"",
  791. "grabchars -n4            get four characters",
  792. "grabchars -t2            timeout after two seconds",
  793. " ",
  794. "print a prompt and grab three characters...",
  795. "grabchars -p 'enter three characters >> ' -n 3",
  796. 0
  797. };
  798. SHAR_EOF
  799. fi
  800. echo shar: "extracting 'grabchars.c'" '(8500 characters)'
  801. if test -f 'grabchars.c'
  802. then
  803.        echo shar: "will not over-write existing file 'grabchars.c'"
  804. else
  805. cat << \SHAR_EOF > 'grabchars.c'
  806. /*
  807. **    $Header: grabchars.c,v 1.3 88/12/05 19:46:06 daniel grabchars_1_3 $
  808. **
  809. **    grabchars.c    - get characters directly from the user
  810. **
  811. **    Dan Smith (daniel@island.uu.net), October 23, 1988
  812. **
  813. **    This program grabs characters from the user as they are
  814. **    typed in, without having to wait for the return key to
  815. **    be pressed.  Among other things, this allows shell scripts
  816. **    to be written with highly interactive menus...
  817. **
  818. **    [to jump right to the code, search for "start of grabchars"]
  819. **
  820. **    Usage rundown:
  821. **
  822. **    grabchars            gets one keystroke
  823. **    grabchars -b            output to stdout and stderr
  824. **    grabchars -c<valid characters>  only <valid chars> are returned
  825. **    grabchars -d<char(s)>        default char or string to return
  826. **    grabchars -e            output to stderr instead of stdout
  827. **    grabchars -f            flush any previous input
  828. **    grabchars -h            help screen
  829. **    grabchars -n<number>        number of characters to read
  830. **    grabchars -p<prompt>        prompt to help user
  831. **    grabchars -q<prompt>        prompt to help user (through stderr)
  832. **    grabchars -r            RETURN key exits (use with -n)
  833. **    grabchars -s            silent, just return status
  834. **    grabchars -t<seconds>        timeout after <seconds>
  835. **    grabchars -E            erase/kill character processing
  836. **
  837. **    examples: (values to arguments can be in the same word or the next one)
  838. **
  839. **    grabchars -caeiou     or
  840. **    grabchars -c aeiou        get one of the vowels
  841. **    grabchars -c i            get the letter 'i'
  842. **    grabchars '-penter a letter '    print the prompt "enter a letter "
  843. **    grabchars '-qenter a letter '    print the prompt ('q' for question)
  844. **                    "enter a letter " through stderr...
  845. **    grabchars -n4            get four characters
  846. **    grabchars -t2            timeout after two seconds
  847. **
  848. **    print a prompt and grab three characters...
  849. **    grabchars -p 'enter three characters >> ' -n 3
  850. **
  851. **    get two numbers with a ten second timeout...
  852. **    grabchars -c 0123456789 -n2 -t10
  853. **
  854. **    note that arguments like "-n4" or "-n 4" are handled the same way
  855. **
  856. **    History:
  857. **    
  858. **    Oct 1988: versions 1.0 - 1.1
  859. **
  860. **    November 6, 1988 (1.15)
  861. **    added -f flag to flush input, default is to use    TIOCSETN instead
  862. **    of TIOCSETP
  863. **
  864. **    November 22, 1988 (1.16)
  865. **    added -d flag for a default character or string to use if the
  866. **    user hits return first thing or times out.  handle_default ()
  867. **    was added at this time
  868. **
  869. **    November 23, 1988 (1.19)
  870. **    added -r flag to exit when RETURN is hit.  This was suggested by
  871. **    David Vezie.
  872. **
  873. **    November 29, 1988 (1.2)
  874. **    Disaster strikes...I was updating Makefile.dist, and copied SRCS
  875. **    to OBJS, and forgot to change grabchars.c to grabchars.o, and
  876. **    then (after Config) did a "make clean"!  I realized that I did not
  877. **    have a backup, but fortunately had David Vezie's hack of grabchars.c
  878. **    from a few days ago (he had added erase/line kill character processing)
  879. **    ...moral: use RCS, check your Makefiles!  Used this as an opportunity
  880. **    to split things up into grabchars.h, globals.c,    and sys.c
  881. **    Got -c to handle ranges (via re_comp() and re_exec())
  882. */
  883.  
  884. /*    start of grabchars... */
  885. #include <stdio.h>
  886. #include <signal.h>
  887. #include "grabchars.h"
  888.  
  889. /*    see globals.c */
  890. extern FILE *outfile, *otherout;
  891. extern FLAG *flags;
  892. extern int exit_stat;
  893. extern char *usage_statement[];
  894.  
  895. /*
  896. **    David Vezie (island!r2d2!dv) took a great shot at putting in
  897. **    erase/kill processing.  I need to test this some more, and I'll
  898. **    most likely change it a bit.  I put DV_ERASE in the Makefile
  899. **    as a default; take it out if it misbehaves :-)
  900. */
  901. #ifdef DV_ERASE
  902. extern char *erase_buf;    /* DV: Malloc'ed later */
  903. #endif
  904.  
  905. main (argc, argv)
  906. int argc;
  907. register char **argv;
  908. {
  909.     /* two signal/wrapup handling routines in sys.c */
  910.     int lets_go (), overtime ();
  911.  
  912.     /* for -d option */
  913.     void handle_default ();
  914.  
  915.     /* for getopt () */
  916.     extern int optind, opterr;
  917.     extern char *optarg;
  918.     char comarg;
  919.  
  920.     int how_many = 1;    /* how many chars to read */
  921.     int num_read;        /* how many we have read... */
  922.     int timeout;        /* and an optional time to do it in... */
  923.     int i;            /* for usage_statement if we need it.. */
  924.  
  925.     /*
  926.     **    re_comp (), re_exec () let us do things
  927.     **    like "grabchars -c '[a-d]'" or "grabchars -c '[^a-z]'"...
  928.     */
  929.     char *re_comp (), *re_error;
  930.     extern char valid_chars[128], default_string[128];
  931.     char ch, check_str[2];
  932.  
  933.     alarm (0);
  934.     opterr = 0;
  935.     exit_stat = -1;    /* if we're interrupted, exit with this status */
  936.  
  937.     outfile = stdout;
  938.     otherout = stderr;
  939.     if ((flags = (FLAG *) malloc (sizeof (FLAG))) == (FLAG *) NULL) {
  940.         fprintf (stderr, "can't find enough memory...bye!\n");
  941.         exit (exit_stat);    /* we don't need lets_go () for this */
  942.     }
  943.  
  944.     init_flags ();
  945.     init_signal ();
  946.  
  947.     while ((comarg = getopt (argc, argv,  "befrsEc:d:n:p:q:t:")) != EOF) {
  948.         switch (comarg) {
  949.             case 'b':
  950.                 flags->both = 1;
  951.                 break;
  952.             case 'c':
  953.                 flags->check = 1;
  954.                 strcpy (valid_chars, optarg);
  955.                 if (strlen (optarg) == 0) {
  956.                     fprintf (stderr, "-c option: must have at least one valid character\n");
  957.                     exit (-1);
  958.                 }
  959.                 /*
  960.                 ** most of the time, grabchars can be
  961.                 ** called safely with things like
  962.                 ** "a-z", because we can check to
  963.                 ** see if we need to add brackets...
  964.                 */
  965.                 if (valid_chars[0] != '[' && 
  966.                 valid_chars[strlen (valid_chars) - 1] != ']')
  967.                     sprintf (valid_chars, "%c%s%c",
  968.                         '[', optarg, ']');
  969.  
  970.                 if ((re_error = re_comp (valid_chars))
  971.                                 != NULL) {
  972.                     fprintf (stderr,
  973.                         "-c option: %s\n", re_error);
  974.                     exit (-1);
  975.                 }
  976.                 break;
  977.             case 'd':
  978.                 flags->dflt = 1;
  979.                 strcpy (default_string, optarg);
  980.                 if (strlen (optarg) == 0) {
  981.                 fprintf (stderr, "-d option: must have at least one character for default\n");
  982.                     exit (-1);
  983.                 }
  984.                 break;
  985.             case 'e':
  986.                 outfile = stderr;
  987.                 otherout = stdout;
  988.                 break;
  989.             case 'f':
  990.                 flags->flush = 1;
  991.                 break;
  992.             case 'n':
  993.                 how_many = atoi (optarg);
  994.                 if (how_many <= 0) {
  995.                     fprintf (stderr, "-n option: number of characters to read must be greater than zero\n");
  996.                     exit (-1);
  997.                 }
  998.                 break;
  999.             case 'p':
  1000.                 fprintf (stdout, "%s", optarg);
  1001.                 break;
  1002.             case 'q':
  1003.                 fprintf (stderr, "%s", optarg);
  1004.                 break;
  1005.             case 'r':
  1006.                 flags->ret_key = 1;
  1007.                 break;
  1008.             case 's':
  1009.                 flags->silent = 1;
  1010.                 break;
  1011.             case 't':
  1012.                 timeout = atoi (optarg);
  1013.                 if (timeout <= 0) {
  1014.                     fprintf (stderr, "-t option: number of seconds to timeout must be greater than zero\n");
  1015.                     exit (-1);
  1016.                 }
  1017.  
  1018.                 /*
  1019.                 ** we must have some valid time >0 seconds to
  1020.                 ** get here, so we'll set an alarm...
  1021.                 */
  1022.                 signal (SIGALRM, overtime);
  1023.                 alarm ((unsigned int) timeout);
  1024.                 break;
  1025.             case 'E':    /* DV: honor erase/kill flag */
  1026. #ifdef DV_ERASE
  1027.                 flags->erase = 1;
  1028. #else
  1029.                 fprintf (stderr, "-E is disabled\n");
  1030.                 exit (-1);
  1031. #endif
  1032.                 break;
  1033.  
  1034.                 /*
  1035.                 ** I bet I could leave out "default", but
  1036.                 ** I also bet that all getopt () routines
  1037.                 ** are not created equal, so in it stays!
  1038.                 */
  1039.             case '?':
  1040.             default:
  1041.                 i = 0;
  1042.                 while (usage_statement[i])
  1043.                     puts (usage_statement[i++]);
  1044.                 exit (-1);
  1045.         }
  1046.     }
  1047.  
  1048.     /* we're still here, really running...now change the tty... */
  1049.     init_term ();
  1050.  
  1051. #ifdef DV_ERASE
  1052.     /* DV: malloc (okay, well calloc) space for the erase buffer */
  1053.     if (flags->erase) {
  1054.         /* We can't do it up in the switch, because we don't know
  1055.         ** how many is how_many
  1056.         */
  1057.         erase_buf = (char *)calloc (1, how_many);
  1058.         if (erase_buf == NULL) {
  1059.             fprintf (stderr,
  1060.             "Error:  Couldn't malloc space for erase buffer\n");
  1061.             exit_stat = -1;
  1062.             lets_go();
  1063.         }
  1064.     }
  1065. #endif
  1066.  
  1067.     for (num_read = 0; num_read < how_many; num_read++) {
  1068.         ch = getchar ();
  1069.  
  1070.         /* use default_string, this does *not* return */
  1071.         if (ch == '\n' && flags->dflt && num_read == 0)
  1072.             handle_default ();
  1073.  
  1074.         /*
  1075.         ** set by -r, a RETURN key gets us out (use with -n)
  1076.         ** suggested by David Vezie
  1077.         */
  1078.         if (ch == '\n' && flags->ret_key)
  1079.             break;
  1080.  
  1081.         /*    filter chars... */
  1082.         if (flags->check) {
  1083.             sprintf (check_str, "%c", ch);
  1084.             if (re_exec (check_str) != 1) {
  1085.                 num_read--;
  1086.                 continue;
  1087.             }
  1088.         }
  1089.  
  1090.         /*
  1091.         ** if we're just looking for a return status
  1092.         ** then have flags->silent set (-s)
  1093.         **
  1094.         ** DV: Also, we don't want to output yet,
  1095.         ** if we're processing erase/kill charfacters.
  1096.         */
  1097. #ifdef DV_ERASE
  1098.         if (! flags->silent && ! flags->erase) {
  1099. #else
  1100.         if (! flags->silent) { 
  1101. #endif
  1102.             putc (ch, outfile);
  1103.             if (flags->both)
  1104.                 putc (ch, otherout);
  1105.         }
  1106.  
  1107. #ifdef DV_ERASE
  1108.         if (flags->erase)
  1109.             handle_erase (ch, &num_read);
  1110. #endif
  1111.     }
  1112.  
  1113. #ifdef DV_ERASE
  1114.     if (flags->erase) {
  1115.         fprintf (outfile, "%s", erase_buf);
  1116.         if (flags->both)
  1117.             fprintf (otherout, "%s", erase_buf);
  1118.     }
  1119. #endif
  1120.  
  1121.     exit_stat = num_read;
  1122.     lets_go ();
  1123. }
  1124. SHAR_EOF
  1125. fi
  1126. echo shar: "extracting 'sys.c'" '(4386 characters)'
  1127. if test -f 'sys.c'
  1128. then
  1129.        echo shar: "will not over-write existing file 'sys.c'"
  1130. else
  1131. cat << \SHAR_EOF > 'sys.c'
  1132. /*
  1133. **    $Header: sys.c,v 1.3 88/12/05 19:46:14 daniel grabchars_1_3 $
  1134. **
  1135. **    sys.c - terminal routines for grabchars
  1136. **
  1137. **    Dan Smith (daniel@island.uu.net), November 29, 1988
  1138. **
  1139. **    History:
  1140. **
  1141. **    December 2, 1988
  1142. **    made #ifdefs for DV_ERASE and BSD, wrote notes in handle_erase ()
  1143. **    for changes and improvements
  1144. */
  1145.  
  1146. #include <stdio.h>
  1147. #include <sgtty.h>
  1148. #include <signal.h>
  1149. #include "grabchars.h"
  1150.  
  1151. struct sgttyb orig, new;
  1152.  
  1153. /* all declared in globals.c */
  1154. extern FILE *outfile, *otherout;
  1155. extern FLAG *flags;
  1156. extern int exit_stat;
  1157. extern char default_string[128];
  1158.  
  1159. #ifdef DV_ERASE
  1160. extern char *erase_buf;
  1161. #endif
  1162.  
  1163. /* initialize global flags */
  1164. init_flags ()
  1165. {
  1166.     flags->both = 0;
  1167.     flags->check = 0;
  1168.     flags->dflt = 0;
  1169.     flags->flush = 0;
  1170.     flags->ret_key = 0;
  1171.     flags->silent = 0;
  1172.     flags->erase = 0;
  1173. }
  1174.  
  1175. /*
  1176. **    initialize tty
  1177. **
  1178. **    this really needs SYS V code...any patchers out there?
  1179. */
  1180. init_term ()
  1181. {
  1182.     /*    play havoc with the terminal :-) */
  1183.  
  1184. #ifdef BSD
  1185.     ioctl (0, TIOCGETP, &orig);
  1186.     new = orig;
  1187.     new.sg_flags &= ~ECHO;
  1188.     new.sg_flags |= CBREAK;
  1189.  
  1190.     (flags->flush) ? ioctl (0, TIOCSETP, &new) :    /* to flush... */
  1191.         ioctl (0, TIOCSETN, &new);        /* ...or not to flush */
  1192. #endif
  1193. }
  1194.  
  1195. /* handle the outside world */
  1196. init_signal ()
  1197. {
  1198.     int lets_go ();
  1199.  
  1200.     signal (SIGINT, lets_go);
  1201.     signal (SIGTSTP, lets_go);
  1202.     signal (SIGQUIT, lets_go);
  1203. }
  1204.  
  1205. /*
  1206. **    something's up with the user...give a useful exit status so
  1207. **    we can ask things like "do you need help?"
  1208. */
  1209. int overtime ()
  1210. {
  1211.     int lets_go ();
  1212.     void handle_default ();
  1213.  
  1214.     /* does not return */
  1215.     if (exit_stat == -1 && flags->dflt)
  1216.         handle_default ();
  1217.  
  1218.     exit_stat = -2;
  1219.     lets_go ();
  1220. }
  1221.  
  1222. /*
  1223. **    the default_flag is set, and the user either typed a return
  1224. **    or timed out.  This routine does not return.
  1225. */
  1226. void handle_default ()
  1227. {
  1228.     int lets_go ();
  1229.  
  1230.     if (! flags->silent) {
  1231.         fputs (default_string, outfile);
  1232.         if (flags->both)
  1233.             fputs (default_string, otherout);
  1234.     }
  1235.     exit_stat = strlen (default_string);
  1236.     lets_go ();
  1237. }
  1238.  
  1239. /*    clean up and get out of here... */
  1240. int lets_go ()
  1241. {
  1242. #ifdef BSD
  1243.     ioctl (0, TIOCSETP, &orig);
  1244. #endif
  1245.     exit (exit_stat);
  1246. }
  1247.  
  1248. #ifdef DV_ERASE
  1249.  
  1250. /*
  1251. **    December 2, 1988
  1252. **    Bucko's (daniel) in progress notes for changing this...
  1253. **
  1254. **    first time through processing should be called as its' own
  1255. **    function from the -E case in the main (getopt ()) switch...
  1256. **
  1257. **    stdout and stderr should never be affected by any erasures...
  1258. **    (they probably are not now, I haven't thoroughly tested this...)
  1259. **
  1260. **    I need to drag in my word erase routine; never can tell how
  1261. **    long some people are going to want their lines with -n! :-)
  1262. **
  1263. **    If someone wants a control char (via literal (^V)), we should
  1264. **    give it to them...this would be more compatible with $< (csh)
  1265. **    and read (sh)... grabchars almost completely replaces these
  1266. **    now.
  1267. **
  1268. **    we can also be sensitive to pipe/no pipe via isatty ()...
  1269. */
  1270.  
  1271. /*    DV: handle erase characters, kill characters, etc. */
  1272. handle_erase (ch, cnt)
  1273. char ch;
  1274. int *cnt;
  1275. {
  1276.     static char first = 1;
  1277.     static char erasec, killc, werasec, lnextc, rprntc;
  1278.     static char lnextflg = 0;
  1279.     static char *cp;
  1280.     static FILE *tty;
  1281.     int i;
  1282.  
  1283.     if (first) {
  1284.         /* initialize static things */
  1285.         struct sgttyb sb;
  1286.         struct ltchars ltc;
  1287.  
  1288.         first = 0;
  1289.         cp = erase_buf;
  1290.         tty = fopen ("/dev/tty", "w");
  1291.  
  1292.         /* . this isn't going to do... what if -e is set?...dan */
  1293.         if (tty == NULL)
  1294.             tty = stderr;
  1295.         ioctl (0, TIOCGETP, &sb);
  1296.         ioctl (0, TIOCGLTC, <c);
  1297.         erasec = sb.sg_erase;
  1298.         killc = sb.sg_kill;
  1299.         werasec = ltc.t_werasc;
  1300.         lnextc = ltc.t_lnextc;
  1301.         rprntc = ltc.t_rprntc;
  1302.     }
  1303.  
  1304.     if (lnextflg) {
  1305.         ch |= 0x80;
  1306.         lnextflg = 0;
  1307.     }
  1308.     (*cnt) --;
  1309.     if (ch == erasec) {
  1310.         if (*cnt < 0)
  1311.             return;
  1312.         fprintf (tty, "\b \b");
  1313.         (*cnt) --;
  1314.         *--cp = 0;
  1315.     } else if (ch == killc) {
  1316.         while (*cnt >= 0) {
  1317.             fprintf (tty, "\b \b");
  1318.             (*cnt) --;
  1319.             *--cp = 0;
  1320.         }
  1321.     } else if (ch == werasec) {
  1322.         if (*cnt < 0)
  1323.             return;
  1324.         while ((cp[-1] == ' ' || cp[-1] == '\t') && (*cnt) >= 0) {
  1325.             fprintf (tty, "\b");
  1326.             (*cnt) --;
  1327.             *--cp = 0;
  1328.         }
  1329.         while (cp[-1] != ' ' && cp[-1] != '\t' && (*cnt) >= 0) {
  1330.             fprintf (tty, "\b \b");
  1331.             (*cnt) --;
  1332.             *--cp = 0;
  1333.         }
  1334.     } else if (ch == lnextc) {
  1335.         lnextflg = 1;
  1336.         fprintf (tty, "^\b");
  1337.     } else if (ch == rprntc) {
  1338.         for (i = strlen (erase_buf); i > 0; i--)
  1339.             putc ('\b', tty);
  1340.         fprintf (tty, "%s", erase_buf);
  1341.     } else {
  1342.         ch &= 0x7f;
  1343.         fprintf (tty, "%c", ch);
  1344.         *cp++ = ch;
  1345.         (*cnt) ++;
  1346.     }
  1347.     fflush (tty);
  1348.     return;
  1349. }
  1350. #endif
  1351. SHAR_EOF
  1352. fi
  1353. echo shar: "extracting 'grabchars.h'" '(553 characters)'
  1354. if test -f 'grabchars.h'
  1355. then
  1356.        echo shar: "will not over-write existing file 'grabchars.h'"
  1357. else
  1358. cat << \SHAR_EOF > 'grabchars.h'
  1359. /*
  1360. **    $Header: grabchars.h,v 1.3 88/12/05 19:46:20 daniel grabchars_1_3 $
  1361. **
  1362. **    grabchars.h - setup for grabchars
  1363. **
  1364. **    Dan Smith (daniel@island.uu.net), November 29, 1988
  1365. */
  1366.  
  1367. struct flag_type {
  1368.     int both;    /* output to stdout and stderr */
  1369.     int check;    /* filter input */
  1370.     int dflt;    /* use following char or string as default */
  1371.     int flush;    /* if set flush input buffer */
  1372.     int ret_key;    /* RETURN key exits when set */
  1373.     int silent;    /* be quiet, just return a status */
  1374.     int erase;    /* DV: honor erase/kill characters */
  1375. };
  1376.  
  1377. typedef struct flag_type FLAG;
  1378. SHAR_EOF
  1379. fi
  1380. exit 0
  1381. #    End of shell archive
  1382.  
  1383.  
  1384.