#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 8 (of 13)."
# Contents:  stevie/help.c stevie/setenv.c
# Wrapped by thor@surt on Fri Oct 16 09:43:47 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'stevie/help.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stevie/help.c'\"
else
echo shar: Extracting \"'stevie/help.c'\" \(14493 characters\)
sed "s/^X//" >'stevie/help.c' <<'END_OF_FILE'
X/* $Header: /nw/tony/src/stevie/src/RCS/help.c,v 1.9 89/08/06 09:50:09 tony Exp $
X *
X * Routine to display a command summary.
X * (Dave Tutelman note:
X *	I added the ability to page backwards and forwards through help.
X *	In order to minimize the abuse to the existing code, I used
X *	"goto"s and labeled each screen.  It's not the way I would have
X *	done help from scratch, but it's not TOO ugly.
X * )
X */
X
X#include <ctype.h>
X#include "stevie.h"
X#include "ascii.h"
X#include "keymap.h"
X
X/* Macro to show help screen 'n'.
X * If C supported label types, it'd be cleaner to do it that way. */
X#define	SHOWHELP( n )	switch(n) {		\
X			case 0: goto Screen0;   \
X			case 1: goto Screen1;	\
X			case 2: goto Screen2;	\
X			case 3: goto Screen3;	\
X			case 4: goto Screen4;	\
X			case 5: goto Screen5;	\
X			case 6: goto Screen6;	\
X			case 7: goto Screen7;	\
X			case 8: goto Screen8;   \
X			default: return (TRUE);	}
X
Xextern	char	*Version;
X
Xstatic	int	helprow;
Xstatic	int	lastscreen = 0;		/* return to help in previous screen */
X
X#ifdef	HELP
X
Xstatic	void	longline();
X
Xbool_t
Xvi_help()
X{
X	int k;
X
X	SHOWHELP( lastscreen );		/* where did we quit help last ? */
X
X/***********************************************************************
X * Zeroth Screen : Index to the help screens.
X ***********************************************************************/
X
XScreen0:
X	CLS;
X	windgoto(helprow = 0, 0);
X
Xlongline("\
X   Index to HELP Screens\n\
X   =====================\n\n");
Xlongline("\
X      0    Help index  (this screen)\n\
X      1    Positioning within file, adjusting the screen\n\
X      2    Character positioning\n\
X      3    Line positioning, marking & returning, undo & redo\n");
Xlongline("\
X      4    Insert & replace, words, sentences, paragraphs\n\
X      5    Operators, miscellaneous operations, yank & put\n\
X      6    \"Ex\" command line operations\n\
X      7    Set parameters\n\
X      8    System-specific features\n");
X
X	windgoto(0, 52);
X	longline(Version);
X
X	SHOWHELP( helpkey (0) );
X
X
X/***********************************************************************
X * First Screen:   Positioning within file, Adjusting the Screen
X ***********************************************************************/
X
XScreen1:
X	CLS;
X	windgoto(helprow = 0, 0);
X
Xlongline("\
X   Positioning within file\n\
X   =======================\n\
X      ^F             Forward screenfull\n\
X      ^B             Backward screenfull\n");
Xlongline("\
X      ^D             scroll down half screen\n\
X      ^U             scroll up half screen\n");
Xlongline("\
X      G              Goto line (end default)\n\
X      ]]             next function\n\
X      [[             previous function\n\
X      /re            next occurence of regular expression 're'\n");
Xlongline("\
X      ?re            prior occurence of regular expression 're'\n\
X      n              repeat last / or ?\n\
X      N              reverse last / or ?\n\
X      %              find matching (, ), {, }, [, or ]\n");
Xlongline("\
X\n\
X   Adjusting the screen\n\
X   ====================\n\
X      ^L             Redraw the screen\n\
X      ^E             scroll window down 1 line\n\
X      ^Y             scroll window up 1 line\n");
Xlongline("\
X      z<RETURN>      redraw, current line at top\n\
X      z-             ... at bottom\n\
X      z.             ... at center\n");
X
X	SHOWHELP( helpkey (1) );
X
X
X/***********************************************************************
X * Second Screen:   Character positioning
X ***********************************************************************/
X
XScreen2:
X	CLS;
X	windgoto(helprow = 0, 0);
X
Xlongline("\
X   Character Positioning\n\
X   =====================\n\
X      ^              first non-white\n\
X      0              beginning of line\n\
X      $              end of line\n\
X      h              backward\n");
Xlongline("\
X      l              forward\n\
X      ^H             same as h\n\
X      space          same as l\n\
X      fx             find 'x' forward\n");
Xlongline("\
X      Fx             find 'x' backward\n\
X      tx             upto 'x' forward\n\
X      Tx             upto 'x' backward\n\
X      ;              Repeat last f, F, t, or T\n");
Xlongline("\
X      ,              inverse of ;\n\
X      |              to specified column\n\
X      %              find matching (, ), {, }, [, or ]\n");
X
X	SHOWHELP( helpkey (2) );
X
X
X/***********************************************************************
X * Third Screen:   Line Positioning, Marking and Returning
X ***********************************************************************/
X
XScreen3:
X	CLS;
X	windgoto(helprow = 0, 0);
X
Xlongline("\
X    Line Positioning\n\
X    ================\n\
X    H           home window line\n\
X    L           last window line\n\
X    M           middle window line\n");
Xlongline("\
X    +           next line, at first non-white\n\
X    -           previous line, at first non-white\n\
X    CR          return, same as +\n\
X    j           next line, same column\n\
X    k           previous line, same column\n");
X
Xlongline("\
X\n\
X    Marking and Returning\n\
X    =====================\n\
X    ``          previous context\n\
X    ''          ... at first non-white in line\n");
Xlongline("\
X    mx          mark position with letter 'x'\n\
X    `x          to mark 'x'\n\
X    'x          ... at first non-white in line\n");
X
Xlongline("\n\
X    Undo  &  Redo\n\
X    =============\n\
X    u           undo last change\n\
X    U           restore current line\n\
X    .           repeat last change\n");
X
X	SHOWHELP( helpkey (3) );
X
X
X/***********************************************************************
X * Fourth Screen:   Insert & Replace,
X ***********************************************************************/
X
XScreen4:
X	CLS;
X	windgoto(helprow = 0, 0);
X
Xlongline("\
X    Insert and Replace\n\
X    ==================\n\
X    a           append after cursor\n\
X    i           insert before cursor\n\
X    A           append at end of line\n\
X    I           insert before first non-blank\n");
Xlongline("\
X    o           open line below\n\
X    O           open line above\n\
X    rx          replace single char with 'x'\n\
X    R           replace characters\n");
Xif (! P(P_TO))
Xlongline("\
X    ~           change case (upper/lower) of single char\n");
X
Xlongline("\
X\n\
X    Words, sentences, paragraphs\n\
X    ============================\n\
X    w           word forward\n\
X    b           back word\n\
X    e           end of word\n\
X    )           to next sentence\n\
X    }           to next paragraph\n");
Xlongline("\
X    (           back sentence\n\
X    {           back paragraph\n\
X    W           blank delimited word\n\
X    B           back W\n\
X    E           to end of W\n");
X
X	SHOWHELP( helpkey (4) );
X
X
X/***********************************************************************
X * Fifth Screen:   Operators, Misc. operations, Yank & Put
X ***********************************************************************/
X
XScreen5:
X	CLS;
X	windgoto(helprow = 0, 0);
X
Xlongline("\
X    Operators (double to affect lines)\n\
X    ==================================\n\
X    d           delete\n\
X    c           change\n");
Xlongline("\
X    <           left shift\n\
X    >           right shift\n\
X    y           yank to buffer\n\
X    !           filter lines (command name follows)\n");
Xif (P(P_TO))
Xlongline("\
X    ~           reverse case (upper/lower)\n");
X
Xlongline("\n\
X    Miscellaneous operations\n\
X    ========================\n\
X    C           change rest of line\n\
X    D           delete rest of line\n\
X    s           substitute chars\n");
Xlongline("\
X    S           substitute lines (not yet)\n\
X    J           join lines\n\
X    x           delete characters\n\
X    X           ... before cursor\n");
X
Xlongline("\n\
X    Yank and Put\n\
X    ============\n\
X    p           put back text\n\
X    P           put before\n\
X    Y           yank lines");
X
X	SHOWHELP( helpkey (5) );
X
X
X/***********************************************************************
X * Sixth Screen:   Command-line operations
X ***********************************************************************/
X
XScreen6:
X	CLS;
X	windgoto(helprow = 0, 0);
X
Xlongline("\
X    EX command-line operations\n\
X    ==========================\n");
Xlongline("\
X    :w          write back changes\n\
X    :wq         write and quit\n\
X    :x          write if modified, and quit\n\
X    :q          quit\n\
X    :q!         quit, discard changes\n\
X    :e name     edit file 'name'\n\
X    :e!         reedit, discard changes\n");
Xif (P(P_TG))
Xlongline("\
X    :e #        edit alternate file\n");
Xelse
Xlongline("\
X    :e #        edit alternate file (also ctrl-^)\n");
Xlongline("\
X    :w name     write file 'name'\n\
X    :n          edit next file in arglist\n\
X    :N          edit prior file in arglist\n\
X    :rew        rewind arglist\n\
X    :f          show current file and lines\n");
Xlongline("\
X    :f file     change current file name\n\
X    :g/pat/p|d  global command (print or delete only)\n\
X    :s/p1/p2/   text substitution (trailing 'g' optional)\n\
X    :ta tag     to tag file entry 'tag'\n\
X    ^]          :ta, current word is tag\n");
Xif (P(P_TG))
Xlongline("\
X    :untag      back to before last ':ta' (also ctrl-^)\n");
Xlongline("\
X    :sh         run an interactive shell\n\
X    :!cmd       execute a shell command\n\
X");
X
X	SHOWHELP( helpkey (6) );
X
X
X/***********************************************************************
X * Seventh Screen:   Set parameters
X ***********************************************************************/
X
XScreen7:
X	CLS;
X	windgoto(helprow = 0, 0);
X
Xlongline("\
X    Set Parameters\n\
X    ==============\n");
Xlongline("\
X    :set param-name[=param-value]   to set\n\
X    :set sm, :set nosm, :set co=23  examples\n\
X    :set all    display all values\n\
X    :set        display non-default values\n\n");
Xlongline("Abbrev, name, and current value:\n");
Xhparm(P_AI); hparm(P_SM); longline("\n");
Xhparm(P_BK); hparm(P_CO); longline("\n");
Xhparm(P_TS); hparm(P_MO); longline("\n");
Xhparm(P_IC); hparm(P_ML); longline("\n");
Xhparm(P_TG); hparm(P_TO); longline("\n");
Xhparm(P_EB); hparm(P_VB); longline("\n");
Xhparm(P_LI); hparm(P_NU); longline("\n");
Xhparm(P_SS); longline(" (# of lines for ^D, ^U)\n");
Xhparm(P_LS); longline(" (show tabs, newlines graphically)\n");
Xhparm(P_RP); longline(" (min # of lines to report on oper)\n");
Xhparm(P_WS); longline(" (search wraps around end of file)\n");
Xhparm(P_CR); longline(" (write newline to file as CR-LF)\n");
X
X	SHOWHELP( helpkey (7) );
X
X
X/***********************************************************************
X * Eighth Screen:   System-Specific Features for DOS and OS/2
X ***********************************************************************/
X
XScreen8:
X	CLS;
X	windgoto(helprow = 0, 0);
X
Xlongline("\
X    MSDOS & OS/2 Special Keys\n\
X    =========================\n");
Xlongline("\
X    The cursor keypad does pretty much what you'd expect,\n");
Xlongline("\
X    as long as you're not in text entry mode:\n\
X\n\
X    Home, End, PgUp, PgDn, and the arrow keys navigate.\n\
X    Insert    enter text before cursor.\n\
X    Delete    delete character at the cursor.\n\n");
X
Xlongline("\
X    Function Keys\n\
X    =============\n\
X    F1      Help\n\
X    F2      Next file (:n)             Shift-F2  discard changes (:n!)\n\
X    F3      Previous file (:N)         Shift-F3  discard changes (:N!)\n");
Xlongline("\
X    F4      Alternate file (:e #)      Shift-F4  discard changes (:e! #)\n\
X    F5      Rewind file list (:rew)    Shift-F5  discard changes (:rew!)\n\
X    F6      Next function (]])         Shift-F6  Prev. function ([[)\n\
X    F8      Global subst. (:1,$s/)\n\
X    F10     Save & quit (:x)           Shift-F10 discard changes (:q!)");
X
X	SHOWHELP( helpkey (8) );
X
X}
X
X
X/*	longline (p)
X *	Put the string p into the buffer, expanding newlines.
X */
Xstatic void
Xlongline(p)
Xchar	*p;
X{
X	register char	*s;
X
X	for ( s = p; *s ;s++ ) {
X		if ( *s == '\n' )
X			windgoto(++helprow, 0);
X		else
X			outchar(*s);
X	}
X}
X
X/*	hparm (n)
X *	Put the help info for param #n into the buffer.
X */
Xhparm (p)
X  int p;
X{
X	char	buf[85];   /* was 25, too small(!), so increased to 85 */
X	char	*bp;
X
X	sprintf(buf, "     %6s  %-10s  ",
X			params[p].shortname, params[p].fullname);
X	bp = buf + strlen (buf);
X	if (params[p].flags & P_NUM)	/* numeric param */
X		sprintf(bp, "%-3d", params[p].value);
X	else {				/* Boolean param */
X		if (params[p].value)
X			strcpy (bp, "yes");
X		else
X			strcpy (bp, "no ");
X	}
X	longline (buf);
X}
X
X/* Get keystroke and return instructions on what to do next.
X * Argument is current help screen.
X * Return value is target help screen, or -1 to quit help.
X */
X
X#ifdef DOS
X#  define	NSCREEN	8
X#else
X#ifdef OS2
X#  define	NSCREEN 8
X#else
X#  define	NSCREEN 7
X#endif
X#endif
X
Xint
Xhelpkey (n)
X  int n;
X{
X	static int	c = '\0';
X	int	prevkey;
X	char	banner [16];
X
X	/* Start with instructions on navigating Help */
X	strcpy (banner, "PAGE 0 OF HELP");
X	banner [5] = (char)n + '0';
X	windgoto(helprow = Rows-4, 63);
X	longline(banner);
X	windgoto(helprow = Rows-3, 63);
X	longline("^^^^^^^^^^^^^^");
X	windgoto(helprow = Rows-2, 54);
X	longline("<Press Esc to quit Help>");
X	windgoto(helprow = Rows-1, 44);
X	longline("<Other keys navigate Help screens>\n");
X
X	/* Now get keystrokes till we get a valid one */
X	while (1) {
X		prevkey = c;
X		c = vgetc();
X		switch (c) {
X		  /* cases for Next Screen */
X		  case ' ':	  case '\t':
X		  case '\n':	  case '\r':	case '+':
X		  case K_DARROW:
X		  case 'f':	  case CTRL('F'):
X		  case CTRL('D'): case CTRL('Y'):
X		  case 'n':	  case 'N':	case CTRL('N'):
X		  case 'j':
X			if (n < NSCREEN)	return (n+1);
X			break;
X
X		  /* cases for Previous Screen */
X		  case BS:	  case '-':
X		  case K_UARROW:
X		  case 'b':	  case CTRL('B'):
X		  case CTRL('U'): case CTRL('E'):
X		  case 'p':	  case 'P':	case CTRL('P'):
X		  case 'k':
X			if (n > 0) return (n-1);
X			break;
X
X		  /* cases for Quit Help */
X		  case ESC:
X		  case 'Q':
X		  case 'q':
X		  case 'X':
X		  case 'x':
X			lastscreen = n;		/* remember where we quit */
X			return (-1);
X
X		  /* "G" is presumed to be a "vi-style" go-to-line,
X		   * except that we interpret it as go-to-screen.
X		   */
X		  case 'G':
X			/* If previous key was a number,
X			 * we're already there.  Otherwise, go to
X			 * last screen.
X			 */
X			if (prevkey<(int)'0' || prevkey>NSCREEN+(int)'0')
X				return (NSCREEN);
X			break;
X
X		  /* Default is screen number or invalid code */
X		  default:
X			if (c>=(int)'0' && c<=NSCREEN+(int)'0')
X				return ( c - (int)'0' );
X			break;
X		}
X	}
X}
X
X
X#else
X
Xbool_t
Xvi_help()
X{
X	msg("Sorry, help not configured");
X	return FALSE;
X}
X#endif
END_OF_FILE
if test 14493 -ne `wc -c <'stevie/help.c'`; then
    echo shar: \"'stevie/help.c'\" unpacked with wrong size!
fi
# end of 'stevie/help.c'
fi
if test -f 'stevie/setenv.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stevie/setenv.c'\"
else
echo shar: Extracting \"'stevie/setenv.c'\" \(14259 characters\)
sed "s/^X//" >'stevie/setenv.c' <<'END_OF_FILE'
X/*****************************************************************************
X * A program for adding or changing environment variable values for MSDOS.
X * The "set" command provided by command.com is very limited.  It fails to
X * provide the ability to use quotation marks and escape characters and
X * octal/hex constants in the value definition.  Setenv provides these
X * abilities.
X *
X * Usage notes:
X *
X *	setenv <symbol> = <value>
X *
X *	<symbol> ::= legal MSDOS environment symbol.  Lower case converted
X *		     to uppercase.
X *
X *	<value>  ::= environment symbol value in one of three forms:
X *
X *		     * No quotation marks.  The value is the literal string
X *		       of characters starting IMMEDIATELY after the equal
X *		       sign and extending to the end-of-line.
X *
X *		     * Single quotation marks (').  The value is the literal
X *		       string enclosed in quotation marks.
X *
X *		     * Double quotation marks (").  The value is the string
X *		       enclosed in double quotation marks.  Backslash escape
X *		       constructions are processed -- this includes the usual
X *		       C language constructions such as \n for newline and
X *		       \r for carriage return plus octal and hexadecimal
X *		       constants (\ddd & \0xdd, respectively).
X *****************************************************************************/
X
X/*****************************************************************************
X * Based on a program by Alan J Myrvold (ajmyrvold@violet.waterloo.edu)
X *
X * WARNING WARNING WARNING - virtually no error checking is done !!
X *                           use at own risk !!
X *
X * This program by Larry A. Shurr (las@cbema.ATT.COM)
X *
X * I added checking for env seg overrun, so now it's a little more robust.
X *****************************************************************************/
X
X/*****************************************************************************
X *
X * Notes by Alan J Myrgold:
X *
X * Technical information : A program's PSP contains a pointer at
X * offset 44 (decimal) to a COPY of the parent's environment.
X * The environment is a set of strings of the form NAME=value,
X * each terminated by a NULL byte.
X * An additional NULL byte marks the end of the environment.
X * The environment area is ALWAYS paragraph aligned
X * i.e. on a 16 byte boundary.
X *
X * Searching backwards from the PSP, I consistently find
X * two copies of the envronment area.
X *
X * The program : finds the two areas
X *               reads one into memory
X *               udpates the specified environment variable
X *               writes updated environment to parent environment
X *****************************************************************************/
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <time.h>
X#include <process.h>
X#include <conio.h>
X#include <dos.h>
X
X#define FALSE 0
X#define TRUE  1
X
Xstruct mcb {				/* MSDOS Memory Control Block */
X  unsigned char tag4D;			/* Tag field must = 0x4D */
X  unsigned int  next;			/* Segment base for next block */
X  unsigned int  size;			/* Memory block size in paragraphs */
X};
X
X
Xunsigned env_size = 0;			/* Maintain size of environment */
X/***************************************************************************/
Xint env_size_bytes(unsigned env_seg)
X/* Determine the length of the environment area in bytes */
X{
X    int n;
X
X    n = 0;
X    while (peekb(env_seg,n) != 0) {
X          while (peekb(env_seg,n) != 0) n++;
X          n++;
X    }
X    return(n);
X}
X/***************************************************************************/
Xint env_size_strings(unsigned env_seg)
X/* Determine how many strings are in the environment area */
X{
X    int k,n;
X
X    k = n = 0;
X    while (peekb(env_seg,n) != 0) {
X          k++;
X          while (peekb(env_seg,n) != 0) n++;
X          n++;
X    }
X    return(k);
X}
X/***************************************************************************/
Xint peek_cmp(unsigned seg1,unsigned seg2,int nbytes)
X/* A trivial compare routine for segement aligned data items */
X{
X   int i;
X
X   for (i = 0; (i < nbytes) && (peekb(seg1,i) == peekb(seg2,i)); i++);
X   return(i == nbytes);
X}
X/***************************************************************************/
Xvoid find_env(unsigned seg_ray[2])
X{
X    unsigned psp_seg,copy_of_seg,env_seg;
X    int k,n;
X
X/* Find first copy of environment */
X    psp_seg = _psp;
X    copy_of_seg = peek(psp_seg,44);
X
X/* Set return value to non-garabage */
X    seg_ray[0] = seg_ray[1] = copy_of_seg;
X
X/* Search back to find 2 copies of environment */
X    env_size = n = env_size_bytes(copy_of_seg);
X    env_seg = copy_of_seg - 1;
X    for (k = 0; (env_seg != 0) && (k < 2); k++) {
X          while ((env_seg != 0) &&
X                 (peek_cmp(copy_of_seg,env_seg,n) == 0)) {
X                     env_seg--;
X          }
X          if (env_seg != 0) {
X              seg_ray[k] = env_seg;
X              env_seg--;
X          }
X    }
X
X/* If not found, display error message and abort */
X    if (k != 2) {
X       fprintf(stderr,"Two copies of the environment were not found\n");
X       exit(-1);
X    }
X}
X/***************************************************************************/
Xvoid read_env(unsigned env_seg,int *k,char ***s,char ***t)
X/* Read environment into a malloc'd array of malloc'd strings */
X{
X  int i,j,n;
X
X  env_size = env_size_bytes(env_seg);
X
X  *k = env_size_strings(env_seg);
X  *s = (char **) malloc((*k)*sizeof(char *));
X  *t = (char **) malloc((*k)*sizeof(char *));
X
X  n = 0;
X  for (i = 0; i < *k; i++) {
X    for (j = 0; peekb(env_seg,n+j) != '='; j++);
X    (*s)[i] = (char *) malloc(j+1);
X    for (j = 0; peekb(env_seg,n+j) != '='; j++)
X      ((*s)[i])[j] = peekb(env_seg,n+j);
X    ((*s)[i])[j] = 0;
X    n += j + 1;
X    for (j = 0; peekb(env_seg,n+j) != 0; j++);
X    (*t)[i] = (char *) malloc(j+1);
X    for (j = 0; peekb(env_seg,n+j) != 0; j++)
X      ((*t)[i])[j] = peekb(env_seg,n+j);
X    ((*t)[i])[j] = 0;
X    n += j + 1;
X  }
X}
X/***************************************************************************/
Xvoid write_env(unsigned env_seg, int k, char **s, char **t)
X/* Write the environment back out to memory */
X{
X  int i,j,n;
X
X  struct mcb far *tmcb = (struct mcb far *)((long)(env_seg-1) << 16);
X
X  if (tmcb->tag4D == 0x4D) {
X    unsigned env_seg_siz = tmcb->size << 4;
X    if (env_size < env_seg_siz) {
X      for (n = i = 0; i < k; i++) {
X        char *si = s[i];
X        char *ti = t[i];
X	for (j = 0; si[j] != 0; j++) pokeb(env_seg,n++,si[j]);
X	pokeb(env_seg,n++,'=');
X	for (j = 0; ti[j] != 0; j++) pokeb(env_seg,n++,ti[j]);
X	pokeb(env_seg,n++,0);
X      }
X      pokeb(env_seg,n,0);
X    } else {
X      fprintf(stderr,"Insufficient space in environment\n");
X      exit(-1);
X    }
X  } else {
X    fprintf(stderr,"Environment memory control block trashed\n");
X    exit(-1);
X  }
X}
X/***************************************************************************/
Xchar *get_env_var(int k,char **s,char **t,char *var)
X/* Return the value of the environment variable or NULL if not found */
X{
X    char *val;
X    int i;
X
X    val = NULL;
X    for (i = 0; i < k; i++) if (stricmp(s[i],var) == 0) val = t[i];
X
X    return(val);
X}
X
X/***************************************************************************/
Xvoid set_env_var(int *k,char ***s,char ***t,char *var,char *val)
X/* Set a new or existing environment variable to a new value */
X{
X  int i,done;
X
X  done = 0;
X  for (i = 0; i < *k; i++) {
X    if (stricmp((*s)[i],var) == 0) {
X      /* Existing variable */
X      done = 1;
X      env_size -= strlen((*t)[i]);
X      free((*t)[i]);
X      (*t)[i] = (char *) malloc(1+strlen(val));
X      strcpy((*t)[i],val);
X      env_size += strlen((*t)[i]);
X    }
X  }
X
X  if (!done) {
X    /* New environment variable */
X    (*k)++;
X    *s = realloc(*s,(*k)*sizeof(char *));
X    *t = realloc(*t,(*k)*sizeof(char *));
X    (*s)[*k-1] = (char *) malloc(1+strlen(var));
X    strcpy((*s)[*k-1],var);
X    strupr((*s)[*k-1]);
X    (*t)[*k-1] = (char *) malloc(1+strlen(val));
X    strcpy((*t)[*k-1],val);
X    /* Length of name  + length of '=' + length of value + length of '\0' */
X    env_size += (strlen((*s)[*k-1]) + 1 + strlen((*t)[*k-1]) + 1);
X  }
X}
X/***************************************************************************/
Xvoid show_env(int k,char **s,char **t)
X/* Display the array of environment strings */
X{
X   int i;
X   for (i = 0; i < k; i++) printf("%s=%s\n",s[i],t[i]);
X}
X/***************************************************************************/
Xvoid get_cmdline(char *cmd)
X/* Read raw command line text into string buffer */
X{
X    char far *pcmd;
X
X    int idx,odx;
X
X    pcmd = (char far *)((long)_psp << 16) + 128L;
X
X    for (idx = *pcmd++, odx = 0; idx > 0; idx--, odx++) {
X      cmd[odx] = *pcmd++;
X    }
X
X    cmd[odx] = '\0';
X}
X/***************************************************************************/
Xchar_in(char ch, char *set)
X/* Determine if a character is in a set of characters */
X{
X  do {
X    if (ch == *set) return(TRUE);
X  } while ((int)*(++set));
X  return(FALSE);
X}
X/***************************************************************************/
Xchar get_num(char *cmd, int *pidx)
X/* Interpret octal or hexadecimal constant in string */
X{
X  int   accum  = 0;
X  char  ch;
X  int   f_scan = TRUE;
X  int   idx    = *pidx;
X  int   limit;
X  char *nch    = cmd+idx;
X  char *och    = nch+1;
X  int   radix;
X
X#define HEXDIG "0123456789ABCDEFabcdef"
X
X  if (*nch == '0' && char_in(*och,"xX") && char_in(*(och+1),HEXDIG)) {
X    radix = 16;
X    limit = 2;
X    och += 1;
X  } else {
X    radix = 8;
X    limit = 3;
X    och = nch;
X  }
X
X  while (limit-- > 0 && f_scan) {
X
X    f_scan = FALSE;
X
X    while ((int)(*nch)) *nch++ = *och++;
X
X    nch = cmd+idx;
X    och = nch+1;
X
X    switch (ch = *nch) {
X      case '0' :
X      case '1' :
X      case '2' :
X      case '3' :
X      case '4' :
X      case '5' :
X      case '6' :
X      case '7' :
X      case '8' :
X      case '9' :
X	if (ch == 9 && radix == 8) break;
X	accum = accum * radix + (int)(ch - '0');
X        f_scan = TRUE;
X	break;
X      case 'A' :
X      case 'B' :
X      case 'C' :
X      case 'D' :
X      case 'E' :
X      case 'F' :
X	if (radix == 8) break;
X	accum = accum * radix + (int)(ch - 'A') + 10;
X        f_scan = TRUE;
X	break;
X      case 'a' :
X      case 'b' :
X      case 'c' :
X      case 'd' :
X      case 'e' :
X      case 'f' :
X	if (radix == 8) break;
X	accum = accum * radix + (int)(ch - 'a') + 10;
X        f_scan = TRUE;
X	break;
X      default  : break;
X    }
X  }
X
X  *pidx = idx;
X  return(accum);
X}
X/***************************************************************************/
Xget_escape(char *cmd, int *pidx, char quote)
X/* Interpret escape'd (i.e., '\' (backslash) character */
X{
X  int   idx = *pidx;
X
X  if (quote == '"') {
X    char *nch = cmd+idx;
X    char *och = nch+1;
X    char *xch = nch;
X    while ((int)(*nch)) *nch++ = *och++;
X    switch (*xch) {
X      case 'a' : *xch = '\a'; break;
X      case 'b' : *xch = '\b'; break;
X      case 'c' : *xch = '\c'; break;
X      case 'd' : *xch = '\d'; break;
X      case 'e' : *xch = '\e'; break;
X      case 'f' : *xch = '\f'; break;
X      case 'g' : *xch = '\g'; break;
X      case 'h' : *xch = '\h'; break;
X      case 'i' : *xch = '\i'; break;
X      case 'j' : *xch = '\j'; break;
X      case 'k' : *xch = '\k'; break;
X      case 'l' : *xch = '\l'; break;
X      case 'm' : *xch = '\m'; break;
X      case 'n' : *xch = '\n'; break;
X      case 'o' : *xch = '\o'; break;
X      case 'p' : *xch = '\p'; break;
X      case 'q' : *xch = '\q'; break;
X      case 'r' : *xch = '\r'; break;
X      case 's' : *xch = '\s'; break;
X      case 't' : *xch = '\t'; break;
X      case 'u' : *xch = '\u'; break;
X      case 'v' : *xch = '\v'; break;
X      case 'w' : *xch = '\w'; break;
X      case 'x' : *xch = '\x'; break;
X      case 'y' : *xch = '\y'; break;
X      case 'z' : *xch = '\z'; break;
X      case '0' :
X      case '1' :
X      case '2' :
X        *xch = get_num(cmd, &idx);
X        break;
X    }
X  }
X
X  *pidx = idx + 1;
X}
X/***************************************************************************/
Xget_qvalue(char *cmd, int idx, char quote, char **value)
X/* Extract a quoted value part from command line */
X{
X  char ch;
X  int  f_esc;
X
X  *value = cmd + (++idx);
X
X  do {
X    while ((int)(ch = cmd[idx]) && ch != '\\' && ch != quote) idx++;
X    if (!(int)ch) return(-1);
X    if (ch == '\\') {
X      f_esc = TRUE;
X      get_escape(cmd, &idx, quote);
X    } else f_esc = FALSE;
X  } while (f_esc);
X
X  cmd[idx] = '\0';
X
X  for (idx += 1; (int)(ch = cmd[idx]) && ch == ' '; idx++);
X
X  if ((int)ch) return(-1);
X
X  return(0);
X}
X/***************************************************************************/
Xget_parm(char **name, char **value)
X/* Extract environment symbol name and value from command line */
X{
X    char ch;
X    int  idx;
X    int  sdx;
X
X    static char cmd[128];
X
X    get_cmdline(cmd);
X
X    for (idx = 0; (int)(ch = cmd[idx]) && ch  == ' '; idx++);
X
X    if (!(int)ch) return(1);
X
X    *name = cmd + idx;
X
X    for (; (int)(ch = cmd[idx]) && ch != '=' && ch != ' '; idx++);
X
X    if (!(int)ch) return(-1);
X
X    if (ch == ' ') {
X      cmd[idx] = '\0';
X      for (idx += 1; (int)(ch = cmd[idx]) && ch != '='; idx++);
X    } else cmd[idx] = '\0';
X
X    if (!(int)ch) return(-1);
X
X    for (sdx = (idx += 1); (int)(ch = cmd[idx]) && ch == ' '; idx++);
X
X    /*if (!(int)ch) return(-1);*/
X
X    switch (ch) {
X      case '"'  : return(get_qvalue(cmd, idx, '"', value));
X      case '\'' : return(get_qvalue(cmd, idx, '\'', value));
X      default   : *value = cmd + sdx; break;
X    }
X
X    return(0);
X}
X/***************************************************************************/
Xmain(int argc,char **argv)
X{
X    unsigned env_seg[2];
X    char **s,**t;
X    int k;
X    long now;
X    struct tm *local;
X
X    static char *name = NULL, *value = NULL;
X
X    switch (get_parm(&name,&value)) {
X
X    case -1:
X
X	fprintf(stderr,"Invalid symbol definition syntax\n");
X	exit(-1);
X
X    case 0:
X
X        /* Find and read environment */
X
X        find_env(env_seg);
X        read_env(env_seg[1],&k,&s,&t);
X
X	/* Set the variable <name> to <value> */
X
X	set_env_var(&k,&s,&t,name,value);
X
X	/* Update caller's environment */
X
X	write_env(env_seg[0],k,s,t);
X
X	break;
X
X    case 1:
X
X	fprintf(stderr,"Usage: setenv <symbol name> = <value>\n");
X	break;
X    }
X
X    return(0);
X}
X/***************************************************************************/
X
END_OF_FILE
if test 14259 -ne `wc -c <'stevie/setenv.c'`; then
    echo shar: \"'stevie/setenv.c'\" unpacked with wrong size!
fi
# end of 'stevie/setenv.c'
fi
echo shar: End of archive 8 \(of 13\).
cp /dev/null ark8isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 13 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
