Subject: v24i082: Qterm5.0 -- Query terminal for its type, Part01/02 Newsgroups: comp.sources.unix Approved: rsalz@uunet.UU.NET X-Checksum-Snefru: 23817b14 f66cb394 106806de f16726fa Submitted-by: "Michael A. Cooper" Posting-number: Volume 24, Issue 82 Archive-name: qterm5.0/part01 Qterm is a program that queries terminals to find out what kind of terminal is responding. It is useful to automagically define your terminal type. It prints the name of the terminal (compatible, hopefully, with a termcap/terminfo name) such as "vt100" to standard output. See the manual for details. The major changes in these version of qterm is a re-write of command line parsing and the options qterm accepts. I've written a new, "generic" command line parsing package called "options" which is included as part of this distribution of qterm. (See the options.3 man page for details on programming with the options package.) Qterm now has a totally new set of (hopefully) clear and concise options. The old command line options are still accepted if qterm is compiled with OPT_COMPAT defined (see Makefile). WARNING: Some of the old options conflict with the new options. i.e. If OPT_COMPAT is defined, "qterm -file foo" does not do what you think it will. This is parsed as "qterm -f ile foo". Qterm was written under 4.[23] BSD and will probably run without modification on other Berkeley Unix systems. This version has also been tested under UTS 2.1 which is a System V.3 derivative. It was compiled with "USG5" defined and setting $(LIBS) to "-lPW". (See Makefile for more info). It should work on other System V platforms. #! /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 options.3 options.c options.h qterm.c # Wrapped by rsalz@litchi.bbn.com on Fri Mar 22 12:25:37 1991 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 2)."' if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(2200 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' X X Q T E R M - Q U E R Y T E R M I N A L X X Version 5.0 X XQterm is a program that queries terminals to find out what kind of Xterminal is responding. It is useful to automagically define your Xterminal type. It prints the name of the terminal (compatible, Xhopefully, with a termcap/terminfo name) such as "vt100" to standard Xoutput. See the manual for details. X XThe major changes in these version of qterm is a re-write of command Xline parsing and the options qterm accepts. I've written a new, X"generic" command line parsing package called "options" which is Xincluded as part of this distribution of qterm. (See the options.3 Xman page for details on programming with the options package.) Qterm Xnow has a totally new set of (hopefully) clear and concise options. XThe old command line options are still accepted if qterm is compiled Xwith OPT_COMPAT defined (see Makefile). WARNING: Some of the old Xoptions conflict with the new options. i.e. If OPT_COMPAT is Xdefined, "qterm -file foo" does not do what you think it will. This Xis parsed as "qterm -f ile foo". X XQterm was written under 4.[23] BSD and will probably run without Xmodification on other Berkeley Unix systems. This version has also Xbeen tested under UTS 2.1 which is a System V.3 derivative. It was Xcompiled with "USG5" defined and setting $(LIBS) to "-lPW". (See XMakefile for more info). It should work on other System V platforms. X XIt has been running at one point or another here at USC on: X X Sun-3, Sun-4, Sun386i's under SunOS 3.X, 4.0, 4.0.3, 4.1, 4.1.1 X Alliant's under Concentrix 3.X, 4.X, 5.X X IBM RT's under ACIS 4.2 and 4.3 X DEC VAX & DEC RISC under Ultrix 2.2, 3.1, 4.0, 4.1 X 4.[23]BSD (VAX) X 4.3BSD [MORE/bsd] (HP) X Amdahl UTS (System V.3) 2.1 X XIf you have Internet access, the latest and greatest version of qterm Xis available from "usc.edu" via anonymous ftp in the file X/pub/qterm.shar. I update this file whenever there are any changes, Xso it's bound to be newer than a copy from any other source. X X XMichael A. Cooper, University Computing Services, U of Southern California X INTERNET: mcooper@usc.edu PHONE: 213-740-2957 X UUCP: ...!uunet!usc!mcooper BITNET: mcooper@gamera END_OF_FILE if test 2200 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'options.3' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'options.3'\" else echo shar: Extracting \"'options.3'\" \(7383 characters\) sed "s/^X//" >'options.3' <<'END_OF_FILE' X.\" X.\" Copyright (c) 1990 Michael A. Cooper. X.\" This software may be freely distributed provided it is not sold for X.\" profit and the author is credited appropriately. X.\" X.\" $Header: /src/common/usc/lib/libgen/RCS/options.3,v 1.4 1991/02/22 02:30:06 mcooper Exp $ X.\" X.TH PARSEOPTIONS 3 "30 October 1990" X.ds ]W USC-UCS X.SH NAME XParseOptions, UsageOptions, HelpOptions, Num_Opts \- Parse command line options X.SH SYNOPSIS X.LP X.nf X.ft B X#include "/usr/usc/include/options.h" X.ft X.fi X.LP X.nf X.ft B Xint ParseOptions(options, num_options, argc, argv) XOptionDescRec *options; Xint num_options; Xint argc; Xchar **argv; X.ft X.fi X.LP X.nf X.ft B Xvoid UsageOptions(options, num_options, badoption) XOptionDescRec *options; Xint num_options; Xchar *badoption; X.ft X.fi X.LP X.nf X.ft B Xvoid HelpOptions(options, num_options, message) XOptionDescRec *options; Xint num_options; Xchar **message; X.ft X.fi X.LP X.nf X.ft B Xint Num_Opts(options) XOptionDescRec *options; X.ft X.fi X.LP X.nf X.ft B Xextern char *OptionChars; Xextern char *ProgramName; X.ft X.fi X.SH DESCRIPTION X.LP X.BR ParseOptions(\|) Xparses a given set of options found in X.B argv. XThe X.B argc Xparameter is the count of the number of string pointers Xin X.B argv. XBoth X.B argc Xand X.B argv Xare typically passed directly from a X.B main(\|) Xfunction. XThe X.B argv Xparameter should contain an array of strings that Xneed to be parsed. X.B ParseOptions(\|) Xreturns the number of entries in X.B argv Xthat were successfully parsed or -1 upon error. X.LP XThe X.B options Xstructure should contain a valid description list of options. XThe type X.B OptionDescRec Xis defined as the following in the X.B "options.h" Xheader file: X.RS X.LP X.nf X.ft B Xtypedef struct { X char *option; /* Option string in argv */ X int flags; /* Flag bits */ X int (*cvtarg)(); /* Function to convert argument */ X caddr_t valp; /* Variable to set */ X caddr_t value; /* Default value to provide */ X char *usage; /* Usage message */ X char *desc; /* Description message */ X} OptionDescRec, *OptionDescList; X.ft R X.fi X.RE X.LP XThe order of X.I options Xis important because Xthe first partial match found in X.I options Xis used. XThis allows abbreviations (except if the option is a X.I StickArg X[see below]). XFor instance, a user may specify only "\-n" for "\-number" provided Xthat "\-n" is unique to X.I options Xor that "\-number" is placed before any other "\-n*" options in X.I options. X.LP XThe X.I option Xmember of X.B OptionDescRec Xis the string name of the option. XThis is typically something like X.RS X.ft B X.nf X.sp X"\-c" X"+c" X"\-file" X.fi X.sp X.ft X.RE XThe first character of X.I option Xis special. It must be one of the characters know to be the Xstart of an option. XThe default list of starting option characters is "\-+". XThis indicates that an option can start with either a "\-" or Xa "+". This list of characters may be changed by setting Xthe variable X.B OptionChars Xto point to a string of custom starting option characters. X.LP XThe X.I flags Xmember is used to set bits to describe how an option Xis to be interpreted. XValid flags are defined in the X.I "options.h" Xheader file: X.RS X.IP NoArg XNo argument for this option. XUse the value in X.I OptionDescRec.value Xto set the value in the X.I valp Xmember of X.B OptionDescRec. X.IP IsArg XValue is the option string itself. X.IP SepArg XValue is in next argument in argv. X.IP StickyArg XValue is the characters immediately following Xthe option. X.IP SkipArg XIgnore this option and the next argument in argv. X.IP SkipLine XIgnore this option and the rest of argv. X.IP SkipNArgs XIgnore this option and the next X.I OptionDescRes.value Xarguments in argv. X.IP ArgHidden XDon't show this option in usage or help messages. X.RE X.LP XThe next member of X.B OptionDescRec Xis X.I cvtarg. XThis should be a pointer to a function that knows how to Xconvert the given argument into the correct type. XThe predefined functions are as follows: X.RS X.IP OptBool XConverts a boolean. X.IP OptInt XConverts an integer. X.IP OptShort XConverts a short. X.IP OptLong XConverts a long. X.IP OptStr XConverts a string. X.RE X.LP XThe X.I valp Xmember should be a pointer Xto the variable that needs to be set. X.I valp Xshould accept whatever type X.I cvtarg Xis expected to return. X.LP XThe X.I value Xmember should contain a default value to Xbe used if no value is given for an option or Xthis type of option does not require an argument X(according to the X.I flags Xbits). XIf X.I value Xis X.B NULL Xthen an argument for this option Xis optional. X.LP X.I usage Xis used to build usage and help messages. XIt should be a string containing a description of any arguments Xthat may be used for this option. XThe option string itself should not be a part of X.I usage. XThe X.B UsageOptions(\|) Xand X.B HelpOptions(\|) Xfunctions combine the X.I option Xfield with X.I usage Xand interpret the X.I flags Xbits to build a usage string. XIf this field is X.B NULL, Xthen just the X.I option Xfield itself is used for usage and help messages. X.LP XThe X.I desc Xmember is used to build a help message for this option. XThis should be a string containing a brief description on what this Xoption does. X.LP XThe X.B num_options Xparameter should be the number of X.B OptionDescRec's Xfound in X.B options. XThe function X.BR Num_Opts(\|) Xwill return the number of X.B OptionDescRec's. X.LP XThe X.B UsageOptions(\|) Xfunction Xprints a usage message. XIf X.I badoption Xis not X.B NULL, Xthen an initial message is displayed indicating that X.I badoption Xis not a valid option. X.LP XThe X.B HelpOptions(\|) Xfunction Xprints a nicely formatted message describing all options. XIf X.I message Xis not X.B NULL Xit is taken to be a message that is displayed in the output of Xa "\-help" option. X.SH EXAMPLE X.LP XHere is an example program: X.nf X.sp X.ft B X#include "options.h" X Xchar *filename = NULL; Xint number = \-1; Xint foo = \-1; Xint I = \-1; Xlong L = \-1; Xshort S = \-1; X XOptionDescRec opts[] = { X {"\-foo", NoArg, OptBool, (caddr_t) &foo, "0", X (char *)NULL, "Disable foo bar"}, X {"+foo", NoArg, OptBool, (caddr_t) &foo, "1", X (char *)NULL, "Enable foo bar"}, X {"\-I", StickyArg, OptInt, (caddr_t) &I, (caddr_t) NULL, X (char *)NULL, "Set value of I"}, X {"\-L", StickyArg, OptLong, (caddr_t) &L, (caddr_t) NULL, X (char *)NULL, "Set value of L"}, X {"\-S", SepArg, OptShort, (caddr_t) &S, (caddr_t) NULL, X (char *)NULL, "Set value of S"}, X {"\-C", StickyArg, OptStr, (caddr_t) &filename, (caddr_t) NULL, X (char *)NULL, "Alternate file to use"}, X {"\-number", SepArg, OptInt, (caddr_t) &number, "66", X "interval", NULL}, X {"\-file", SepArg, OptStr, (caddr_t) &filename, (caddr_t) NULL, X "filename", "Specify alternate file to use"}, X}; X Xmain(argc, argv) X int argc; X char **argv; X{ X int c; X X c = ParseOptions(opts, Num_Opts(opts), argc, argv); X printf("Count = %d of %d\n", c, argc); X} X.ft X.fi X.SH "RETURN VALUES" X.B ParseOptions(\|) Xreturns the number of arguments parsed or -1 upon error. X.SH NOTES X.LP XThe X.I \-help Xoption is automatically built into X.B ParseOptions(\|). X.LP XAll error messages are sent to X.B stderr. X.LP XAn option may be both X.I StickyArg Xand X.I SepArg. XIf both are set for one option, preference is given to X.I SepArg Xparsing. XAlso, no appreviations are allowed. X.SH AUTHOR XMichael A. Cooper, X.br XUniversity Computing Services, X.br XUniversity of Southern California. END_OF_FILE if test 7383 -ne `wc -c <'options.3'`; then echo shar: \"'options.3'\" unpacked with wrong size! fi # end of 'options.3' fi if test -f 'options.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'options.c'\" else echo shar: Extracting \"'options.c'\" \(10901 characters\) sed "s/^X//" >'options.c' <<'END_OF_FILE' X/* X * Copyright (c) 1990 Michael A. Cooper. X * This software may be freely distributed provided it is not sold for X * profit and the author is credited appropriately. X */ X X#ifndef lint Xstatic char *RCSid = "$Header: /am/sol/src/common/usc/lib/libgen/RCS/options.c,v 1.13 90/12/15 18:13:28 mcooper Exp $"; X#endif X X/* X * $Log: options.c,v $ X * Revision 1.13 90/12/15 18:13:28 mcooper X * Add copywrite notice. X * X * Revision 1.12 90/12/15 17:51:46 mcooper X * Add #ifdef HAS_VARARGS around include for . X * X * Revision 1.11 90/11/13 16:39:28 mcooper X * Add #ifdef HAS_VARARGS for systems without X * varargs. X * X * Revision 1.10 90/11/13 15:28:01 mcooper X * - Add OptBool cvtarg routine. X * - Print default values in HelpOptions() X * when appropriate. X * X * Revision 1.9 90/11/13 15:19:00 mcooper X * Added supported for options being both X * SepArg and StickyArg. X * X * Revision 1.8 90/10/30 21:02:31 mcooper X * Need to exit() if -help is specified. X * X * Revision 1.7 90/10/30 20:24:33 mcooper X * Fixed bug in UsageString(). X * X * Revision 1.6 90/10/30 19:53:05 mcooper X * Cleaned up some NeXT cc and lint stuff. X * X * Revision 1.5 90/10/30 19:45:31 mcooper X * Remove unneeded paramter to HelpOptions(). X * X * Revision 1.4 90/10/29 14:47:42 mcooper X * Added real function UsageString() to X * handle formating usage option strings. X * X * Revision 1.3 90/10/29 14:17:00 mcooper X * Allow options to be abbreviated X * (for all non StickArg options). X * X * Revision 1.2 90/10/26 15:56:11 mcooper X * - Fix bug in SepArg code that ate arguments. X * - Cleanup help message. X * - Add ArgHidden code. X * X * Revision 1.1 90/10/26 14:42:51 mcooper X * Initial revision X * X */ X X/* X * Functions to parse options. X */ X X#include "options.h" X#ifdef HAS_VARARGS X#include X#endif X Xchar *OptionChars = "-+"; /* Default option switching characters */ Xchar *ProgramName = NULL; /* Name of this program */ Xchar *UsageString(); Xstatic int isopt(); Xstatic int suppress_help_msg = 0; Xchar *strcat(); X X/* X * ParseOptions - Parse options found in argv using "options". X * Returns the number of options parsed if there X * were no errors. Returns -1 if an error occurs. X */ Xint ParseOptions(options, num_options, argc, argv) X OptionDescRec *options; X int num_options; X int argc; X char **argv; X{ X OptionDescRec *opt; X register int x; X char *p; X X if (ProgramName == NULL) X ProgramName = argv[0]; X X#ifdef OPTION_DEBUG X (void) printf("Option list is:\n"); X for (x = 0; x < num_options; ++x) { X opt = &options[x]; X (void) printf("%s\n", opt->option); X } X X (void) printf("Arguments (%d):", argc); X for (x = 0; x < argc; ++x) { X (void) printf(" %s", argv[x]); X } X (void) printf("\n"); X#endif /* OPTION_DEBUG */ X X for (x = 1; x < argc; ++x) { X if (strcmp(HELPSTR, argv[x]) == 0) { X HelpOptions(options, num_options, (char **)NULL); X exit(0); X } X X opt = FindOption(options, num_options, argv[x]); X if (opt == NULL) { X if (isopt(argv[x])) { /* this was suppose to be an option */ X UsageOptions(options, num_options, argv[x]); X return(-1); X } else { /* must be end of options */ X break; X } X } X X if (opt->flags & NoArg) { X if (!(*opt->cvtarg)(opt, opt->value, FALSE)) { X UsageOptions(options, num_options, opt->option); X return(-1); X } X } else if (opt->flags & IsArg) { X if (!(*opt->cvtarg)(opt, opt->option, FALSE)) { X UsageOptions(options, num_options, opt->option); X return(-1); X } X } else if ((opt->flags & StickyArg) && (opt->flags & SepArg)) { X p = (char *) &argv[x][strlen(opt->option)]; X if (!*p) { /*** SepArg ***/ X if (x + 1 >= argc || isopt(argv[x+1])) { X if (opt->value == (caddr_t) NULL) { X UserError("%s: Option requires an argument.", argv[x]); X UsageOptions(options, num_options, opt->option); X return(-1); X } X p = opt->value; X } else { X p = argv[++x]; X } X } X if (!(*opt->cvtarg)(opt, p, TRUE)) { X UsageOptions(options, num_options, opt->option); X return(-1); X } X } else if (opt->flags & StickyArg) { X p = (char *) &argv[x][strlen(opt->option)]; X if (!*p) { X if (opt->value == (caddr_t) NULL) { X UserError("%s: Option requires an argument.", argv[x]); X UsageOptions(options, num_options, opt->option); X return(-1); X } else { X p = opt->value; X } X } X if (!(*opt->cvtarg)(opt, p, TRUE)) { X UsageOptions(options, num_options, opt->option); X return(-1); X } X } else if (opt->flags & SepArg) { X if (x + 1 >= argc || isopt(argv[x+1])) { X if (opt->value == (caddr_t) NULL) { X UserError("%s: Option requires an argument.", argv[x]); X UsageOptions(options, num_options, opt->option); X return(-1); X } else { X p = opt->value; X } X } else { X p = argv[++x]; X } X if (!(*opt->cvtarg)(opt, p, TRUE)) { X UsageOptions(options, num_options, opt->option); X return(-1); X } X } else if (opt->flags & SkipArg) { X x += 2; X } else if (opt->flags & SkipLine) { X return(x); X } else if (opt->flags & SkipNArgs) { X if (opt->value) { X x += atoi(opt->value); X } else { X UserError("Internal Error: No 'value' set for SkipNArgs."); X return(-1); X } X } else { X UserError("Internal Error: Unknown argument type for option '%s'.", X opt->option); X return(-1); X } X } X X return(x); X} X X/* X * FindOption - Find "option" in "options". Returns NULL if not found. X */ XOptionDescRec *FindOption(options, num_options, option) X OptionDescRec *options; X int num_options; X char *option; X{ X OptionDescRec *opt; X register int x; X X for (x = 0; x < num_options; ++x) { X opt = &options[x]; X if (opt->flags & StickyArg) { X if (strncmp(option, opt->option, strlen(opt->option)) == 0) X return(opt); X } else { X if (strncmp(option, opt->option, strlen(option)) == 0) X return(opt); X } X } X X return(NULL); X} X X/* X * isopt - Is "str" an option string? Compare first char of str against X * list of option switch characters. Returns TRUE if it is an option. X */ Xstatic int isopt(str) X char *str; X{ X register char *p; X X for (p = OptionChars; p && *p; *++p) { X if (*str == *p) { X return(TRUE); X } X } X X return(FALSE); X} X X/* X * UsageOptions - Print a usage message based on "options". X */ Xvoid UsageOptions(options, num_opts, badOption) X OptionDescRec *options; X int num_opts; X char *badOption; X{ X OptionDescRec *opt; X char *optstr; X register int x; X int col, len; X X if (badOption) X (void) fprintf (stderr, "%s: bad command line option \"%s\"\r\n\n", X ProgramName, badOption); X X (void) fprintf (stderr, "usage: %s", ProgramName); X col = 8 + strlen(ProgramName); X for (x = 0; x < num_opts; x++) { X opt = &options[x]; X if (opt->flags & ArgHidden) X continue; X optstr = UsageString(opt); X len = strlen(optstr) + 3; /* space [ string ] */ X if (col + len > 79) { X (void) fprintf (stderr, "\r\n "); /* 3 spaces */ X col = 3; X } X (void) fprintf (stderr, " [%s]", optstr); X col += len; X } X X if (suppress_help_msg) X (void) fprintf(stderr, "\r\n\n"); X else X (void) fprintf(stderr, X "\r\n\nType \"%s %s\" for a full description.\r\n\n", X ProgramName, HELPSTR); X} X X/* X * HelpOptions - Print a nice help/usage message based on options. X */ Xvoid HelpOptions(options, num_opts, message) X OptionDescRec *options; X int num_opts; X char **message; X{ X OptionDescRec *opt; X register int x; X char **cpp; X X suppress_help_msg = 1; X UsageOptions(options, num_opts, (char *)NULL); X suppress_help_msg = 0; X X (void) fprintf (stderr, "where options include:\n"); X for (x = 0; x < num_opts; x++) { X opt = &options[x]; X if (opt->flags & ArgHidden) X continue; X (void) fprintf (stderr, " %-28s %s\n", UsageString(opt), X (opt->desc) ? opt->desc : ""); X if (opt->value && opt->cvtarg != OptBool) X (void) fprintf (stderr, " %-28s [ Default value is %s ]\n", X "", opt->value); X } X X if (message) { X (void) putc ('\n', stderr); X for (cpp = message; *cpp; cpp++) { X (void) fputs (*cpp, stderr); X (void) putc ('\n', stderr); X } X (void) putc ('\n', stderr); X } X} X X/* X * UserError - Print a user error. X */ X#ifdef HAS_VARARGS Xvoid UserError(va_alist) X va_dcl X{ X va_list args; X char *fmt; X X va_start(args); X if (ProgramName) X (void) fprintf(stderr, "%s: ", ProgramName); X fmt = (char *) va_arg(args, char *); X (void) vfprintf(stderr, fmt, args); X va_end(args); X (void) fprintf(stderr, "\n"); X} X#else Xvoid UserError(fmt, a1, a2, a3, a4, a5, a6) X char *fmt; X{ X if (ProgramName) X (void) fprintf(stderr, "%s: ", ProgramName); X (void) fprintf(stderr, fmt, a1, a2, a3, a4, a5, a6); X (void) fprintf(stderr, "\n"); X} X#endif X XOptBool(opt, value, docopy) X OptionDescRec *opt; X caddr_t value; X int docopy; /*ARGSUSED*/ X{ X char *vpp; X X *(int *) opt->valp = (int) strtol(value, &vpp, 0); X if (*vpp) { X UserError("Invalid integer argument for '%s'.", opt->option); X return(FALSE); X } else { X return(TRUE); X } X} X XOptInt(opt, value, docopy) X OptionDescRec *opt; X caddr_t value; X int docopy; /*ARGSUSED*/ X{ X char *vpp; X X *(int *) opt->valp = (int) strtol(value, &vpp, 0); X if (*vpp) { X UserError("Invalid integer argument for '%s'.", opt->option); X return(FALSE); X } else { X return(TRUE); X } X} X XOptShort(opt, value, docopy) X OptionDescRec *opt; X caddr_t value; X int docopy; /*ARGSUSED*/ X{ X char *vpp; X X *(short *) opt->valp = (short) strtol(value, &vpp, 0); X if (*vpp) { X UserError("Invalid integer argument for '%s'.", opt->option); X return(FALSE); X } else { X return(TRUE); X } X} X XOptLong(opt, value, docopy) X OptionDescRec *opt; X caddr_t value; X int docopy; /*ARGSUSED*/ X{ X char *vpp; X X *(long *) opt->valp = (long) strtol(value, &vpp, 0); X if (*vpp) { X UserError("Invalid integer argument for '%s'.", opt->option); X return(FALSE); X } else { X return(TRUE); X } X} X XOptStr(opt, value, docopy) X OptionDescRec *opt; X caddr_t value; X int docopy; X{ X char *p; X X if (docopy) { X if ((p = (char *) malloc((unsigned)strlen(value)+1)) == NULL) { X UserError("Cannot malloc memory: %s", SYSERR); X return(FALSE); X } X (void) strcpy(p, value); X } else { X p = value; X } X X *(char **) opt->valp = p; X X return(TRUE); X} X Xstatic char *UsageString(opt) X OptionDescRec *opt; X{ X static char buf[BUFSIZ], buf2[BUFSIZ]; X X (void) sprintf(buf, opt->option); X (void) strcpy(buf2, ""); X if (opt->usage) { X (void) sprintf(buf2, "%s%s%s%s", X ((opt->flags & StickyArg) && X !((opt->flags & StickyArg) && (opt->flags & SepArg))) X ? "" : " ", X (opt->value) ? "[" : "", X opt->usage, X (opt->value) ? "]" : "" X ); X } X (void) strcat(buf, buf2); X X return(buf); X} END_OF_FILE if test 10901 -ne `wc -c <'options.c'`; then echo shar: \"'options.c'\" unpacked with wrong size! fi # end of 'options.c' fi if test -f 'options.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'options.h'\" else echo shar: Extracting \"'options.h'\" \(2592 characters\) sed "s/^X//" >'options.h' <<'END_OF_FILE' X/* X * Copyright (c) 1990 Michael A. Cooper. X * This software may be freely distributed provided it is not sold for X * profit and the author is credited appropriately. X */ X X/* X * $Header: /am/sol/src/common/usc/lib/libgen/RCS/options.h,v 1.7 90/12/15 18:13:30 mcooper Exp $ X * X * $Log: options.h,v $ X * Revision 1.7 90/12/15 18:13:30 mcooper X * Add copywrite notice. X * X * Revision 1.6 90/11/13 15:28:39 mcooper X * Add OptBool cvtarg routine. X * X * Revision 1.5 90/10/29 19:34:03 mcooper X * Fixed comment for NoArg. X * X * Revision 1.4 90/10/29 18:48:43 mcooper X * Cleanup some comments. X * X * Revision 1.3 90/10/29 14:47:29 mcooper X * UsageString is now a real function. X * X * Revision 1.2 90/10/26 15:55:44 mcooper X * Add defines for "__" and ArgHidden. X * X * Revision 1.1 90/10/26 14:42:53 mcooper X * Initial revision X * X */ X X X#include X#include X#include X X#define Num_Opts(o) (sizeof(o)/sizeof(OptionDescRec)) X#define HELPSTR "-help" X#define __ (caddr_t) X X#ifndef SYSERR X#define SYSERR sys_errlist[errno] X#endif X#ifndef TRUE X#define TRUE 1 X#endif X#ifndef FALSE X#define FALSE 0 X#endif X X/* X * Values for OptionDescRec.flags. X */ X#define NoArg 0x001 /* No argument for this option. Use X OptionDescRec.value. */ X#define IsArg 0x002 /* Value is the option string itself */ X#define SepArg 0x004 /* Value is in next argument in argv */ X#define StickyArg 0x008 /* Value is characters immediately following X option */ X#define SkipArg 0x010 /* Ignore this option and the next argument in X argv */ X#define SkipLine 0x020 /* Ignore this option and the rest of argv */ X#define SkipNArgs 0x040 /* Ignore this option and the next X OptionDescRes.value arguments in argv */ X#define ArgHidden 0x080 /* Don't show in usage or help messages */ X X/* X * Option description record. X */ Xtypedef struct { X char *option; /* Option string in argv */ X int flags; /* Flag bits */ X int (*cvtarg)(); /* Function to convert argument */ X caddr_t valp; /* Variable to set */ X caddr_t value; /* Default value to provide */ X char *usage; /* Usage message */ X char *desc; /* Description message */ X} OptionDescRec, *OptionDescList; X Xvoid UsageOptions(); Xvoid HelpOptions(); Xvoid UserError(); Xint ParseOptions(); XOptionDescRec *FindOption(); X Xint OptBool(); Xint OptInt(); Xint OptLong(); Xint OptShort(); Xint OptStr(); X Xextern char *OptionChars; Xextern int errno; Xextern char *sys_errlist[]; Xextern long strtol(); Xextern char *malloc(); Xextern char *strcpy(); END_OF_FILE if test 2592 -ne `wc -c <'options.h'`; then echo shar: \"'options.h'\" unpacked with wrong size! fi # end of 'options.h' fi if test -f 'qterm.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'qterm.c'\" else echo shar: Extracting \"'qterm.c'\" \(24777 characters\) sed "s/^X//" >'qterm.c' <<'END_OF_FILE' X#ifndef lint Xstatic char *RCSid = "$Header: /src/common/usc/bin/qterm/RCS/qterm.c,v 5.4 1991/03/21 02:09:40 mcooper Exp $"; X#endif X X/* X * Copyright (c) 1990 Michael A. Cooper. X * This software may be freely distributed provided it is not sold for X * profit and the author is credited appropriately. X */ X X/* X *------------------------------------------------------------------ X * X * $Source: /src/common/usc/bin/qterm/RCS/qterm.c,v $ X * $Revision: 5.4 $ X * $Date: 1991/03/21 02:09:40 $ X * $State: Exp $ X * $Author: mcooper $ X * $Locker: $ X * X *------------------------------------------------------------------ X * X * Michael A. Cooper X * Research and Development Group X * University Computing Services X * University of Southern California X * (mcooper@usc.edu) X * X *------------------------------------------------------------------ X * X * $Log: qterm.c,v $ X * Revision 5.4 1991/03/21 02:09:40 mcooper X * Fix memory buffer problem with some C X * compilers. (tp@vtold.vtol.fi) X * X * Revision 5.3 1991/03/16 05:36:30 mcooper X * Fix casting of (char) NULL problem. X * X * Revision 5.2 1991/03/12 00:46:24 mcooper X * Change CMASK to CHAR_CMASK to avoid conflict X * under AIX 3.1. X * X * Revision 5.1 1991/02/20 02:23:33 mcooper X * Cleanup #ifdef USG5 as part of port X * to UTS 2.1 (System V.3). X * X * Revision 5.0 1990/12/15 18:30:41 mcooper X * Version 5. X * X * Revision 4.13 90/12/15 18:14:23 mcooper X * Add copywrite. X * X * Revision 4.12 90/11/13 16:00:03 mcooper X * Convert OptInt's to OptBool's where needed. X * X * Revision 4.11 90/11/13 15:38:28 mcooper X * Make OLD_SepArg include both X * SepArg and StickyArg. X * X * Revision 4.10 90/11/08 15:41:08 mcooper X * Make sure qt_fullname is not 0 length. X * X * Revision 4.9 90/11/08 13:02:06 mcooper X * Fix bug that closes the tty when an error X * occurs during command line parsing. X * X * Revision 4.8 90/11/06 13:19:40 mcooper X * Changed command line options to new X * longer names. X * X * Revision 4.7 90/11/05 17:09:30 mcooper X * Update option help messages and option names X * to be more mnemonic. X * X * Revision 4.6 90/11/05 16:44:35 mcooper X * - Converted to use new ParseOptions() for X * command line parsing. X * - Major de-linting. X * - Convert dprintf() to use varargs (if X * HAS_VARARGS is defined). X * - Lots of misc. cleanup. X * X * Revision 4.5 89/10/20 22:50:49 mcooper X * Changed code indention to current local X * standard of 4. (This should also mess up X * everybody trying to do diff's from older versions!) X * X * Revision 4.4 89/10/20 14:03:48 mcooper X * Fixed command line parsing of "-f -q". X * X * Revision 4.3 88/06/16 19:43:46 mcooper X * - Added -T flag to wait until timeout when X * listening for response string. This solves X * problem when the first entry in a table X * doesn't have a response string with a X * common ending character to look for. X * - Added -I flag for "intense" query mode. X * - Cleaned up debugging a bit. X * X * Revision 4.2 88/06/08 15:30:53 mcooper X * Cleanup pass including removing X * extraneous debugging messages. X * X * Revision 4.1 88/04/25 13:24:38 mcooper X * Added -S option to print send and recieve X * strings as they are sent and recieved as X * suggested by David W. Sanderson X * (dws@attunix.att.com). X * X * Revision 4.0 88/03/08 19:30:59 mcooper X * Version 4. X * X * Revision 3.7 88/03/08 19:28:32 mcooper X * Major rewrite. X * X * Revision 3.6 88/03/08 15:31:35 mcooper X * General cleanup time. X * X * Revision 3.5 88/03/08 13:59:39 mcooper X * - Catch signals and fix terminal modes. X * - Don't allow alarm times of 0. X * - Support for HP-UX machines and cleaner X * listen() code from Zenon Fortuna, X * HP-UX Support, Hewlett-Packard Vienna. X * X * Revision 3.4 87/10/07 15:16:17 mcooper X * - Beautify code a bit. X * - Add -w option to set the wait time. X * X * Revision 3.3 87/08/24 19:25:32 mcooper X * The following based on code from Frank Crawford X * : X * - Use $TERM as output string when the terminal X * type is not known instead of "dumb". X * - Regular Expressions are now supported. RE are X * started with a leading `\'. X * - Octal values may now be used in send/recieve strings. X * X * Revision 3.1 87/08/03 15:21:07 mcooper X * As pointed out by Scott H. Robinson , X * the -F switch does work. Problem was that it never read X * in the ~/.qterm file. X * X * Revision 3.0 87/06/30 19:07:59 mcooper X * Release of version 3. X * X * Revision 2.4 87/04/29 19:28:35 mcooper X * In readtabfile() we now do special X * things when opening "file" fails X * depending on the bequiet flag. X * X * Revision 2.3 87/04/29 13:11:37 mcooper X * - No more "internal" table. The master X * table is read from a file (TABFILE). X * This makes ~/.qterm stuff much cleaner. X * - Error handling for qtermtab files is X * much more informative now. X * - More things I can't remember. X * X * Revision 2.2 87/03/05 21:01:28 mcooper X * Fixed system V compiler problem. X * X * Revision 2.1 87/03/01 19:43:22 mcooper X * Be more intelligent about the size of X * the default terminal table. X * X * Revision 2.0 87/03/01 19:20:00 mcooper X * General cleanup. X * X *------------------------------------------------------------------ X */ X X X/* X * qterm - Query Terminal X * X * qterm is used to query a terminal to determine the name of the terminal. X * This is done by sending a fairly universal string "\33Z" to the terminal, X * reading in a response, and comparing it against a master table of responses X * and names. The "name" printed to standard output should be one found in X * the termcap(5) database. X * X * Putting a line in your ".login" file such as: X * X * setenv TERM `qterm` X * X * or the following lines in your ".profile" file: X * X * TERM=`qterm` X * export TERM X * X * will set your terminal type automagically. X * X * If you add a terminal to the master table, please also send me a copy X * so that I may put it into my version. X * X * Michael Cooper X * Internet: mcooper@usc.edu X * UUCP: ...!rutgers!usc!mcooper X * BITNET: mcooper@gamera X */ X X#include X#include X#include X#include X#include X#include X#ifdef USG5 X# include X#else /*USG5*/ X# include X# include X#endif /*USG5*/ X#include "qterm.h" X#include "options.h" X#ifdef HAS_VARARGS X#include X#endif /*HAS_VARARGS*/ X X#ifdef USG5 Xstruct termio _ntty, _otty; X#else Xstruct sgttyb _tty; X#endif Xint _tty_ch = 2; Xchar recvbuf[SIZE]; Xchar *progname; Xchar *termfile = NULL; X Xint debug = FALSE; /* Debug mode */ Xint use_alt_str = FALSE; /* Alternate string */ Xint towait = FALSE; /* Time out wait flag */ Xint always_send = FALSE; /* Intense query mode */ Xint longname = FALSE; /* Print long terminal name */ Xint sent_chars = FALSE; /* Print strings sent from the terminal */ Xint watch_chars = FALSE; /* Watch strings as they are sent and recv. */ Xint quiet = FALSE; /* Quiet mode */ Xint do_usrtabfile = FALSE; /* Use user's own .qtermtab file */ Xint do_systabfile = TRUE; /* Use the system's qterm tab file */ Xint almwait = WAIT; /* Wait (timeout) interval */ X X/* X * Old options should not be visable in help and usage messages. X */ X#ifdef OPT_COMPAT X#define OLD_NoArg NoArg|ArgHidden X#define OLD_SepArg SepArg|StickyArg|ArgHidden X#define fFLAG "-f" X#define FFLAG "-F" X#endif X X/* X * Command line options table. X */ XOptionDescRec opts[] = { X#ifdef OPT_COMPAT X {"-a", OLD_NoArg, OptInt, (caddr_t) &use_alt_str, "1", X (char *)NULL, "Use alternate query string"}, X {"-s", OLD_NoArg, OptInt, (caddr_t) &sent_chars, "1", X (char *)NULL, "Display the characters the terminal sent"}, X {"-t", ArgHidden|OLD_NoArg, OptInt, (caddr_t) &sent_chars, "1", X (char *)NULL, "Display the characters the terminal sent"}, X {"-I", OLD_NoArg, OptInt, (caddr_t) &always_send, "1", X (char *)NULL, "Always send the terminal query string"}, X {"-T", OLD_NoArg, OptInt, (caddr_t) &towait, "1", X (char *)NULL, "Enable time out wait"}, X {"-S", OLD_NoArg, OptInt, (caddr_t) &watch_chars, "1", X (char *)NULL, "Print strings as they are sent and received"}, X {"-q", OLD_NoArg, OptInt, (caddr_t) &quiet, "1", X (char *)NULL, "Enable quite mode"}, X {"-f", OLD_SepArg, OptStr, (caddr_t) &termfile, fFLAG, X "", "Try , then ~/.qtermtab, then system tabfile"}, X {"-F", OLD_SepArg, OptStr, (caddr_t) &termfile, FFLAG, X "", "Try , then ~/.qtermtab"}, X {"-l", OLD_NoArg, OptInt, (caddr_t) &longname, "1", X (char *)NULL, "Output only the long (verbose) terminal name"}, X {"-d", OLD_NoArg, OptInt, (caddr_t) &debug, "1", X (char *)NULL, "Enable debug mode"}, X {"-w", OLD_SepArg, OptInt, (caddr_t) &almwait, __ NULL, X "", "Wait (timeout) period (in seconds)"}, X#endif /*OPT_COMPAT*/ X {"+alt", NoArg, OptBool, (caddr_t) &use_alt_str, "1", X (char *)NULL, "Use alternate query string"}, X {"-alt", NoArg, OptBool, (caddr_t) &use_alt_str, "0", X (char *)NULL, "Don't use alternate query string"}, X {"+always", NoArg, OptBool, (caddr_t) &always_send, "1", X (char *)NULL, "Always send the terminal query string"}, X {"-always", NoArg, OptBool, (caddr_t) &always_send, "0", X (char *)NULL, "Don't always send the terminal query string"}, X {"-file", SepArg, OptStr, (caddr_t) &termfile, __ NULL, X "", "Use to query terminal"}, X {"+longname",NoArg, OptBool, (caddr_t) &longname, "1", X (char *)NULL, "Output only the long (verbose) terminal name"}, X {"-longname",NoArg, OptBool, (caddr_t) &longname, "0", X (char *)NULL, "Don't output the long (verbose) terminal name"}, X {"+quiet", NoArg, OptBool, (caddr_t) &quiet, "1", X (char *)NULL, "Enable quiet mode"}, X {"-quiet", NoArg, OptBool, (caddr_t) &quiet, "0", X (char *)NULL, "Disable quiet mode"}, X {"+sent", NoArg, OptBool, (caddr_t) &sent_chars, "1", X (char *)NULL, "Display the characters the terminal sent"}, X {"-sent", NoArg, OptBool, (caddr_t) &sent_chars, "0", X (char *)NULL, "Don't display the characters the terminal sent"}, X {"+timeout",NoArg, OptBool, (caddr_t) &towait, "1", X (char *)NULL, "Enable time out wait"}, X {"-timeout",NoArg, OptBool, (caddr_t) &towait, "0", X (char *)NULL, "Disable time out wait"}, X {"+usrtab", NoArg, OptBool, (caddr_t) &do_usrtabfile, "1", X (char *)NULL, "Enable using ~/.qtermtab"}, X {"-usrtab", NoArg, OptBool, (caddr_t) &do_usrtabfile, "0", X (char *)NULL, "Disable using ~/.qtermtab"}, X {"-wait", SepArg, OptInt, (caddr_t) &almwait, __ NULL, X "", "Wait (timeout) period (in seconds)"}, X {"+watch", NoArg, OptBool, (caddr_t) &watch_chars, "1", X (char *)NULL, "Watch the characters sent and recieved"}, X {"-watch", NoArg, OptBool, (caddr_t) &watch_chars, "0", X (char *)NULL, "Don't watch the characters sent and recieved"}, X {"+systab", NoArg, OptBool, (caddr_t) &do_usrtabfile, "1", X (char *)NULL, "Enable using system qtermtab file"}, X {"-systab", NoArg, OptBool, (caddr_t) &do_systabfile, "0", X (char *)NULL, "Disable using system qtermtab file"}, X {"-debug", ArgHidden|NoArg, OptInt, (caddr_t) &debug, "1", X (char *)NULL, "Enable debug mode"}, X}; X XFILE *fopen(); Xchar *decode(); Xchar *getenv(); Xchar *malloc(); Xchar *re_comp(); Xchar *strcat(); Xchar *xmalloc(); Xint alarm(); Xint found = FALSE; Xint modes_set = FALSE; Xjmp_buf env; Xstruct termtable *compare(); Xstruct passwd *getpwuid(); Xvoid catch(); Xvoid done(); Xvoid dprintf(); Xvoid exit(); Xvoid myperror(); Xvoid mktable(); Xvoid notrecognized(); Xvoid proctab(); Xvoid wakeup(); X#ifdef USG5 Xchar *regcmp(); X#endif /* USG5 */ X Xmain(argc, argv) X int argc; X char **argv; X{ X config(argc, argv); X setmodes(); X mktable(); X proctab((struct termtable *)NULL); X resetmodes(); X X if (!found) { X notrecognized(); X } X X exit(0); X} X X/* X * Config() - Perform configuration operations. X */ Xconfig(argc, argv) X int argc; X char **argv; X{ X progname = argv[0]; X X /* X * Parse command line args X */ X if (ParseOptions(opts, Num_Opts(opts), argc, argv) < 0) { X done(1); X /*NOTREACHED*/ X } X X /* X * Check results of command line parsing and perform any X * needed post processing. X */ X X if (longname) X quiet = TRUE; X X if (almwait == 0) { X (void) fprintf(stderr, X "%s: Alarm (wait) time must be greater than 0.\n", X progname); X done(1); X /*NOTREACHED*/ X } X X#ifdef OPT_COMPAT X /* X * Kludgy stuff to be backwards compatable for command line options. X */ X if (termfile) { X if (strcmp(termfile, fFLAG) == 0) { X do_usrtabfile = TRUE; X do_systabfile = TRUE; X termfile = NULL; X } else if (strcmp(termfile, FFLAG) == 0) { X do_usrtabfile = TRUE; X do_systabfile = FALSE; X termfile = NULL; X } X } X#endif /*OPT_COMPAT*/ X X dprintf("[ %s debug mode enabled ]\n\n", progname); X} X X/* X * Set signal catches and terminal modes X */ Xsetmodes() X{ X if (!isatty(0)) { X (void) fprintf(stderr, "%s: Not a tty.\n", progname); X done(0); X /*NOTREACHED*/ X } X X /* X * Set output buffers X */ X setbuf(stdout, (char *)0); X if (debug) X setbuf(stderr, (char *)0); X X /* X * Cleanup terminal modes & such if we are killed X */ X (void) signal(SIGINT, catch); X (void) signal(SIGHUP, catch); X (void) signal(SIGTERM, catch); X X /* X * Set terminal modes X */ X#ifdef USG5 X if (ioctl(_tty_ch, TCGETA, &_otty) < 0) X#else X if (ioctl(_tty_ch, TIOCGETP, &_tty) < 0) X#endif /* USG5 */ X { X myperror("gtty"); X done(1); X /*NOTREACHED*/ X } X#ifdef USG5 X _ntty = _otty; X#endif /* USG5 */ X X if (crmode() < 0) { X myperror("crmode"); X done(1); X /*NOTREACHED*/ X } X X if (noecho() < 0) { X myperror("noecho"); X done(1); X /*NOTREACHED*/ X } X modes_set = TRUE; X} X X/* X * Reset terminal modes X */ Xresetmodes() X{ X if (modes_set) { X (void) nocrmode(); X (void) echo(); X } X} X X/* X * Print info about terminal structure t. X */ Xprinfo(t, what) X struct termtable *t; X int what; X{ X int len = 0; X int st = FALSE; X X if (t && t->qt_termname && (recvbuf[0] != (char) NULL)) { X if (debug || sent_chars) { X len = strlen(recvbuf); X (void) fprintf(stderr, "%s received %d character%s:", X progname, len, (len == 1) ? "" : "s"); X (void) fprintf(stderr, " %s\n", decode(recvbuf)); X } X X if (!quiet) { X (void) fprintf(stderr, "Terminal recognized as %s", X t->qt_termname); X if (t->qt_fullname && t->qt_fullname[0]) X (void) fprintf(stderr, " (%s)\n", t->qt_fullname); X else X (void) fprintf(stderr, "\n"); X } X X if (longname) { X if (t->qt_fullname && t->qt_fullname[0]) X (void) printf("%s\n", t->qt_fullname); X else X (void) fprintf(stderr, "%s: No full terminal name for %s.\n", X progname, t->qt_termname); X } else { X (void) printf("%s\n", t->qt_termname); X } X X found = TRUE; X done(0); X /*NOTREACHED*/ X } else { X found = FALSE; X X if (what) { X notrecognized(); X done(1); X /*NOTREACHED*/ X } X } X X return(st); X} X X/* X * compare - actually compare what we received against the table. X */ Xstruct termtable *compare(str) X char *str; X{ X#ifdef USG5 X register char *reexp; X#endif /* USG5 */ X register struct termtable *t; X char buf[BUFSIZ]; X X dprintf("compare %s\n", (str && str[0]) ? decode(str) : "nothing"); X (void) alarm((unsigned)0); X X if (strlen(str) == 0) X return(NULL); X X for (t = termtab; t != NULL; t = t->nxt) { X dprintf(" with %s ", decode(t->qt_recvstr)); X (void) sprintf(buf, "^%s$", t->qt_recvstr); X X#ifdef USG5 X if ((reexp = regcmp(buf, NULL)) == NULL) { X#else X if (re_comp((char *)buf) != NULL) { X#endif /* USG5 */ X (void) fprintf(stderr, "%s: bad regular expression: \"%s\"\n", X progname, t->qt_recvstr); X done(1); X /*NOTREACHED*/ X } X X#ifdef USG5 X if (regex(reexp, str) != NULL) { X#else X if (re_exec(str) == 1) { X#endif /* USG5 */ X found = TRUE; X dprintf("\tOK\n"); X return(t); X } X X dprintf("\tNOPE\n"); X#ifdef USG5 X (void) free(reexp); X#endif /* USG5 */ X } X found = FALSE; X X return(NULL); X} X X/* X * getch - read in a character at a time. X */ Xgetch() X{ X char c; X X (void) read(0, &c, 1); X X return(c & CHAR_MASK); X} X X/* X * decode - print str in a readable fashion X */ Xchar *decode(str) X char *str; X{ X register int len; X static char buf[BUFSIZ]; X char tmp[10]; X X if (!str) X return("(null)"); X X (void) strcpy(buf, ""); X while (*str) { X if (*str == ESC) { X (void) strcat(buf, " "); X } else if ((*str <= 33) || (*str >= 127)) { X (void) sprintf(tmp,"\\%#o ", (unsigned) *str); X (void) strcat(buf, tmp); X } else { X (void) sprintf(tmp,"%c ", *str); X (void) strcat(buf, tmp); X } X ++str; X } X X len = strlen(buf); X if (len && buf[len - 1] == ' ') { X buf[len - 1] = (char) NULL; X } X X return(buf); X} X X/* X * Make a termtab table X */ Xvoid mktable() X{ X char file[BUFSIZ]; X struct passwd *pwd; X char *home; X X dprintf("[ initilizing term table... ]\n"); X X if (termfile != NULL) { X (void) readtabfile(termfile, FALSE); X } X X if (do_usrtabfile) { X /* X * Try to read the user's own table X */ X if ((home = getenv("HOME")) == NULL) { X if ((pwd = getpwuid(getuid())) == NULL) { X (void) fprintf(stderr, X "%s: Cannot find user info for uid %d.\n", X progname, getuid()); X done(1); X /*NOTREACHED*/ X } X home = pwd->pw_dir; X } X X (void) sprintf(file, "%s/%s", home, USRFILE); X if (readtabfile(file, TRUE) < 0) { X (void) sprintf(file, "%s/%s", home, OLDUSRFILE); X (void) readtabfile(file, TRUE); X } X } X X if (do_systabfile) X (void) readtabfile(TABFILE, FALSE); X X dprintf("[ mktable done ]\n"); X} X Xint readtabfile(file, bequiet) X char *file; X int bequiet; X{ X static int line = 0; X char lbuf[4][BUFSIZ]; X char buf[BUFSIZ]; X FILE *fd; X char *p, *fixctl(); X char *errmsg = NULL; X struct termtable *t; X X if ((fd = fopen(file, "r")) == NULL) { X if (bequiet) { X dprintf("[ tab file '%s' can not read ]\n", file); X return(-1); X } X myperror(file); X done(1); X /*NOTREACHED*/ X } X X dprintf("[ Read tab file '%s' ]\n", file); X X line = 0; X while (fgets(buf, sizeof(buf), fd)) { X ++line; X X if (buf[0] == '#' || buf[0] == '\n') X continue; X X lbuf[0][0] = lbuf[1][0] = lbuf[2][0] = lbuf[3][0] = (char) NULL; X X (void) sscanf(buf, "%s%s%s\t%[^\n]", X lbuf[0], lbuf[1], lbuf[2], lbuf[3]); X X if (lbuf[0][0] == (char) NULL) X continue; X X if (lbuf[1][0] == (char) NULL) X errmsg = "receive string"; X X if (lbuf[2][0] == (char) NULL) X errmsg = "terminal name"; X X if (errmsg) { X (void) fprintf(stderr, "%s: Line %d of %s: Error parsing %s.\n", X progname, line, file, errmsg); X done(1); X /*NOTREACHED*/ X } X X t = (struct termtable *) xmalloc(sizeof(struct termtable)); X X if (use_alt_str) X p = fixctl(ALTSEND, 0); X else X p = fixctl(lbuf[0], 0); X X t->qt_sendstr = (char *) xmalloc(strlen(p)+1); X (void) strcpy(t->qt_sendstr, p); X X p = fixctl(lbuf[1], 1); X t->qt_recvstr = (char *) xmalloc(strlen(p)+1); X (void) strcpy(t->qt_recvstr, p); X X t->qt_termname = (char *) xmalloc(strlen(lbuf[2])+1); X (void) strcpy(t->qt_termname, lbuf[2]); X X t->qt_fullname = (char *) xmalloc(strlen(lbuf[3])+1); X (void) strcpy(t->qt_fullname, lbuf[3]); X X dprintf("\n Send String = %s\n", decode(t->qt_sendstr)); X dprintf("Expect String = %s\n", decode(t->qt_recvstr)); X dprintf(" Terminal = '%s'\n", t->qt_termname); X dprintf(" Full Name = '%s'\n", t->qt_fullname); X X (void) addterm(t); X } X X return(0); X} X X/* X * Add termtab (n) entry to main termtab. X */ Xint addterm(n) X struct termtable *n; X{ X register struct termtable *t; X X if (!n) X return(-1); X X n->nxt = NULL; X X if (termtab == NULL) { X termtab = n; X } else { X t = termtab; X while(t && t->nxt) X t = t->nxt; X t->nxt = n; X } X X return(0); X} X X/* X * Listen for a response. X */ Xvoid qterm_listen(q) X struct termtable *q; X{ X static int i, len; X register char c; X char end; X X (void) alarm((unsigned)0); X (void) strcpy(recvbuf, ""); X i = 0; X X len = strlen(q->qt_recvstr); X X if (len) { X end = q->qt_recvstr[len - 1]; X } else { X end = 'c'; /* Fairly standard ANSI default */ X } X X dprintf("\nlisten for %s\t [ len = %d, end = `%c' ]\n", X decode(q->qt_recvstr), len, end); X X /* X * If we don't get an initial character, bounce out X * of here and finish with done(0). X */ X if (setjmp(env)) { X if (found) { X done(0); X /*NOTREACHED*/ X } X (void) fflush(stdin); X proctab(q->nxt); X } else { X (void) signal(SIGALRM, wakeup); X (void) alarm((unsigned)almwait); X recvbuf[0] = getch(); X (void) alarm((unsigned)0); X } X X /* X * Read in remaining response. Loop until ending character X * is received or until alarm goes off. If towait is set, X * then let alarm go off. X */ X for (i = 1, c = -1; (!towait && (c != end)) || towait; ) { X if (setjmp(env)) { X recvbuf[i] = (char) NULL; X return; X } else { X (void) signal(SIGALRM, wakeup); X (void) alarm((unsigned)almwait); X c = getch(); X (void) alarm((unsigned)0); X } X recvbuf[i++] = c; X } X recvbuf[i] = (char) NULL; X X dprintf("listen done. read %d chars.\n\n", i); X} X X/* X * Print a message since we didn't recognize this terminal. X */ Xvoid notrecognized() X{ X char *envterm; X X if ((envterm = getenv("TERM")) == NULL) X envterm = "dumb"; X X if (!quiet) X (void) fprintf(stderr, X "Terminal NOT recognized - defaults to \"%s\".\n", X envterm); X X puts(envterm); X} X X/* X * Process entries in the termtable. X */ Xvoid proctab(t) X struct termtable *t; X{ X int st = FALSE; X static int firsttime = TRUE; X static struct termtable *lastt; X X dprintf("\n[ Processing entries ] \n"); X X if (firsttime) { X t = termtab; X lastt = NULL; X } X X while ((!found || do_usrtabfile) && t && t->qt_sendstr && !st) { X /* X * If this is our first time or the sendstr is the same as X * last time, don't send it again. X */ X if (always_send || firsttime || lastt == NULL || X strcmp(t->qt_sendstr, lastt->qt_sendstr) != 0) { X X if (firsttime) X firsttime = FALSE; X X if (watch_chars) X (void) printf("Send: %s\n", decode(t->qt_sendstr)); X X (void) fflush(stdin); X (void) fprintf(stderr, "%s", t->qt_sendstr); X (void) fflush(stderr); X X lastt = t; X (void) qterm_listen(t); X X if (watch_chars) X (void) printf("\tRead: %s\n", decode(recvbuf)); X } X X st = prinfo(compare(recvbuf), FALSE); X X lastt = t; X t = t->nxt; X } X X if (!found) X notrecognized(); X X done(0); X /*NOTREACHED*/ X} X Xchar *fixctl(str, rex) X char *str; X int rex; X{ X register int i; X static char buf[BUFSIZ]; X X for (i = 0; str && *str; ) { X switch (*str) { X X case '\\': X if (isdigit(*++str)) { X buf[i] = 0; X while (isdigit(*str)) X buf[i] = (char) (((int)buf[i] * 8) + X (int)*str++ - (int) '0'); X i++; X } else X buf[i++] = *str++; X continue; X X case '^': X switch (*++str) { X case '?': X buf[i++] = '\177'; X break; X default: X buf[i++] = *str & 037; X break; X } X break; X X /* Special R.E. symbols */ X case '[': X case '*': X case '.': X case '$': X case '{': X case '(': X if (rex) X buf[i++] = '\\'; X X default: X buf[i++] = *str; X } X *++str; X } X X buf[i] = (char) NULL; X X return(buf); X} X X/* X * xmalloc - Do a malloc with error checking. X */ Xchar *xmalloc(size) X int size; X{ X char *p; X X if ((p = malloc((unsigned) size)) == NULL) { X myperror("malloc"); X done(1); X /*NOTREACHED*/ X } X X return(p); X} X X#ifdef HAS_VARARGS Xvoid dprintf(va_alist) X va_dcl X{ X va_list args; X char *fmt; X X if (!debug) X return; X X va_start(args); X fmt = (char *) va_arg(args, char *); X (void) vprintf(fmt, args); X va_end(args()); X (void) fflush(stdout); X} X X#else /*HAS_VARARGS*/ X Xvoid dprintf(fmt, a1, a2, a3, a4, a5, a6) X char *fmt; X{ X if (!debug) X return; X X (void) printf(fmt, a1, a2, a3, a4, a5, a6); X (void) fflush(stdout); X} X#endif /*HAS_VARARGS*/ X X/* X * Catch kill signals and cleanup. X */ Xvoid catch() X{ X done(2); X /*NOTREACHED*/ X} X Xvoid wakeup() X{ X dprintf("wakeup called\n"); X longjmp(env, 1); X} X Xvoid myperror(msg) X char *msg; X{ X (void) fprintf(stderr, "%s: ", progname); X perror(msg); X} X X/* X * Reset terminal and exit with status s. X */ Xvoid done(s) X int s; X{ X resetmodes(); X exit(s); X} END_OF_FILE if test 24777 -ne `wc -c <'qterm.c'`; then echo shar: \"'qterm.c'\" unpacked with wrong size! fi # end of 'qterm.c' fi echo shar: End of archive 1 \(of 2\). cp /dev/null ark1isdone MISSING="" for I in 1 2 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked both archives. rm -f ark[1-9]isdone else echo You still must unpack the following archives: echo " " ${MISSING} fi exit 0 exit 0 # Just in case...