Subject: v22i036: NN Newsreader, release 6.4, Part01/21 Newsgroups: comp.sources.unix Approved: rsalz@uunet.UU.NET X-Checksum-Snefru: d04fa928 5e29b51a 7500b5b8 47b939e6 Submitted-by: "Kim F. Storm" Posting-number: Volume 22, Issue 36 Archive-name: nn6.4/part01 nn is a menu based (point and shoot) netnews reader with a complete set of features to satisfy both the expert and the novice user. Since its first release in Denmark in 1984 (!), in Europe in 1988, and the global release in June 1989, it has replaced rn and other well-known news readers at many sites. Some of the key features of nn are: * It is fast. It uses a dtabase, so it starts almost equally fast (in a few seconds), no matter whether you have 100 or 10000 unread articles! On my system nn uses less than 20 seconds to find all articles on a specific subject among 64000 articles in all groups! * Menu-based article selection prior to reading the articles with the articles sorted according to subject & posting time! * Release 6.4 uses standard .newsrc, and can leave individual articles unread! * Digests are automatically split and presented as ordinary articles! You can transparently save and respond to individual subarticles. * Full folder support: read, save, and delete individual articles. * Online help and manual. * Built-in unshar and patch functions. * Built-in uudecode function which will automatically unpack, concatenate, and decode multi-part postings. * Easy remapping of keys with advanced macro definition features. * Automatic kill & selection of articles based on subject or author. * Whole classes of news groups can easily be unsubscribed * Related groups can be merged and presented as a single group, e.g. comp.emacs and all gnu.emacs groups. * In a distributed environment, the database can be shared among all hosts on the network. Only one daemon is needed on the news server for all hosts. This works in a heterogenous environment as well. * NNTP is also supported (using a local database for speed). #! /bin/sh # This is a shell archive. Remove anything before this line, then feed it # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # Contents: README MANIFEST conf contrib doc help inews man regexp.h # term.c # Wrapped by storm@texas.dk on Sun May 6 18:19:13 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo If this archive is complete, you will see the following message: echo ' "shar: End of archive 1 (of 22)."' if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(7714 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' X INTRODUCTION TO NN X ------------------ X X RELEASE 6.4 X X Xnn is a menu based (point and shoot) netnews reader with a complete Xset of features to satisfy both the expert and the novice user. Since Xits first release in Denmark in 1984 (!), in Europe in 1988, and the Xglobal release in June 1989, it has replaced rn and other well-known Xnews readers at many sites. X XSome of the key features of nn are: X X * Menu-based article selection prior to reading the articles X with the articles sorted according to subject & posting time! X X This significantly reduces the time spent on news reading. X No keystorkes are wasted on articles you don't want to read, and X only the articles selected on the menu will be read. X X * Release 6.4 uses standard .newsrc, and can leave individual X articles unread! X X * Digests are automatically split and presented as ordinary articles! X You can transparently save and respond to individual subarticles. X X * Full folder support: read, save, and delete individual articles. X X * Online help and manual. X X * Built-in unshar and patch functions. X X * Built-in uudecode function which will automatically unpack, X concatenate, and decode multi-part postings. X X * Easy remapping of keys with advanced macro definition features. X X * Automatic kill & selection of articles based on subject or author. X X * User specified presentation sequence of news groups based on the X news group hierarchy. X X * Whole classes of news groups can easily be unsubscribed X permanently, e.g. talk.all and all.politics X X * Related groups can be merged and presented as a single group, e.g. X comp.emancs and all gnu.emacs groups. X X * Blindingly fast 'search for subject'. On my Texas S1500 system, X nn uses less than 20 seconds to find all articles on a specific X subject among 64000 articles in all groups! X X * News collection and presentation is extremely fast, because nn X uses its own database on top of the standard news system. X X * In a distributed environment, the database can be shared among all X hosts on the network. Only one daemon is needed on the news server X for all hosts. This works in a heterogenous environment as well. X X * NNTP is also supported (using a local database for speed). X XBecause of the database, nn starts almost equally fast (in a few Xseconds), no matter whether you have 100 or 10000 unread articles! XThe database takes up some disk space, but dramatically improves speed Xand functionality. The amount of disk space consumed is approx. 1Mb Xper 10000 articles. X X X DISTRIBUTION X ------------ X XThe package is posted as 22 separate shar archives on comp.sources.unix. XIt is unpacked by applying /bin/sh to each archive in turn. XEverything is a little more than 1 Mbyte, including documentation. X XIt is also available via anonymous ftp from X X host: dkuug.dk (129.142.96.41) X File: /pub/nn6.4.tar.Z (compressed tar) X X X COPYRIGHT X --------- X XCopyright (c) 1989, 1990 by Kim Fabricius Storm. All rights reserved. X XNot derived from licensed software except as stated below. X XPermission is granted to anyone to use, modify, and reuse this Xsoftware for any purpose on any computer system, and to redistribute Xit freely, subject to the following restrictions: X X1. The author is not responsible for the consequences of use of this X software, no matter how awful, even if they arise from defects in it. X X2. The origin of this software must not be misrepresented, either by X explicit claim or by omission. X X3. Altered versions must be plainly marked as such, and must not be X misrepresented as being the original software. X X XThe following code modules have been incorporated into nn, and the Xabove copyright notice does not apply to these modules; they include Xtheir own copyright notices (or have none): X Xregexp.c: Copyright (c) 1986 by University of Toronto. X Written by Henry Spencer. X Xunshar.c: No copyright notice. X Written by K. Greer, S. Shafer, and M. Mauldin X Xdecode.c: Derived from a modified Berkeley original posted on X USENET. X Xfullname.c: Copyright (c) 1986 by Rick Adams. X Derived from the Bnews distribution. X Xcontrib/*: Various copyright notices. X The software available in the contrib/ directory was sent X to me for inclusion in the nn distribution, because X the authors think it might be useful to other nn users. X I have included it *as is*. X Xinews/*: NNTP 1.5 mini-inews. Copyrights for NNTP applies. X The software in the inews/ directory is a stand-alone X version of the NNTP 1.5.7 mini-inews which has been X slightly changed to ease configuration when used with nn. X XVarious pieces of code which may have their own copyright notices are Xincluded in the contrib/ and inews/ directories. This software has been Xsent to me in the hope that it will be useful to somebody else. I Xhave included it in this spirit, but I take no responsibilities for Xthis software, and I have no intentions to support it. X X X INSTALLATION X ------------ X XThe following files are contained in the `doc' subdirectory: X XThe installation procedure is described in the file INSTALLATION. X XYou may also find useful information in the files PROBLEMS and NNTP. X XThe file NEWS-6.3 describes the major changes from release 6.1 to 6.3. X XThe file NEWS-6.4 describes the major changes from release 6.3 to 6.4. X X X BUG REPORTS and SUGGESTIONS X --------------------------- X XPlease send bug reports (and fixes) to the following address: X nn-bugs@dkuug.dk X XYou may also use nn-bugs for suggestions for improvements (missing Xfeatures in nn are considered to be bugs :-) X XThe easiest way to send a bug report is by using the :bug command in nn. X X X NN HAS ITS OWN NEWS GROUP X ------------------------- X XWe have an unmoderated news group dedicated to nn: news.software.nn X XThe news.software.nn group is used for discussion on all subjects Xrelated to the nn news reader. This includes, but is not limited to, Xquestions, answers, ideas, hints, information from the development Xgroup, patches, etc. X XThe news.software.nn group was created in January 1990 after an Xofficial vote. It may still be missing on parts of the net, so if you Xdon't get it please check your news feed, and help propagating the Xnews group to the entire net. X X X ACKNOWLEDGEMENTS X ---------------- X XSince the development of nn is now on its fifth year, numerous persons Xhave contributed to nn with ideas and critisism, have helped me debug Xthe software by patiently using alpha and beta versions, have provided Xbug fixes, small and big chunks of code, new configuration files, etc. X XMy warm thanks go to Rene Seindal and Wayne Davison for their many Xcontributions, to Lloyd W. Taylor for his efforts counting the Xvotes for news.software.nn, and to Paul D. Anderson for running the Xrelease 6.3 patch server. X XI also thank the following persons for their help and contributions: XPeter Andersen, Jonathan Bayer, Gardner Cohen, Bernie Cosell, P{r XEmanuelsson, Steven Grady, Miek Grenier, Scott Hankin, Kareth, Mike XKhaw, Edwin Kremer, Jean-Francois Lamy, Mark Moraes, A. E. Mossberg, XMark Nagel, Rich Salz, Steve Simmons, Wietse Z. Venema, James A. XWoods, and Pim Zandbergen. X XAnd of course I would like to thank the hundreds of other people who Xhave reported bugs, given suggestions, provided information, etc. XForgive me for not listing all your names here, but I hope you Xunderstand, and that you will continue to contribute your Xvaluable input to the continued developments. Let us keep nn in the Xlead! X X XKim Fabricius Storm XTexas Instruments A/S, Denmark X XEmail: storm@texas.dk XSnail: Marielundvej 46E, DK-2730 Herlev, Denmark Xtel: +45 42 91 7400 fax: +45 42 91 8400 END_OF_FILE if test 7714 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'MANIFEST' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'MANIFEST'\" else echo shar: Extracting \"'MANIFEST'\" \(10469 characters\) sed "s/^X//" >'MANIFEST' <<'END_OF_FILE' X File Name Archive # Description X---------------------------------------------------------- XREADME 1 Read this file first XMANIFEST 1 Packing list XFILES 22 Extract file names from MANIFEST XMakefile 21 Makefile for building nn XSPLITNN1 22 Split nn.1 in four parts. Xaccount.c 17 Accounting routines Xactive.c 20 Read active file Xadmin.c 12 Administration mode (nnadmin) Xanswer.c 14 Respond/post/mail code Xarticles.c 17 Incore article fetching and management Xarticles.h 21 Header file for article management Xaux.sh 10 Auxiliary script for post/mail Xback_act.sh 22 Backup active file once a day Xcollect.c 16 Collect groups and articles in the database Xconf 1 Directory for s- and m- files Xconf/m-3b1g.h 22 For 3b1 (unix-pc) with GCC [no networking]. Xconf/m-att3b.h 22 For AT&T 3b2 (with s-usg3-1.h) Xconf/m-convex.h 21 For Convex. Xconf/m-dec3100.h 22 For DECstation 3100 (with s-bsd4-2.h) Xconf/m-gould.h 22 For Gould PN6000 (with s-bsd4-3.h) Xconf/m-hp9000.h 22 For HP9000 series 320 and 800 (at least) Xconf/m-i80286.h 22 For Intel 80286 processors [no network support] Xconf/m-i80386.h 22 For Intel 80386 processors [no network support] Xconf/m-m680x0.h 22 For 68000 family processors Xconf/m-m88000.h 22 For Motorola 88000 risc processors Xconf/m-mips.h 22 For MIPS processors Xconf/m-pyramid.h 22 For Pyramid (and Targon 35). Xconf/m-rt6150.h 22 For IBM 6150 Xconf/m-sgi4D.h 22 For Silicon Graphics 4D series. Xconf/m-sparc.h 22 For SPARC processors Xconf/m-sun386i.h 22 For 80386 based SUNs [have network support] Xconf/m-symmetry.h 22 For Sequent Symmetry. Xconf/m-template.h 21 Template for new machine files. Xconf/m-vax.h 22 For VAX family Xconf/s-3b1g.h 22 For 3b1 (unix-pc) with GCC. Xconf/s-aix221.h 14 For AIX 2.2.1 Xconf/s-aux1-1.h 22 For A/UX 1.1 Xconf/s-bsd4-2.h 20 For 4.2 BSD and Ultrix systems Xconf/s-bsd4-3.h 22 For 4.3 BSD systems Xconf/s-dnix5-2.h 22 For dnix 5.2 on DIAB DS90. Xconf/s-dnix5-3.h 22 For dnix 5.3 on DIAB DS90. Xconf/s-dynix3-0.h 22 For Dynix 3.0 on Symmetry. Xconf/s-fortune.h 19 For Fortune 32:16 [read comments in the file] Xconf/s-hpux.h 6 For HPUX (series 300) Xconf/s-hpux2-1.h 22 For HPUX 2.1 (series 800) Xconf/s-hpux3-0.h 22 For HPUX 3.0 (series 800) Xconf/s-hpux6-5.h 21 For HPUX 6.5 or newer (series 300) Xconf/s-pyramid.h 22 For Pyramid (and Targon 35). Xconf/s-sgi4D.h 21 For IRIX 3.1/3.2 [read comments in the file] Xconf/s-sunos3.h 22 For SunOS 3 Xconf/s-sunos4-0.h 22 For SunOS 4.0 Xconf/s-sys5-tcap.h 22 For system V using termcap. Xconf/s-sys5.h 20 For most system V based systems. Xconf/s-template.h 19 Template for new system files. Xconf/s-texas1500.h 22 For Texas Instruments System 1500. Xconf/s-tower32.h 22 For NCR tower Xconf/s-umipsb.h 19 For Mips w/riscos 4.0 or greater Xconf/s-uport2-2.h 22 For Microport UNIX V.2 Xconf/s-usg3-1.h 22 For most system V systems (obsolete) Xconf/s-xenix386.h 21 For xenix386 [termcap version]. Xconf/s-xenix386ds.h 22 For Xenix386 2.3.2 w/development system. Xconfig.h-dist 17 CONFIGURATION FILE, DISTRIBUTED VERSION Xcontrib 1 Directory for contributed software Xcontrib/aspell 20 Ispell front-end written in perl Xcontrib/cn 22 Checknews w/multi-column output Xcontrib/recmail.c 18 Sample recmail program Xcontrib/recmail.sh 18 Sample recmail script Xcvt-help.c 22 Convertion utility for help files Xdata.h 15 Internal article and group information Xdb.c 13 Database access and update routines Xdb.h 20 External database format Xdebug.h 22 Debugging symbols Xdecode.c 17 UUdecode engine Xdigest.c 17 Digest splitting Xdir.c 19 Directory access Xdir.h 22 Include file for directory access Xdoc 1 Directory for documentation files Xdoc/INSTALLATION 9 INSTALLATION AND CONFIGURATION Xdoc/NEWS-6.3 18 What's new in release 6.3 Xdoc/NEWS-6.4 16 What's new in release 6.4 Xdoc/NNTP 16 INSTALLATION WITH NNTP or NFS Xdoc/PROBLEMS 15 KNOWN PROBLEMS AND SOLUTIONS Xdoc/RELEASE_NOTES 20 Known problems Xexecute.c 19 Shell command execution Xexpire.c 15 Database expiration Xfolder.c 13 Folder menu and file name expansion Xformat.awk 21 Nroff -man formatter in awk Xfullname.c 20 Extract full name from /etc/passwd Xglobal.c 4 Global routines Xglobal.h 19 Global include file Xgroup.c 10 Group menu, group overview, and goto-group Xhelp 1 Directory for online help files Xhelp/adm.upgrade1 22 Start-up message 1 Xhelp/adm.upgrade2 22 Start-up message 2 Xhelp/adm.upgrade3 22 Start-up message 3 Xhelp/adm.upgrade4 22 Start-up message 4 Xhelp/adm.welcome 22 New user welcome message Xhelp/help.attr 22 Help on attributes Xhelp/help.commands 20 Help on commands Xhelp/help.extended 21 Help on : commands Xhelp/help.help 22 Help on help Xhelp/help.map 21 Help on key mapping Xhelp/help.menu 21 ? in selection mode Xhelp/help.more 21 ? in reading mode Xhelp/help.read 12 Help on reading mode Xhelp/help.set 22 Help on :set commands Xhelp/help.show 22 Help on :show commands Xhelp/help.sort 21 Help on menu ordering Xhelp/help.variables 2 Help on variables Xhostname.c 20 Generic gethostname() function Xinews 1 Directory for NNTP 1.5.7 mini-inews Xinews/Makefile 19 mini-inews makefile Xinews/Manifest 22 mini-inews manifest Xinews/README 21 mini-inews read me 2nd Xinews/README.NN 19 mini-inews read me 1st Xinews/clientlib.c 16 mini-inews source Xinews/clientlib.h 22 mini-inews source Xinews/conf.h 20 mini-inews configuration file Xinews/inews.c 12 mini-inews source Xinews/nntp.h 20 mini-inews source Xinews/version.c 22 mini-inews source Xinit.c 11 Init file and extended command parsing Xinit.sample 20 Sample init file Xinst.sh 18 Installation script Xkeymap.c 6 Key mapping and command names Xkeymap.h 19 Key and command names Xkill.c 11 Kill compilation and processing Xmacro.c 14 Macro compilation and execution Xman 1 Directory for user manuals Xman/nn.1.A 2 nn manual (for users) - part 1 Xman/nn.1.B 7 nn manual (for users) - part 2 Xman/nn.1.C 3 nn manual (for users) - part 3 Xman/nn.1.D 4 nn manual (for users) - part 4 Xman/nnacct.1m 9 nnacct manual (for sysadm) Xman/nnadmin.1m 8 nnadmin manual (for sysadm) Xman/nncheck.1 20 nncheck manual (for users) Xman/nngoback.1 19 nngoback manual (for users) Xman/nngrab.1 5 nngrab manual (for users) Xman/nngrep.1 20 nngrep manual (for users) Xman/nnmaster.8 13 nnmaster manual (for sysadm) Xman/nnpost.1 21 nnpost manual (for users) Xman/nnspew.8 21 nnspew manual (for sysadm) Xman/nnstats.1m 21 nnstats manual (for sysadm) Xman/nntidy.1 21 nntidy manual (for users) Xman/nnusage.1m 21 nnusage manual (for sysadm) Xmaster.c 7 Database manager (nnmaster) Xmatch.c 20 String/regexp matching Xmenu.c 6 Article selection menu Xmenu.h 21 Return values from various modes Xmore.c 9 Pager (reading mode) Xnews.c 18 Parsing of news article headers Xnews.h 21 Article header information Xnewsrc.c 5 Access and update .newsrc Xnn.c 14 nn main program Xnngrab.sh 22 Quick subject search Xnnmail.c 21 Primitive mailer w/domain addressing Xnnspew.sh 22 Subject database generator (for nngrab) Xnnstats.sh 20 Collection and Expiration reports Xnntp.c 10 NNTP interface library Xnntp.h 20 NNTP response codes Xnnusage.sh 22 Usage statistics Xoptions.c 19 Option parsing (much better than getopt!) Xoptions.h 21 Header file for option parsing Xpack_date.c 19 Timestamp generation Xpack_name.c 3 Pack sender names Xpack_subject.c 21 Pack subject lines Xpatchlevel.h 8 Patch level and history Xprefix.c 16 Generate prefix for scripts. Xproto.c 19 Locking and message passing Xproto.h 21 Include file for proto routines Xregexp.c 8 Regular expression compile and exec Xregexp.h 1 Include file for regexp usage Xreroute.c 18 Mail address parsing and rewrite Xroutes.sample 21 Sample configuration file for nnmail Xsave.c 15 Article saving, unpacking, etc. Xsequence.c 5 Group presentation sequence parser Xsort.c 11 Article menu ordering Xterm.c 1 Terminal interface library Xterm.h 21 Include file for terminal interface Xunshar.c 18 Unshar pre-processor Xupgrade_rc.sh 22 .nn/rc to .newsrc converter Xusercheck.c 22 Check uid during installation Xvararg.h 21 Faked and real varargs.h encapsulation Xvariable.c 12 Variable management Xxmakefile 18 Skeleton for ymakefile END_OF_FILE if test 10469 -ne `wc -c <'MANIFEST'`; then echo shar: \"'MANIFEST'\" unpacked with wrong size! fi # end of 'MANIFEST' fi if test ! -d 'conf' ; then echo shar: Creating directory \"'conf'\" mkdir 'conf' fi if test ! -d 'contrib' ; then echo shar: Creating directory \"'contrib'\" mkdir 'contrib' fi if test ! -d 'doc' ; then echo shar: Creating directory \"'doc'\" mkdir 'doc' fi if test ! -d 'help' ; then echo shar: Creating directory \"'help'\" mkdir 'help' fi if test ! -d 'inews' ; then echo shar: Creating directory \"'inews'\" mkdir 'inews' fi if test ! -d 'man' ; then echo shar: Creating directory \"'man'\" mkdir 'man' fi if test -f 'regexp.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'regexp.h'\" else echo shar: Extracting \"'regexp.h'\" \(731 characters\) sed "s/^X//" >'regexp.h' <<'END_OF_FILE' X/* X * Definitions etc. for regexp(3) routines. X * X * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], X * not the System V one. X */ X X#define NSUBEXP 10 Xtypedef struct regexp { X char *startp[NSUBEXP]; X char *endp[NSUBEXP]; X char regstart; /* Internal use only. */ X char reganch; /* Internal use only. */ X char *regmust; /* Internal use only. */ X int regmlen; /* Internal use only. */ X char program[1]; /* Unwarranted chumminess with compiler. */ X} regexp; X X X/* X * The first byte of the regexp internal "program" is actually this magic X * number; the start node begins in the second byte. X */ X#define MAGIC 0234 X Xextern regexp *regcomp(); Xextern int regexec(); Xextern void regsub(); Xextern void regerror(); X END_OF_FILE if test 731 -ne `wc -c <'regexp.h'`; then echo shar: \"'regexp.h'\" unpacked with wrong size! fi # end of 'regexp.h' fi if test -f 'term.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'term.c'\" else echo shar: Extracting \"'term.c'\" \(27619 characters\) sed "s/^X//" >'term.c' <<'END_OF_FILE' X/* X * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved. X * X * Terminal interface. X */ X X#include X#include X#include "config.h" X#include "term.h" X#include "keymap.h" X X#ifdef RESIZING X#include /* for TIOCGWINSZ */ X#ifdef SYSV_RESIZING X#include X#include X#endif X Xint s_resized; X#endif X Xexport char *term_name = NULL; Xexport int show_current_time = 1; Xexport int conf_dont_sleep = 0; Xexport int prompt_length; Xexport int terminal_speed; Xexport int slow_speed = 1200; Xexport int any_message = 0; Xexport int flow_control = 1; Xexport int use_visible_bell = 1; /* if supported by terminal */ X Xexport key_type help_key = '?'; Xexport key_type comp1_key = SP; Xexport key_type comp2_key = TAB; Xexport key_type erase_key, kill_key; Xexport key_type delword_key = CONTROL_('W'); X Xstatic char bell_str[256] = "\007"; X X#ifdef USE_TERMINFO X X#include X#ifndef auto_left_margin X#include X#endif X X#define HAS_CAP(str) (str && *str) X Xextern char *tgoto(); /* some systems don't have this in term.h */ X X#else X X#define USE_TERMCAP X Xchar *tgoto(); Xchar PC; Xchar *BC, *UP; Xshort ospeed; X Xstatic char XBC[64], XUP[64]; Xstatic char enter_ca_mode[64], exit_ca_mode[64]; Xstatic char cursor_home[64]; Xstatic char cursor_address[64]; Xstatic char clear_screen[64]; Xstatic char clr_eol[64]; Xstatic char clr_eos[64]; Xstatic char enter_standout_mode[64], exit_standout_mode[64]; Xstatic char enter_underline_mode[64], exit_underline_mode[64]; Xstatic char key_down[64], key_up[64], key_right[64], key_left[64]; X Xint magic_cookie_glitch; /* magic cookie size */ X X#define putp(str) tputs(str, 0, outc) X X#define HAS_CAP(str) (*str) X Xstatic outc(c) X{ X putchar(c); X} X X#endif /* USE_TERMCAP */ X Xint Lines, Columns; /* screen size */ Xint cookie_size; /* size of magic cookie */ Xint two_cookies; /* space needed to enter&exit standout mode */ Xint STANDOUT; /* terminal got standout mode */ Xint WRAP; /* terminal got automatic margins */ X X#ifdef HAVE_TERMIO X X#define KEY_BURST 50 /* read bursts of 50 chars (or timeout after 100 ms) */ X X#ifdef USE_TERMCAP X#include X#endif X X#undef CBREAK X Xstatic struct termio norm_tty, raw_tty; X X#define IntrC norm_tty.c_cc[VINTR] X#define EraseC norm_tty.c_cc[VERASE] X#define KillC norm_tty.c_cc[VKILL] X#define SuspC CONTROL_('Z') /* norm_tty.c_cc[SWTCH] */ X X#else /* V7/BSD TTY DRIVER */ X X#include X Xstatic struct sgttyb norm_tty, raw_tty; Xstatic struct tchars norm_chars; X X#define IntrC norm_chars.t_intrc X#define EraseC norm_tty.sg_erase X#define KillC norm_tty.sg_kill X X#ifdef TIOCGLTC Xstatic struct ltchars spec_chars; X#define SuspC spec_chars.t_suspc X#else X#define SuspC CONTROL_('Z') X#endif X X#endif X X#ifdef USE_TERMCAP X Xopt_cap(cap, buf) Xchar *cap, *buf; X{ X char *tgetstr(); X X *buf = NUL; X return tgetstr(cap, &buf) != NULL; X} X Xget_cap(cap, buf) Xchar *cap, *buf; X{ X if (!opt_cap(cap, buf)) X user_error("TERMCAP entry for %s has no '%s' capability", X term_name, cap); X} X X#endif /* USE_TERMCAP */ X Xstatic int multi_keys = 0; X Xstatic struct multi_key { X key_type *cur_key; X key_type *keys; X key_type code; X} multi_key_list[MULTI_KEYS]; X Xenter_multi_key(code, keys) Xint code; Xkey_type *keys; X{ X register i; X X if (strlen((char *)keys) == 1) X /* will ignore arrow keys overlaying these keys */ X if (*keys == NL || *keys == CR || X *keys == erase_key || *keys == kill_key || X *keys == IntrC) return; X X /* lookup code to see if it is already defined... */ X for (i = 0; i < multi_keys; i++) X if (multi_key_list[i].code == (key_type)code) X goto replace_key; X X i = multi_keys++; X X /* now i points to matching or empty slot */ X if (i >= MULTI_KEYS) { X /* should never happen */ X log_entry('E', "too many multi keys"); X return; X } X X replace_key: X X multi_key_list[i].keys = keys; X multi_key_list[i].code = code; X} X Xdump_multi_keys() X{ X register i; X register key_type *cp; X X clrdisp(); X pg_init(0, 1); X X for (i = 0; i < multi_keys; i++) { X if (pg_next() < 0) break; X printf("%d\t%s\t", i, key_name(multi_key_list[i].code)); X for (cp = multi_key_list[i].keys; *cp; cp++) { X putchar(SP); X fputs(key_name(*cp), stdout); X } X } X X pg_end(); X} X X X#ifdef RESIZING X Xsig_type catch_winch() X{ X struct winsize winsize; X X (void) signal(SIGWINCH, catch_winch); X if (ioctl(0, TIOCGWINSZ, &winsize) >= 0 X && (winsize.ws_row != Lines || winsize.ws_col != Columns)) { X Lines = winsize.ws_row; X Columns = winsize.ws_col; X s_redraw = 1; X s_resized = 1; X } X} X#endif /* RESIZING */ X X#ifdef SV_INTERRUPT X#ifdef NO_SIGINTERRUPT Xstatic siginterrupt(signo, on) X{ X struct sigvec sv; X sv.sv_handler = signal (signo, SIG_DFL); X sv.sv_mask = 0; X sv.sv_flags = on ? SV_INTERRUPT : 0; X sigvec (signo, &sv, 0); X} X#endif X#endif X Xstatic unsigned sp_table[] = { X B9600, 960, X#ifdef B19200 X B19200, 1920, X#else X#ifdef EXTA X EXTA, 1920, X#endif X#endif X#ifdef B38400 X B38400, 3840, X#else X#ifdef EXTB X EXTB, 3840, X#endif X#endif X B1200, 120, X B2400, 240, X B4800, 480, X B300, 30, X 0, 0 X}; X Xstatic set_term_speed(sp) Xregister unsigned long sp; X{ X register unsigned *tp; X X for (tp = sp_table; *tp; tp += 2) X if (*tp == sp) { X terminal_speed = tp[1]; X return; X } X X terminal_speed = 30; X} X Xinit_term() X{ X#ifdef USE_TERMCAP X char tbuf[1024]; X#endif X X if ((term_name = getenv("TERM")) == NULL) X user_error("No TERM variable in enviroment"); X X#ifdef HAVE_TERMIO X ioctl(0, TCGETA, &norm_tty); X#else X ioctl(0, TIOCGETP, &norm_tty); X#endif X X#ifdef USE_TERMINFO X setupterm((char *)NULL, 1, (int *)NULL); X Columns = columns; X Lines = lines; X cookie_size = magic_cookie_glitch; X WRAP = auto_right_margin; X if (use_visible_bell && HAS_CAP(flash_screen)) X strcpy(bell_str, flash_screen); X else if (HAS_CAP(bell)) X strcpy(bell_str, bell); X if (! HAS_CAP(cursor_home)) X cursor_home = copy_str(tgoto(cursor_address, 0, 0)); X#else X X if (tgetent(tbuf, term_name) <= 0) X user_error("Unknown terminal type: %s", term_name); X X if (opt_cap("bc", XBC)) BC = XBC; X if (opt_cap("up", XUP)) UP = XUP; X opt_cap("pc", cursor_address); /* temp. usage */ X PC = cursor_address[0]; X X get_cap("cm", cursor_address); X if (!opt_cap("ho", cursor_home)) X strcpy(cursor_home, tgoto(cursor_address, 0, 0)); X X get_cap("cl", clear_screen); X get_cap("ce", clr_eol); X opt_cap("cd", clr_eos); X X#ifdef RESIZING X { X struct winsize winsize; X X if (ioctl(0, TIOCGWINSZ, &winsize) >= 0 X && winsize.ws_row != 0 && winsize.ws_col != 0) { X Lines = winsize.ws_row; X Columns = winsize.ws_col; X (void) signal(SIGWINCH, catch_winch); X#ifdef SV_INTERRUPT X siginterrupt(SIGWINCH, 1); /* make read from tty interruptable */ X#endif /* SV_INTERRUPT */ X } X } X if (Lines == 0 || Columns == 0) { X#endif /* RESIZING */ X Lines = tgetnum("li"); X Columns = tgetnum("co"); X#ifdef RESIZING X } X#endif /* RESIZING */ X X opt_cap("so", enter_standout_mode); X opt_cap("se", exit_standout_mode); X X opt_cap("us", enter_underline_mode); X opt_cap("ue", exit_underline_mode); X X opt_cap("kd", key_down); X opt_cap("ku", key_up); X opt_cap("kr", key_right); X opt_cap("kl", key_left); X X cookie_size = tgetnum("sg"); X X WRAP = tgetflag("am"); X X opt_cap("ti", enter_ca_mode); X opt_cap("te", exit_ca_mode); X X if (!use_visible_bell || !opt_cap("vb", bell_str)) X if (!opt_cap("bl", bell_str)) X strcpy(bell_str, "\007"); X X#endif /* !USE_TERMINFO */ X X STANDOUT = HAS_CAP(enter_standout_mode); X if (STANDOUT) { X if (cookie_size < 0) cookie_size = 0; X two_cookies = 2 * cookie_size; X } else X cookie_size = two_cookies = 0; X X X raw_tty = norm_tty; X X#ifdef HAVE_TERMIO X raw_tty.c_iflag &= ~(BRKINT|INLCR|ICRNL|IGNCR); X raw_tty.c_iflag |= IGNBRK|IGNPAR|ISTRIP; X raw_tty.c_oflag &= ~OPOST; X raw_tty.c_lflag &= ~(ISIG|ICANON|XCASE|ECHO|NOFLSH); X X /* read a maximum of 10 characters in one burst; timeout in 1-200 ms */ X raw_tty.c_cc[VEOF] = KEY_BURST; X raw_tty.c_cc[VEOL] = ((raw_tty.c_cflag & CBAUD) > B1200) ? 1 : 2; X set_term_speed((unsigned long)(raw_tty.c_cflag & CBAUD)); X#else X ioctl(0, TIOCGETC, &norm_chars); X X#ifdef TIOCGLTC X ioctl(0, TIOCGLTC, &spec_chars); X#endif X X ospeed = norm_tty.sg_ospeed; X set_term_speed((unsigned long)ospeed); X X raw_tty.sg_flags &= ~ECHO; X#ifdef CBREAK X#ifdef SV_INTERRUPT /* make read from tty interruptable */ X siginterrupt(SIGTSTP, 1); /* this is necessary to redraw screen */ X#endif X raw_tty.sg_flags |= CBREAK; X#else X raw_tty.sg_flags |= RAW; X#endif X X#ifdef SV_INTERRUPT X siginterrupt(SIGALRM, 1); /* make read from tty interruptable */ X#endif X#endif X X erase_key = (key_type)EraseC; X kill_key = (key_type)KillC; X X if (HAS_CAP(key_down)) X enter_multi_key(K_down_arrow, (key_type *)key_down); X if (HAS_CAP(key_up)) X enter_multi_key(K_up_arrow, (key_type *)key_up); X if (HAS_CAP(key_right)) X enter_multi_key(K_right_arrow, (key_type *)key_right); X if (HAS_CAP(key_left)) X enter_multi_key(K_left_arrow, (key_type *)key_left); X X visual_on(); X} X Xhome() X{ X putp(cursor_home); X} X Xstatic int curxy_c = -1, curxy_l, savxy_c = -1, savxy_l; X Xsave_xy() X{ X savxy_c = curxy_c; savxy_l = curxy_l; X} X Xrestore_xy() X{ X if (savxy_c < 0) return; X gotoxy(savxy_c, savxy_l); fl; X} X Xgotoxy(c, l) Xint c, l; X{ X curxy_c = c; curxy_l = l; X putp(tgoto(cursor_address, c, l)); X} X Xclrdisp() X{ X#ifdef USE_TERMINFO X putp(clear_screen); /* tputs is broken on UNISYS I've been told */ X#else X tputs(clear_screen, Lines, outc); X#endif X curxy_c = savxy_c = -1; X} X Xclrline() X{ X putp(clr_eol); X fl; X} X Xclrpage(lineno) Xregister int lineno; X{ X register int olineno= lineno; X X if (HAS_CAP(clr_eos)) { X#ifdef USE_TERMINFO X putp(clr_eos); X#else X tputs(clr_eos, Lines - lineno, outc); X#endif X } else { X clrline(); X lineno++; X for (; lineno < Lines; lineno++) { X gotoxy(0, lineno); X putp(clr_eol); X } X gotoxy(0, olineno); X fl; X } X} X Xstatic char so_buf[512], *so_p; Xstatic int so_c, so_l, so_b, so_active = 0; X Xso_gotoxy(c, l, blank) X{ X if (!STANDOUT && c >= 0) { X if (l >= 0) gotoxy(c, l); X return 0; X } X X so_active++; X so_c = c; X so_l = l; X so_b = blank; X so_p = so_buf; X *so_p = NUL; X X return 1; /* not really true if not standout & c < 0 */ X} X X/*VARARGS*/ Xso_printf(va_alist) Xva_dcl X{ X use_vararg; X X start_vararg; X so_vprintf(va_args1toN); X end_vararg; X} X Xso_vprintf(va_tail) Xva_tdcl X{ X char *fmt; X X fmt = va_arg1(char *); X X if (!so_active) { X vprintf(fmt, va_args2toN); X return; X } X X vsprintf(so_p, fmt, va_args2toN); X while (*so_p) so_p++; X} X Xso_end() X{ X int len; X X if (!so_active) return; X X if (so_l >= 0) { X X len = so_p - so_buf + two_cookies; X X if (so_c < 0) X so_c = Columns - len - 2; X if (so_c < 0) so_c = 0; X X if (len + so_c >= Columns) { X len = Columns - so_c - two_cookies; X so_buf[len] = NUL; X } X X if (cookie_size) { X gotoxy(so_c + len - cookie_size, so_l); X putp(exit_standout_mode); X } X X gotoxy(so_c, so_l); X X } X X if ((so_b & 1) && (!STANDOUT || !cookie_size)) putchar(SP); X X if (STANDOUT) putp(enter_standout_mode); X X fputs(so_buf, stdout); X X if (STANDOUT) putp(exit_standout_mode); X X if ((so_b & 2) && (!STANDOUT || !cookie_size)) putchar(SP); X X so_active = 0; X} X X X/*VARARGS*/ Xso_printxy(va_alist) Xva_dcl X{ X int k, l; X use_vararg; X X start_vararg; X X k = va_arg1(int); X l = va_arg2(int); X X so_gotoxy(k, l, 0); X so_vprintf(va_args3toN); X so_end(); X X end_vararg; X} X Xunderline(on) X{ X if (cookie_size) return 0; X if (! HAS_CAP(enter_underline_mode)) return 0; X putp(on ? enter_underline_mode : exit_underline_mode); X return 1; X} X Xhighlight(on) X{ X if (cookie_size) return 0; X if (! HAS_CAP(enter_standout_mode)) return 0; X putp(on ? enter_standout_mode : exit_standout_mode); X return 1; X} X Xstatic int is_visual = 0; Xstatic int is_raw = 0; X X#ifdef HAVE_TERMIO X#define RAW_MODE_ON ioctl(0, TCSETAF, &raw_tty) X#define RAW_MODE_OFF ioctl(0, TCSETAF, &norm_tty) X#else X#define RAW_MODE_ON ioctl(0, TIOCSETP, &raw_tty) X#define RAW_MODE_OFF ioctl(0, TIOCSETP, &norm_tty) X#endif X Xvisual_on() X{ X if (HAS_CAP(enter_ca_mode)) { X putp(enter_ca_mode); X is_visual = 1; X } X} X Xvisual_off() X{ X int was_raw = is_raw; X X if (term_name == NULL) return 0; X X if (is_visual && HAS_CAP(exit_ca_mode)) putp(exit_ca_mode), fl; X is_visual = 0; X X is_raw = 1; X unset_raw(); X X return was_raw; X} X X#ifdef CBREAK Xraw() X{ X if (is_raw == 1) X return; X is_raw = 1; X RAW_MODE_ON; X} X Xno_raw() X{ X return 0; X} X Xunset_raw() X{ X if (is_raw == 0) X return 0; X RAW_MODE_OFF; X is_raw = 0; X return 1; X} X X#else /* not CBREAK */ Xstatic int must_set_raw = 1; X Xraw() X{ X if (!flow_control) { X if (!must_set_raw) return; X must_set_raw = 0; X } X X if (is_raw) return; X X RAW_MODE_ON; X X is_raw++; X} X Xno_raw() X{ X if (!flow_control) return 0; X X if (!is_raw) return 0; X X RAW_MODE_OFF; X X is_raw = 0; X X return 1; X} X Xunset_raw() X{ X int was_raw = is_raw; X X if (is_raw) { X RAW_MODE_OFF; X is_raw = 0; X } X X if (!flow_control) X must_set_raw = 1; X return was_raw; X} X X#endif /* CBREAK */ X Xstatic int do_flush_input = 0; X Xflush_input() X{ X#ifdef HAVE_TERMIO X ioctl(0, TCFLSH, 0); X do_flush_input = 1; X#else X#ifdef FREAD X int arg = FREAD; X ioctl(0, TIOCFLUSH, &arg); X#else X ioctl(0, TIOCFLUSH, 0); X#endif X#endif X} X Xint enable_stop = 1; X X#ifndef KEY_BURST X Xstatic int alarm_on = 0; X Xstatic mk_timeout() X{ X alarm_on = 0; X} X X#endif X Xstatic int do_macro_processing = 1; X Xget_c() X{ X key_type c; X int any_multi, key_cnt, mc; X register struct multi_key *mk; X register int i; X#ifdef KEY_BURST X static char cbuf[KEY_BURST], *cp; X static int n = 0; X X if (do_flush_input) { X do_flush_input = 0; X n = 0; X } X#else X int n; X key_type first_key; X#endif X X next_key: X if (s_hangup) X return K_interrupt; X X#ifdef RESIZING X if (s_resized) { X s_resized = 0; X return GETC_COMMAND | K_REDRAW; X } X#endif X X if (do_macro_processing) X switch (m_getc(&mc)) { X case 0: X break; X case 1: X return mc; X case 2: X return K_interrupt; X } X X for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++) X mk->cur_key = mk->keys; X key_cnt = 0; X X#ifdef KEY_BURST X if (n <= 0) { X n = read(0, cbuf, KEY_BURST); X if (n < 0 && errno != EINTR) s_hangup++; X if (n <= 0) return K_interrupt; X cp = cbuf; X } X X while (--n >= 0) { X c = (key_type)*cp++; X#else X X while ((n = read(0, (char *)&c, 1)) > 0) { X c &= 0177; /* done by ISTRIP on USG systems */ X#endif X X if (c == CONTROL_('Q') || c == CONTROL_('S')) X continue; X X any_multi = 0; X for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++) X if (mk->cur_key) { X if (*(mk->cur_key)++ == c) { X if (*(mk->cur_key) == NUL) { X c = mk->code; X goto got_char; X } X any_multi++; X } else X mk->cur_key = NUL; X } X X if (any_multi) { X#ifndef KEY_BURST X if (key_cnt == 0) { X first_key = c; X alarm_on = 1; X signal(SIGALRM, mk_timeout); X MICRO_ALARM(); X } X#endif X key_cnt++; X continue; X } X if (key_cnt == 0) X goto got_char; X X ding(); X flush_input(); X goto next_key; X } X X#ifdef CBREAK X if (s_redraw) { X s_redraw = 0; X return GETC_COMMAND | K_REDRAW; X } X#endif X X#ifndef KEY_BURST X if (n < 0) { X if (errno != EINTR) s_hangup++; X return K_interrupt; X } X#endif X X#ifdef RESIZING X if (s_resized) { X s_resized = 0; X return GETC_COMMAND | K_REDRAW; X } X#endif X X#ifndef KEY_BURST X if (n < 0 && key_cnt) X c = first_key; X#endif X Xgot_char: X X#ifndef KEY_BURST X if (alarm_on) { X alarm(0); X alarm_on = 0; X } X#endif X X c = global_key_map[c]; X X#ifndef CBREAK X if (c == SuspC) { X if (!enable_stop) goto next_key; X if (suspend_nn()) X return GETC_COMMAND | K_REDRAW; X else X goto next_key; X } X X if (c == IntrC) c = K_interrupt; X#endif X return (int)c; X} X X X/* X * read string with completion, pre-filling, and break on first char X * X * dflt is a string that will be use as default value if the X * space bar is hit as the first character. X * X * prefill pre-fill the buffer with .... and print it X * X * break_chars return immediately if one of these characters X * is entered as the first character. X * X * completion is a function that will fill the buffer with a value X * see the group_completion and file_completion routines X * for examples. X */ X Xchar *get_s(dflt, prefill, break_chars, completion) Xchar *dflt, *prefill, *break_chars; Xfct_type completion; X{ X static char buf[GET_S_BUFFER]; X register char *cp; X register int i, c, lastc; X char *ret_val = buf; X int comp_used, comp_len; X int ostop, max, did_help; X int hit_count; X X switch (m_gets(buf)) { X case 0: X break; X case 1: X return buf; X case 2: X return NULL; X } X X ostop = enable_stop; X enable_stop = 0; X do_macro_processing = 0; X hit_count = 0; X X max = Columns - prompt_length; X X if (max >= FILENAME) max = FILENAME-1; X X i = comp_len = comp_used = did_help = 0; X X if (prefill && prefill[0]) { X while (c = *prefill++) { X if (i == max) break; X X putchar(c); X buf[i] = c; X i++; X } X fl; X } X X if (dflt && *dflt == NUL) X dflt = NULL; X X if (break_chars && *break_chars == NUL) X break_chars = NULL; X X c = NUL; X for(;;) { X lastc = c; X c = get_c(); X if (c & GETC_COMMAND) continue; X X kill_prefill_hack: X X hit_count++; X X if (i == 0) { X if (c == comp1_key && dflt) { X while ((c = *dflt++) != NUL && i < max) { X putchar(c); X buf[i] = c; X i++; X } X fl; X dflt = NULL; X continue; X } X if (cp = break_chars) { X while (*cp) X if (*cp++ == c) { X buf[0] = c; X buf[1] = NUL; X goto out; X } X } X } X X if (completion != NULL_FCT) { X if (comp_used && c == erase_key) { X CALL(completion)(buf, -1); X if (did_help) { clrmsg(i); did_help = 0; } X if (comp_len) { X i -= comp_len; X while (--comp_len >= 0) putchar(BS); X clrline(); X } X comp_len = comp_used = 0; X if (lastc == help_key) goto no_completion; X continue; X } X X if (c == comp1_key || c == comp2_key || c == help_key) { X if (!comp_used || c == comp2_key || X (c == help_key && lastc != c)) { X buf[i] = NUL; X if ((comp_used = CALL(completion)(buf, i)) == 0) { X ding(); X continue; X } X if (comp_used < 0) { X comp_used = 0; X goto no_completion; X } X comp_len = 0; X } X if (c == help_key) { X if (CALL(completion)((char *)NULL, 1)) { X gotoxy(prompt_length+i, prompt_line); fl; X did_help = 1; X } X continue; X } X X if (comp_len) { X i -= comp_len; X while (--comp_len >= 0) putchar(BS); X clrline(); X comp_len = 0; X } X X switch ( CALL(completion)((char *)NULL, 0) ) { X X case 0: /* no possible completion */ X comp_used = 0; X ding(); X continue; X X case 2: /* whole new alternative */ X while (--i >= 0) putchar(BS); X clrline(); X /* fall thru */ X X case 1: /* completion */ X comp_len = i; X while (c = buf[i]) { X if (i == max) break; X putchar(c); X i++; X } X fl; X comp_len = i - comp_len; X continue; X } X } X X if (comp_used) { X CALL(completion)(buf, -1); X if (did_help) clrmsg(i); X comp_len = comp_used = 0; X } X } X X no_completion: X X if (c == CR || c == NL) { X buf[i] = NUL; X break; X } X X if (c == erase_key) { X if (i <= 0) continue; X i--; X putchar(BS); X putchar(' '); X putchar(BS); X fl; X continue; X } X X if (c == delword_key) { X if (i <= 0) continue; X buf[i-1] = 'X'; X while (i > 0 && isalnum(buf[i-1])) { putchar(BS); i--; } X clrline(); X continue; X } X X if (c == kill_key) { X while (i > 0) { putchar(BS); i--; } X clrline(); X if (hit_count == 1 && dflt) { X c = comp1_key; X goto kill_prefill_hack; X } X continue; X } X X if (c == K_interrupt) { X ret_val = NULL; X break; X } X X if (!isascii(c) || !isprint(c)) continue; X X if (i == max) continue; X X if (i > 0 && buf[i-1] == '/' && (c == '/' || c == '+')) { X while (i > 0) { putchar(BS); i--; } X clrline(); X } X X putchar(c); X fl; X X buf[i] = c; X i++; X } X out: X enable_stop = ostop; X do_macro_processing = 1; X return ret_val; X} X Xexport int list_offset = 0; X Xlist_completion(str) Xchar *str; X{ X static int cols, line; X X if (str == NULL) { X cols = Columns; X line = prompt_line + 1; X X gotoxy(0, line); X clrpage(line); X return 1; X } X X str += list_offset; X X for (;;) { X cols -= strlen(str); X if (cols >= 0) { X printf("%s%s", str, cols > 0 ? " " : ""); X cols--; X return 1; X } X if (line >= Lines - 1) return 0; X line++; X cols = Columns; X gotoxy(0, line); X if (line == Lines - 1) cols--; X } X} X Xyes(must_answer) Xint must_answer; X{ X int c, help = 1, in_macro = 0; X X switch (m_yes()) { X case 0: X break; X case 1: X return 0; X case 2: X return 1; X case 3: X do_macro_processing = 0; X in_macro++; X break; X } X X for (;;) { X if (!is_raw) { X raw(); X c = get_c(); X unset_raw(); X } else X c = get_c(); X X if (c == 'y' || c == 'Y') { X c = 1; X break; X } X X if (must_answer == 0 && (c == SP || c == CR || c == NL)) { X c = 1; X break; X } X X if (c == 'n' || c == 'N') { X c = 0; X break; X } X if (c == K_interrupt) { X c = -1; X break; X } X if (help) { X fputs(" y=YES n=NO", stdout); X prompt_length += 11; X help = 0; X } X } X X if (in_macro) { X if (c < 0) m_break(); X do_macro_processing = 1; X } X X return c; X} X X Xding() X{ X putp(bell_str); X fl; X} X X Xdisplay_file(name, modes) Xchar *name; Xint modes; X{ X FILE *f; X register c, stand_on; X int linecnt, headln_cnt, hdline, no_conf; X char headline[128]; X import char *help_directory; X X headline[0] = 0; X hdline = 0; X no_conf = 0; X X headln_cnt = -1; X X if (modes & CLEAR_DISPLAY) { X gotoxy(0,0); X clrdisp(); X } X X linecnt = Lines - 1; X Xchain: X X f = open_file(relative(help_directory, name), OPEN_READ); X if (f == NULL) X printf("\r\n\nFile %s is not available\n\n", name); X else { X stand_on = 0; X X while ((c = getc(f)) != EOF) { X#ifdef HAVE_JOBCONTROL X if (s_redraw) { X no_conf = 1; X break; X } X#endif X no_conf = 0; X if (c == '\1') { X if (STANDOUT) { X putp(stand_on ? exit_standout_mode : enter_standout_mode); X stand_on = !stand_on; X } X continue; X } X if (c == '\2') { X headln_cnt = 0; X continue; X } X if (c == '\3') { X headln_cnt = 0; X while ((c = getc(f)) != EOF && c != NL) X headline[headln_cnt++] = c; X headline[headln_cnt++] = NUL; X name = headline; X fclose(f); X goto chain; X } X if (c == '\4') { X printf("%s", version_id); X continue; X } X X if (headln_cnt >= 0) X headline[headln_cnt++] = c; X X if (hdline) { X puts(headline); X putchar(CR); X hdline = 0; X linecnt--; X } X X putchar(c); X if (c == NL) { X putchar(CR); X if (headln_cnt >= 0) { X headline[--headln_cnt] = 0; X headln_cnt = -1; X } X if (--linecnt == 0) { X no_conf = 1; X if (any_key(0) == K_interrupt) X break; X linecnt = Lines - 1; X if (modes & CLEAR_DISPLAY) { X gotoxy(0,0); X clrdisp(); X } X hdline = headline[0]; X } X } X } X X if (stand_on) putp(exit_standout_mode); X fclose(f); X } X X prompt_line = Lines-1; /* move prompt to last line */ X X if (!no_conf && (modes & CONFIRMATION)) X any_key(prompt_line); X} X X X/*VARARGS*/ Xuser_error(va_alist) Xva_dcl X{ X char *fmt; X use_vararg; X X unset_raw(); X clrdisp(); X fl; X X start_vararg; X fmt = va_arg1(char *); X X vprintf(fmt, va_args2toN); X putchar(NL); X X end_vararg; X nn_exit(1); X} X X/*VARARGS*/ Xmsg(va_alist) Xva_dcl X{ X use_vararg; X X start_vararg; X vmsg(va_args1toN); X end_vararg; X} X Xvmsg(va_tail) Xva_tdcl X{ X static char errmsg[512] = ""; X char *fmt; X X fmt = va_arg1(char *); X X if (fmt) vsprintf(errmsg, fmt, va_args2toN); X X gotoxy(0, Lines-1); X fputs(errmsg, stdout); X clrline(); X any_message = 1; X X gotoxy(prompt_length, prompt_line); X fl; X} X Xclrmsg(col) Xint col; X{ X gotoxy(0, prompt_line + 1); X clrpage(prompt_line + 1); X if (col >= 0) X gotoxy(prompt_length + col, prompt_line); X fl; X any_message = 0; X} X X X/*VARARGS*/ Xprompt(va_alist) Xva_dcl X{ X register char *cp; X int stand_on; X char *fmt; X static char cur_p[FILENAME]; X static char saved_p[FILENAME]; X use_vararg; X X start_vararg; X X fmt = va_arg1(char *); X X if (fmt == P_VERSION) { X gotoxy(0, prompt_line + 1); X printf("Release %s ", version_id); X clrline(); X any_message++; X X if (prompt_line >= 0) X gotoxy(prompt_length, prompt_line); X goto out; X } X X if (fmt == P_SAVE) { X strcpy(saved_p, cur_p); X goto out; X } X X if (fmt == P_RESTORE) X strcpy(cur_p, saved_p); X X if (prompt_line >= 0) X gotoxy(0, prompt_line); X X if (fmt == P_MOVE) { X clrline(); X goto out; X } X X if (fmt != P_REDRAW && fmt != P_RESTORE) X vsprintf(cur_p, fmt, va_args2toN); X X putchar(CR); X X for (cp = cur_p, stand_on = 0, prompt_length = 0; *cp; cp++) { X if (*cp == '\1') { X if (cp[1] != '\1') { X if (STANDOUT) { X putp(stand_on ? exit_standout_mode : enter_standout_mode); X stand_on = !stand_on; X prompt_length += cookie_size; X } X continue; X } X cp++; X } else X if (*cp == '\2') { X time_t t, tick_usage(); X char *timestr; X X t = tick_usage(); X X if (show_current_time) { X timestr = ctime(&t) + 11; X timestr[5] = NUL; X X printf("-- %s ", timestr); X prompt_length += 9; X } X X if (unread_mail(t)) { X printf("Mail "); X prompt_length += 5; X } X X continue; X } X X putchar(*cp); X prompt_length ++; X } X if (stand_on) { X putp(exit_standout_mode); X prompt_length += cookie_size; X } X X clrline(); X X if (fmt == P_RESTORE) X restore_xy(); X else X curxy_c = -1; X X out: X end_vararg; X} X X Xany_key(line) Xint line; X{ X int was_raw, c, dmp; X X was_raw = is_raw; X if (!is_raw) raw(); X if (line == 0) X line = -1; X else X if (line < 0) X line = Lines + line; X X if (line != 10000) X so_printxy(0, line, "Hit any key to continue"); X X clrline(); X X dmp = do_macro_processing; X do_macro_processing = 0; X c = get_c(); X if (c == 'q' || c == 'Q') c = K_interrupt; X do_macro_processing = dmp; X X if (!was_raw) unset_raw(); X X return c; X} X X Xstatic pg_fline, pg_width, pg_maxw, pg_line, pg_col, pg_quit; X Xpg_init(first_line, cols) Xint first_line, cols; X{ X pg_fline = first_line; X pg_line = pg_fline - 1; X pg_quit = pg_col = 0; X pg_width = Columns / cols; X pg_maxw = pg_width * (cols - 1); X} X Xpg_scroll(n) Xint n; X{ X pg_line += n; X if (pg_line >= (Lines - 1)) { X pg_line = 0; X if (any_key(0) == K_interrupt) X return 1; X putchar(CR); X clrline(); X } X return 0; X} X Xpg_next() X{ X int c; X X pg_line++; X if (pg_line < Lines) { X gotoxy(pg_col, pg_line); X if (pg_line == Lines - 1 && pg_col == pg_maxw) { X c = any_key(0); X gotoxy(0, pg_fline); X clrpage(pg_fline); X pg_col = 0; X pg_line = pg_fline; X if (c == K_interrupt) { X pg_quit = 1; X return -1; X } X return 1; X } X } else { X pg_line = pg_fline; X pg_col += pg_width; X gotoxy(pg_col, pg_line); X } X return 0; X} X Xpg_indent(pos) Xint pos; X{ X gotoxy(pg_col + pos, pg_line); X} X Xpg_end() X{ X if (pg_quit == 0 && pg_next() == 0) X any_key(0); X} X X Xuser_delay(ticks) Xint ticks; X{ X if (ticks <= 0 || conf_dont_sleep) { X printf(" <>"); X any_key(10000); X } else { X fl; X sleep((unsigned)ticks); X } X} X END_OF_FILE if test 27619 -ne `wc -c <'term.c'`; then echo shar: \"'term.c'\" unpacked with wrong size! fi # end of 'term.c' fi echo shar: End of archive 1 \(of 22\). cp /dev/null ark1isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 22 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still must unpack the following archives: echo " " ${MISSING} fi exit 0 exit 0 # Just in case...