[comp.sources.misc] v19i048: dmake - dmake version 3.7, Part27/37

dvadura@watdragon.waterloo.edu (Dennis Vadura) (05/13/91)

Submitted-by: Dennis Vadura <dvadura@watdragon.waterloo.edu>
Posting-number: Volume 19, Issue 48
Archive-name: dmake/part27
Supersedes: dmake-3.6: Volume 15, Issue 52-77

---- Cut Here and feed the following to sh ----
#!/bin/sh
# this is dmake.shar.27 (part 27 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file dmake/os2/mscdos/public.h continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 27; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test -f _shar_wnt_.tmp; then
sed 's/^X//' << 'SHAR_EOF' >> 'dmake/os2/mscdos/public.h' &&
void Catch_signals ANSI((void (*)()));
void Clear_signals ANSI(());
void Prolog ANSI((int, char* []));
void Epilog ANSI((int));
char * Get_current_dir ANSI(());
int Set_dir ANSI((char*));
char Get_switch_char ANSI(());
FILE* Get_temp ANSI((char **, char *, int));
FILE * Start_temp ANSI((char *, CELLPTR, char **));
void Open_temp_error ANSI((char *, char *));
void Link_temp ANSI((CELLPTR, FILE *, char *));
void Close_temp ANSI((CELLPTR, FILE *));
void Unlink_temp_files ANSI((CELLPTR));
void Handle_result ANSI((int, int, int, CELLPTR));
void Update_time_stamp ANSI((CELLPTR));
void Parse ANSI((FILE *));
int Get_line ANSI((char *, FILE *));
char * Do_comment ANSI((char *, char **, int));
char * Get_token ANSI((TKSTRPTR, char *, int));
void Quit ANSI(());
void Read_state ANSI(());
void Write_state ANSI(());
int Check_state ANSI((CELLPTR, STRINGPTR *, int));
char* basename ANSI((char *));
void Dump ANSI(());
void Dump_recipe ANSI((STRINGPTR));
int Parse_macro ANSI((char *, int));
int Macro_op ANSI((char *));
int Parse_rule_def ANSI((int *));
int Rule_op ANSI((char *));
void Add_recipe_to_list ANSI((char *, int, int));
void Bind_rules_to_targets ANSI((int));
int Set_group_attributes ANSI((char *));
DFALINKPTR Match_dfa ANSI((char *));
void Check_circle_dfa ANSI(());
void Add_nfa ANSI((char *));
char * Exec_function ANSI((char *));
int runargv ANSI((CELLPTR, int, int, int, int, char *));
void SetSessionTitle ANSI(());
int Wait_for_child ANSI((int, int));
void Clean_up_processes ANSI(());
int _chdir ANSI((char *));
int If_root_path ANSI((char *));
time_t seek_arch ANSI((char*, char*));
int touch_arch ANSI((char*, char*));
void Remove_prq ANSI((CELLPTR));
X
#endif
SHAR_EOF
chmod 0640 dmake/os2/mscdos/public.h ||
echo 'restore of dmake/os2/mscdos/public.h failed'
Wc_c="`wc -c < 'dmake/os2/mscdos/public.h'`"
test 5614 -eq "$Wc_c" ||
	echo 'dmake/os2/mscdos/public.h: original size 5614, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/os2/mscdos/startup.mk ==============
if test -f 'dmake/os2/mscdos/startup.mk' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/os2/mscdos/startup.mk (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/os2/mscdos/startup.mk' &&
#NOTE:  startup.mk file is called dmake.ini for OS/2
#       and is found in os2/mscdos/dmake.ini
.INCLUDE : "os2/mscdos/dmake.ini"
SHAR_EOF
chmod 0640 dmake/os2/mscdos/startup.mk ||
echo 'restore of dmake/os2/mscdos/startup.mk failed'
Wc_c="`wc -c < 'dmake/os2/mscdos/startup.mk'`"
test 132 -eq "$Wc_c" ||
	echo 'dmake/os2/mscdos/startup.mk: original size 132, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/os2/mscdos/tempnam.c ==============
if test -f 'dmake/os2/mscdos/tempnam.c' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/os2/mscdos/tempnam.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/os2/mscdos/tempnam.c' &&
/*LINTLIBRARY*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dos.h>
X
#if defined(max)
#   undef  max
#endif
#define max(A,B) (((A)<(B))?(B):(A))
X
extern int access();
int _access();
X
/* MSC stdio.h defines P_tmpdir, so let's undo it here */
/* Under DOS leave the default tmpdir pointing here!		*/
#ifdef P_tmpdir
#undef P_tmpdir
#endif
static char *P_tmpdir = "";
X
char *
tempnam(dir, prefix)
char *dir;		/* use this directory please (if non-NULL) */
char *prefix;		/* use this (if non-NULL) as filename prefix */
{
X   static         int count = 0;
X   register char *p, *q, *tmpdir;
X   int            tl=0, dl=0, pl;
X   char		  buf[30];
X
X   pl = strlen(P_tmpdir);
X
X   if( (tmpdir = getenv("TMPDIR")) != NULL )
X      tl = strlen(tmpdir);
X   else if( (tmpdir = getenv("TMP")) != NULL )
X      tl = strlen(tmpdir);
X   if( dir != NULL ) dl = strlen(dir);
X
X   if( (p = malloc((unsigned)(max(max(dl,tl),pl)+13))) == NULL )
X     return(NULL);
X
X   *p = '\0';
X
X   if( (tl == 0) || (_access( strcpy(p, tmpdir), 0) != 0) )
X     if( (dl == 0) || (_access( strcpy(p, dir), 0) != 0) )
X	if( _access( strcpy(p, P_tmpdir), 0) != 0 )
X	   if( !prefix )
X	      prefix = "tp";
X
X   if(prefix)
X   {
X      *(p+strlen(p)+2) = '\0';
X      (void)strncat(p, prefix, 2);
X   }
X
#ifdef OS2
X   sprintf( buf, "%08x", getpid() );
#else
X   sprintf( buf, "%08x", _psp );
#endif
X   buf[6]='\0';
X   (void)strcat(p, buf );
X   sprintf( buf, "%04d", count++ );
X   q=p+strlen(p)-6;
X   *q++ = buf[0]; *q++ = buf[1];
X   *q++ = buf[2]; *q++ = buf[3];
X
X   if( (q = strrchr(p,'.')) != NULL ) *q = '\0';
X
X   return strlwr(p);
}
X
X
X
_access( name, flag )
char *name;
int  flag;
{
X   char *p;
X   int r;
X
X   if( name == NULL || !*name ) return(1);  /* NULL dir means current dir */
X   p = name+strlen(name)-1;
X   if(*p == ':' ) strcat( p++, "\\" );
X   r = access( name, flag );
X   if(*p != '/' && *p != '\\') strcat( p, "\\" );
X
X   return( r );
}
SHAR_EOF
chmod 0640 dmake/os2/mscdos/tempnam.c ||
echo 'restore of dmake/os2/mscdos/tempnam.c failed'
Wc_c="`wc -c < 'dmake/os2/mscdos/tempnam.c'`"
test 1919 -eq "$Wc_c" ||
	echo 'dmake/os2/mscdos/tempnam.c: original size 1919, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/os2/ruletab.c ==============
if test -f 'dmake/os2/ruletab.c' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/os2/ruletab.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/os2/ruletab.c' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/os2/RCS/ruletab.c,v 1.1 91/05/06 15:33:22 dvadura Exp $
-- SYNOPSIS -- Default initial configuration of dmake.
-- 
-- DESCRIPTION
-- 	Define here the initial set of rules that are defined before
--	dmake performs any processing.
--
-- AUTHOR
--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
--
-- COPYRIGHT
--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
-- 
--      This program is free software; you can redistribute it and/or
--      modify it under the terms of the GNU General Public License
--      (version 1), as published by the Free Software Foundation, and
--      found in the file 'LICENSE' included with this distribution.
-- 
--      This program is distributed in the hope that it will be useful,
--      but WITHOUT ANY WARRANTY; without even the implied warrant of
--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--      GNU General Public License for more details.
-- 
--      You should have received a copy of the GNU General Public License
--      along with this program;  if not, write to the Free Software
--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--
-- LOG
--     $Log:	ruletab.c,v $
X * Revision 1.1  91/05/06  15:33:22  dvadura
X * dmake Release Version 3.7
X * 
*/
X
/* These are control macros for dmake that MUST be defined at some point
X * if they are NOT dmake will not work!  These are default definitions.  They
X * may be overridden inside the .STARTUP makefile, they are here
X * strictly so that dmake can parse the STARTUP makefile */
/*
X * For OS/2 these are close to the Unix definitions in terms of limits.
X * We dont need the two different cases of Makefile, so only keep the
X * pretty one.
X */
static char *_rules[] = {
X	"MAXLINELENGTH := 2046",
X	"MAXPROCESSLIMIT := 16",
X	".IMPORT .IGNORE: ROOTDIR INIT",
X	".MAKEFILES : makefile.mk Makefile",
X	".SOURCE    : .NULL",
#include "startup.h"
X	0 };
X
char **Rule_tab = _rules; /* for sundry reasons in Get_environment() */
X
SHAR_EOF
chmod 0640 dmake/os2/ruletab.c ||
echo 'restore of dmake/os2/ruletab.c failed'
Wc_c="`wc -c < 'dmake/os2/ruletab.c'`"
test 2098 -eq "$Wc_c" ||
	echo 'dmake/os2/ruletab.c: original size 2098, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/os2/runargv.c ==============
if test -f 'dmake/os2/runargv.c' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/os2/runargv.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/os2/runargv.c' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/os2/RCS/runargv.c,v 1.1 91/05/06 15:33:22 dvadura Exp $
-- SYNOPSIS -- invoke a sub process, modified unix/runargv.c for OS/2.
-- 
-- DESCRIPTION
-- 	Use the standard methods of executing a sub process.
--
-- AUTHOR
--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
--
-- COPYRIGHT
--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
-- 
--      This program is free software; you can redistribute it and/or
--      modify it under the terms of the GNU General Public License
--      (version 1), as published by the Free Software Foundation, and
--      found in the file 'LICENSE' included with this distribution.
-- 
--      This program is distributed in the hope that it will be useful,
--      but WITHOUT ANY WARRANTY; without even the implied warrant of
--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--      GNU General Public License for more details.
-- 
--      You should have received a copy of the GNU General Public License
--      along with this program;  if not, write to the Free Software
--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--
-- LOG
--     $Log:	runargv.c,v $
X * Revision 1.1  91/05/06  15:33:22  dvadura
X * dmake Release Version 3.7
X * 
*/
X
#define INCL_DOSPROCESS
#include <os2.h>
X
#include <process.h>
#include <stdlib.h>
#include <signal.h>
#include "extern.h"
#include "sysintf.h"
X
typedef struct prp {
X   char *prp_cmd;
X   int   prp_group;
X   int   prp_ignore;
X   int   prp_last;
X   int	 prp_shell;
X   struct prp *prp_next;
} RCP, *RCPPTR;
X
typedef struct pr {
X   int		pr_valid;
X   int		pr_pid;
X   CELLPTR	pr_target;
X   int		pr_ignore;
X   int		pr_last;
X   RCPPTR  	pr_recipe;
X   RCPPTR  	pr_recipe_end;
X   char		*pr_dir;
} PR;
X
static PR  *_procs    = NIL(PR);
static int  _proc_cnt = 0;
static int  _abort_flg= FALSE;
static int  _use_i    = -1;
static int  _do_upd   = 0;
X
extern unsigned int _far _pascal DosSmSetTitle(char _far *s);
static  void	SetSessionTitle (char *s);
static  void	_add_child ANSI((int, CELLPTR, int, int));
static  void	_attach_cmd ANSI((char *, int, int, CELLPTR, int, int));
static  void    _finished_child ANSI((int, int));
static  int     _running ANSI((CELLPTR));
X
PUBLIC int
runargv(target, ignore, group, last, shell, cmd)
CELLPTR target;
int     ignore;
int	group;
int	last;
int     shell;
char	*cmd;
{
X   int          pid;
X   char         **argv;
X
X   if( _running(target) /*&& Max_proc != 1*/ ) {
X      /* The command will be executed when the previous recipe
X       * line completes. */
X      _attach_cmd( cmd, group, ignore, target, last, shell );
X      return(1);
X   }
X
X   while( _proc_cnt == Max_proc )
X      if( Wait_for_child(FALSE, -1) == -1 )  Fatal( "Lost a child" );
X
#ifdef SESSTITLE
X   SetSessionTitle(target->CE_NAME);
#endif
X   argv = Pack_argv( group, shell, cmd );
X
X   if((pid=spawnvp((_osmode == DOS_MODE)?P_WAIT:P_NOWAIT,argv[0],argv)) == -1){
X      Error("%s: %s", argv[0], sys_errlist[errno]);
X      Handle_result(-1, ignore, _abort_flg, target);
X      return(-1);
X   }
X   else if( _osmode == DOS_MODE ) {
X     _add_child(4711, target, ignore, last);
X     _finished_child(4711, pid);
X   }
X   else
X     _add_child(pid, target, ignore, last);
X
X   return(1);
}
X
X
#ifdef SESSTITLE
/* N.B. The system call used below is undocumented and therefore possibly
X * subject to change. It sets the session title even from a full screen
X * session, so you can see which target is being built.
X * If dubious about undocumented calls simply remove it.
X */
PUBLIC void
SetSessionTitle(char *s)
{
X   char buff[128];
X   strncpy(buff, Pname, sizeof(buff));
X   buff[sizeof(buff)-1] = 0;
X   strncat(buff, " - ", sizeof(buff));
X   strncat(buff, s, sizeof(buff));
X   buff[sizeof(buff)-1] = 0;
X   DosSmSetTitle(buff);
}
#endif
X
X
PUBLIC int
Wait_for_child( abort_flg, pid )
int abort_flg;
int pid;
{
X   int wid;
X   int status;
X   int waitchild;
X
X   if( _osmode == DOS_MODE ) return(1);
X
X   waitchild = (pid == -1)? FALSE : Wait_for_completion;
X
X   do {
X      if( (wid = wait(&status)) == -1 ) return(-1);
X
X      _abort_flg = abort_flg;
X      _finished_child(wid, status);
X      _abort_flg = FALSE;
X   }
X   while( waitchild && pid != wid );
X
X   return(0);
}
X
X
PUBLIC void
Clean_up_processes()
{
X   register int i;
X
X   if( _osmode == DOS_MODE ) {
X      _abort_flg = TRUE;
X      _finished_child(4711, -1);
X      return;
X   }
X
X   if( _procs != NIL(PR) ) {
X      for( i=0; i<Max_proc; i++ )
X	 if( _procs[i].pr_valid )
X	    DosKillProcess(DKP_PROCESSTREE, _procs[i].pr_pid);
X
X      while( Wait_for_child(TRUE, -1) != -1 );
X   }
}
X
X
static void
_add_child( pid, target, ignore, last )
int	pid;
CELLPTR target;
int	ignore;
int     last;
{
X   register int i;
X   register PR *pp;
X
X   if( _procs == NIL(PR) ) {
X      TALLOC( _procs, Max_proc, PR );
X   }
X
X   if( (i = _use_i) == -1 )
X      for( i=0; i<Max_proc; i++ )
X	 if( !_procs[i].pr_valid )
X	    break;
X
X   pp = _procs+i;
X
X   pp->pr_valid  = 1;
X   pp->pr_pid    = pid;
X   pp->pr_target = target;
X   pp->pr_ignore = ignore;
X   pp->pr_last   = last;
X   pp->pr_dir    = _strdup(Get_current_dir());
X
X   Current_target = NIL(CELL);
X
X   _proc_cnt++;
X
X   if( Wait_for_completion ) Wait_for_child( FALSE, pid );
}
X
X
static void
_finished_child(pid, status)
int	pid;
int	status;
{
X   register int i;
X   register PR *pp;
X   char     *dir;
X
X   for( i=0; i<Max_proc; i++ )
X      if( _procs[i].pr_valid && _procs[i].pr_pid == pid )
X	 break;
X
X   /* Some children we didn't make esp true if using /bin/sh to execute a
X    * a pipe and feed the output as a makefile into dmake. */
X   if( i == Max_proc ) return;
X   _procs[i].pr_valid = 0;
X   _proc_cnt--;
X   dir = _strdup(Get_current_dir());
X   Set_dir( _procs[i].pr_dir );
X
X   if( _procs[i].pr_recipe != NIL(RCP) && !_abort_flg ) {
X      RCPPTR rp = _procs[i].pr_recipe;
X
X
X      Current_target = _procs[i].pr_target;
X      Handle_result( status, _procs[i].pr_ignore, FALSE, _procs[i].pr_target );
X      Current_target = NIL(CELL);
X
X      _procs[i].pr_recipe = rp->prp_next;
X
X      _use_i = i;
X      runargv( _procs[i].pr_target, rp->prp_ignore, rp->prp_group,
X	       rp->prp_last, rp->prp_shell, rp->prp_cmd );
X      _use_i = -1;
X
X      FREE( rp->prp_cmd );
X      FREE( rp );
X
X      if( _proc_cnt == Max_proc ) Wait_for_child( FALSE, -1 );
X   }
X   else {
X      Unlink_temp_files( _procs[i].pr_target );
X      Handle_result(status,_procs[i].pr_ignore,_abort_flg,_procs[i].pr_target);
X
X      if( _procs[i].pr_last ) {
X	 FREE(_procs[i].pr_dir );
X
X	 if( !Doing_bang ) Update_time_stamp( _procs[i].pr_target );
X      }
X   }
X
X   Set_dir(dir);
X   FREE(dir);
}
X
X
static int
_running( cp )
CELLPTR cp;
{
X   register int i;
X
X   if( !_procs ) return(FALSE);
X
X   for( i=0; i<Max_proc; i++ )
X      if( _procs[i].pr_valid &&
X	  _procs[i].pr_target == cp  )
X	 break;
X	 
X   return( i != Max_proc );
}
X
X
static void
_attach_cmd( cmd, group, ignore, cp, last, shell )
char    *cmd;
int	group;
int     ignore;
CELLPTR cp;
int     last;
int     shell;
{
X   register int i;
X   RCPPTR rp;
X
X   for( i=0; i<Max_proc; i++ )
X      if( _procs[i].pr_valid &&
X	  _procs[i].pr_target == cp  )
X	 break;
X
X   TALLOC( rp, 1, RCP );
X   rp->prp_cmd   = _strdup(cmd);
X   rp->prp_group = group;
X   rp->prp_ignore= ignore;
X   rp->prp_last  = last;
X   rp->prp_shell = shell;
X   rp->prp_dir   = _strdup(Get_current_dir());
X
X   if( _procs[i].pr_recipe == NIL(RCP) )
X      _procs[i].pr_recipe = _procs[i].pr_recipe_end = rp;
X   else {
X      _procs[i].pr_recipe_end->prp_next = rp;
X      _procs[i].pr_recipe_end = rp;
X   }
}
SHAR_EOF
chmod 0640 dmake/os2/runargv.c ||
echo 'restore of dmake/os2/runargv.c failed'
Wc_c="`wc -c < 'dmake/os2/runargv.c'`"
test 7611 -eq "$Wc_c" ||
	echo 'dmake/os2/runargv.c: original size 7611, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/os2/startup.h ==============
if test -f 'dmake/os2/startup.h' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/os2/startup.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/os2/startup.h' &&
/* This file contains the default value of the MAKESTARTUP variable.
X * You must set the quoted string below to the default path to the startup
X * variable, so that it gets compiled in.  LEAVE ROOTDIR at the front of
X * the path.  This allows the user to customize his environment for dmake
X * by setting up a new ROOTDIR environment variable. */
X
"MAKESTARTUP := $(INIT)/dmake.ini",
SHAR_EOF
chmod 0640 dmake/os2/startup.h ||
echo 'restore of dmake/os2/startup.h failed'
Wc_c="`wc -c < 'dmake/os2/startup.h'`"
test 384 -eq "$Wc_c" ||
	echo 'dmake/os2/startup.h: original size 384, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/os2/stdarg.h ==============
if test -f 'dmake/os2/stdarg.h' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/os2/stdarg.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/os2/stdarg.h' &&
/*
X * stdarg.h
X *
X * defines ANSI style macros for accessing arguments of a function which takes
X * a variable number of arguments
X *
X */
X
#if !defined(__STDARG)
#define __STDARG
X
typedef char *va_list;
X
#define va_dcl int va_alist
#define va_start(ap,v)  ap = (va_list)&va_alist
#define va_arg(ap,t)    ((t*)(ap += sizeof(t)))[-1]
#define va_end(ap)      ap = NULL
#endif
SHAR_EOF
chmod 0640 dmake/os2/stdarg.h ||
echo 'restore of dmake/os2/stdarg.h failed'
Wc_c="`wc -c < 'dmake/os2/stdarg.h'`"
test 373 -eq "$Wc_c" ||
	echo 'dmake/os2/stdarg.h: original size 373, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/os2/switchar.c ==============
if test -f 'dmake/os2/switchar.c' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/os2/switchar.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/os2/switchar.c' &&
/*
** return switch char
*/
#if defined(OS2) || defined(_MSC_VER)
#include <stdlib.h>
#endif
#if !defined(OS2)
#include <dos.h>
#endif /* !OS2 */
#include <stdio.h>
#include "stdmacs.h"
X
getswitchar()/*
===============
X   Try the environment first.  If you don't find SWITCHAR there, then use
X   the DOS call.  The call is undocumented, and doesn't work for DOS versions
X   4.0 and up, so the check of the environment will fix that. */
{
#if defined(M_I86)
#if !defined(OS2)
X   union REGS rg;
#endif /* ! OS2 */
X   static char *_env_switchar = NIL(char);
X
X   if( _env_switchar != NIL(char) ||
X       (_env_switchar = (char *)getenv("SWITCHAR")) != NIL(char) )
X      return(*_env_switchar);
X
#if !defined(OS2)
X   rg.h.ah = 0x37;      /* switch char request */
X   rg.h.al = 0;         /* get (not set) */
X
X   intdos(&rg, &rg);
X   return (rg.h.dl);
#endif /* ! OS2 */
#endif /* M_I86 */
X
X   return ('/');
}
SHAR_EOF
chmod 0640 dmake/os2/switchar.c ||
echo 'restore of dmake/os2/switchar.c failed'
Wc_c="`wc -c < 'dmake/os2/switchar.c'`"
test 904 -eq "$Wc_c" ||
	echo 'dmake/os2/switchar.c: original size 904, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/os2/sysintf.h ==============
if test -f 'dmake/os2/sysintf.h' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/os2/sysintf.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/os2/sysintf.h' &&
/*
** assorted bits of system interface
*/
X
#define STAT stat
#define VOID_LCACHE(l,m)
#define Hook_std_writes(A)
#define GETPID getpid()
X
extern char * tempnam();
extern char * getcwd();
X
/*
** standard C items
*/
X
/*
** DOS interface standard items
*/
#define	chdir(p) _chdir(p)
X
/*
** make parameters
*/
#define	MAX_PATH_LEN	256
X
SHAR_EOF
chmod 0640 dmake/os2/sysintf.h ||
echo 'restore of dmake/os2/sysintf.h failed'
Wc_c="`wc -c < 'dmake/os2/sysintf.h'`"
test 333 -eq "$Wc_c" ||
	echo 'dmake/os2/sysintf.h: original size 333, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/parse.c ==============
if test -f 'dmake/parse.c' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/parse.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/parse.c' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/parse.c,v 1.1 91/05/06 15:23:20 dvadura Exp $
-- SYNOPSIS -- parse the input, and perform semantic analysis
-- 
-- DESCRIPTION
-- 	This file contains the routines that parse the input makefile and
--	call the appropriate routines to perform the semantic analysis and
--	build the internal dag.
--
-- AUTHOR
--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
--
-- COPYRIGHT
--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
-- 
--      This program is free software; you can redistribute it and/or
--      modify it under the terms of the GNU General Public License
--      (version 1), as published by the Free Software Foundation, and
--      found in the file 'LICENSE' included with this distribution.
-- 
--      This program is distributed in the hope that it will be useful,
--      but WITHOUT ANY WARRANTY; without even the implied warrant of
--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--      GNU General Public License for more details.
-- 
--      You should have received a copy of the GNU General Public License
--      along with this program;  if not, write to the Free Software
--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--
-- LOG
--     $Log:	parse.c,v $
X * Revision 1.1  91/05/06  15:23:20  dvadura
X * dmake Release Version 3.7
X * 
*/
X
#include "extern.h"
X
X
PUBLIC void
Parse( fil )/*
==============  Parse the makefile input */
FILE *fil;
{
X   int  rule  = FALSE;                 /* have seen a recipe line        */
X   char *p;			       /* termporary pointer into Buffer */
X
X   DB_ENTER( "Parse" );
X
X   State = NORMAL_SCAN;
X   Group = FALSE;                 /* true if scanning a group rcpe  */
X   while( TRUE ) {
X      if( Get_line( Buffer, fil ) ) {
X	 if( fil != NIL( FILE ) )               /* end of parsable input */
X	    Closefile();
X
X	 Bind_rules_to_targets( F_DEFAULT );
X         if( Group )  Fatal( "Incomplete rule recipe group detected" );
X
X	 DB_VOID_RETURN;
X      }
X      else {
X         switch( State ) {
X	    case RULE_SCAN:
X
X	       /* Check for the `[' that starts off a group rule definition.  It
X	        * must appear as the first non-white space
X		* character in the line. */
X
X	       p = _strspn( Buffer, " \t\r\n" );
X               if( Set_group_attributes( p ) ) {
X                  if( rule && Group )
X                     Fatal( "Cannot mix single and group recipe lines" );
X                  else
X                     Group = TRUE;
X
X                  rule = TRUE;
X
X                  break;                     /* ignore the group start  */
X               }
X
X               if( Group ) {
X                  if( *p != ']' ) {
X                     Add_recipe_to_list( Buffer, TRUE, TRUE );
X                     rule = TRUE;
X                  }
X                  else
X                     State = NORMAL_SCAN;
X               }
X               else {
X                  if( *Buffer == '\t' ) {
X                     Add_recipe_to_list( Buffer, FALSE, FALSE );
X                     rule = TRUE;
X                  }
X                  else if( *p == ']' )
X                     Fatal( "Found unmatched ']'" );
X                  else if( *Buffer && *p )
X		     State = NORMAL_SCAN;
X               }
X 
X               if( State == RULE_SCAN ) break;     /* ie. keep going    */
X               
X	       Bind_rules_to_targets( (Group) ? F_GROUP: F_DEFAULT );
X
X               rule = FALSE;
X               if( Group ) {
X                  Group = FALSE;
X                  break;
X               }
X	       /*FALLTRHOUGH*/
X
X               /* In this case we broke out of the rule scan because we do not
X                * have a recipe line that begins with a <TAB>, so lets
X		* try to scan the thing as a macro or rule definition. */
X               
X
X	    case NORMAL_SCAN:
X	       if( !*Buffer ) continue;         /* we have null input line */
X
X	       /* STUPID AUGMAKE uses "include" at the start of a line as
X	        * a signal to include a new file, so let's look for it.
X		* if we see it replace it by .INCLUDE: and stick this back
X		* into the buffer. */
X	       if( !strncmp( "include", Buffer, 7 ) &&
X		   (Buffer[7] == ' ' || Buffer[7] == '\t') )
X	       {
X		  char *tmp;
X
X		  tmp = _strjoin( ".INCLUDE:", Buffer+7, -1, FALSE );
X		  strcpy( Buffer, tmp );
X		  FREE( tmp );
X	       }
X
X               /* look for a macro definition, they all contain an = sign
X	        * if we fail to recognize it as a legal macro op then try to
X		* parse the same line as a rule definition, it's one or the
X		* other */
X		
X	       if( Parse_macro(Buffer, M_DEFAULT) ) break;/* it's a macro def */
X	       if( Parse_rule_def( &State ) ) 	    break;/* it's a rule def  */
X
X	       /* if just blank line then ignore it */
X	       if( *_strspn( Buffer, " \t\r\n" ) == '\0' ) break;
X	       
X	       /* otherwise assume it was a line of unrecognized input, or a
X	        * recipe line out of place so print a message */
X		
X	       Fatal( "Expecting macro or rule defn, found neither" );
X	       break;
X
X	    default:
X	       Fatal( "Internal -- UNKNOWN Parser state %d", State );
X	 }
X      }
X   }
}
X
SHAR_EOF
chmod 0640 dmake/parse.c ||
echo 'restore of dmake/parse.c failed'
Wc_c="`wc -c < 'dmake/parse.c'`"
test 5207 -eq "$Wc_c" ||
	echo 'dmake/parse.c: original size 5207, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/patchlvl.h ==============
if test -f 'dmake/patchlvl.h' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/patchlvl.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/patchlvl.h' &&
/* dmake patch level, reset to 0 for each new version release. */
X
#define PATCHLEVEL 0
SHAR_EOF
chmod 0640 dmake/patchlvl.h ||
echo 'restore of dmake/patchlvl.h failed'
Wc_c="`wc -c < 'dmake/patchlvl.h'`"
test 88 -eq "$Wc_c" ||
	echo 'dmake/patchlvl.h: original size 88, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/path.c ==============
if test -f 'dmake/path.c' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/path.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/path.c' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/path.c,v 1.1 91/05/06 15:23:23 dvadura Exp $
-- SYNOPSIS -- pathname manipulation code
-- 
-- DESCRIPTION
--	Pathname routines to handle building and pulling appart
--	pathnames.
-- 
-- AUTHOR
--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
--
-- COPYRIGHT
--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
-- 
--      This program is free software; you can redistribute it and/or
--      modify it under the terms of the GNU General Public License
--      (version 1), as published by the Free Software Foundation, and
--      found in the file 'LICENSE' included with this distribution.
-- 
--      This program is distributed in the hope that it will be useful,
--      but WITHOUT ANY WARRANTY; without even the implied warrant of
--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--      GNU General Public License for more details.
-- 
--      You should have received a copy of the GNU General Public License
--      along with this program;  if not, write to the Free Software
--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--
-- LOG
--     $Log:	path.c,v $
X * Revision 1.1  91/05/06  15:23:23  dvadura
X * dmake Release Version 3.7
X * 
*/
X
#include "extern.h"
X
/*
** Return the suffix portion of a filename, assumed to begin with a `.'.
*/
PUBLIC char *
Get_suffix(name)
char *name;
{
X   char *suff;
X
X   if(name == NIL(char)  || (suff = strrchr(name, '.')) == NIL(char))
X      suff = ".NULL";
X
X   return (suff);
}
X
X
X
/*
** Take dir and name, and return a path which has dir as the directory
** and name afterwards.
**
** N.B. Assumes that the dir separator string is in DirSepStr.
**      Return path is built in a static buffer, if you need to use it
**      again you must _strdup the result returned by Build_path.
*/
PUBLIC char *
Build_path(dir, name)
char *dir;
char *name;
{
X   register char *p;
X   register char *q;
X   static char     *path  = NIL(char);
X   static unsigned buflen = 0;
X   int  plen = 0;
X   int  dlen = 0;
X   int  len;
X
X   if( dir  != NIL(char) ) dlen = strlen( dir  );
X   if( name != NIL(char) ) plen = strlen( name );
X   len = plen+dlen+strlen(DirSepStr)+1;
X
X   if( len > buflen ) {
X      buflen = (len+16) & ~0xf;		/* buf is always multiple of 16 */
X
X      if( path == NIL(char) )
X         path = MALLOC( buflen, char );
X      else
X         path = realloc( path, (unsigned) (buflen*sizeof(char)) );
X   }
X   
X   *path = '\0';
X
X   if( dlen ) {
X      strcpy( path, dir );
X      if( *path && strchr(DirBrkStr, dir[dlen-1]) == NIL(char) )
X	 strcat( path, DirSepStr );
X   }
X   strcat( path, name );
X
X   q=path;
X   while( *q ) {
X      char *t;
X
X      p=_strpbrk(q,DirBrkStr);
X      t=_strpbrk(p+1,DirBrkStr);
X      if( !*p || !*t ) break;
X
X      if(    !(p-q == 2 && strncmp(q,"..",2) == 0)
X          && t-p-1 == 2 && strncmp(p+1,"..",2) == 0 ) {
X	 t = _strspn(t,DirBrkStr);
X	 strcpy(q,t);
X      }
X      else
X	 q = p+1;
X   }
X
X   return( path );
}
SHAR_EOF
chmod 0640 dmake/path.c ||
echo 'restore of dmake/path.c failed'
Wc_c="`wc -c < 'dmake/path.c'`"
test 3063 -eq "$Wc_c" ||
	echo 'dmake/path.c: original size 3063, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/percent.c ==============
if test -f 'dmake/percent.c' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/percent.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/percent.c' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/percent.c,v 1.1 91/05/06 15:23:24 dvadura Exp $
-- SYNOPSIS -- handle building or %-rule meta-target nfa.
-- 
-- DESCRIPTION
--	Builds the NFA used by dmake to match targets against %-meta
--	rule constructs.  The NFA is built as a set of DFA's.
-- 
-- AUTHOR
--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
--
-- COPYRIGHT
--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
-- 
--      This program is free software; you can redistribute it and/or
--      modify it under the terms of the GNU General Public License
--      (version 1), as published by the Free Software Foundation, and
--      found in the file 'LICENSE' included with this distribution.
-- 
--      This program is distributed in the hope that it will be useful,
--      but WITHOUT ANY WARRANTY; without even the implied warrant of
--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--      GNU General Public License for more details.
-- 
--      You should have received a copy of the GNU General Public License
--      along with this program;  if not, write to the Free Software
--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--
-- LOG
--     $Log:	percent.c,v $
X * Revision 1.1  91/05/06  15:23:24  dvadura
X * dmake Release Version 3.7
X * 
*/
X
#include "extern.h"
X
static DFAPTR _build_dfa ANSI((char *));
static char   _shift_dfa ANSI((DFAPTR, char *));
X
X
#define NO_ACTION	0
#define START_PERCENT	1
#define END_PERCENT	2
#define ACCEPT		4
#define FAIL           -1
X
static  NFAPTR _nfa = NIL( NFA );
X
X
PUBLIC DFALINKPTR
Match_dfa( buf )/*
==================
X   This routines runs all DFA's in parrallel and selects the one that best
X   matches the string.  If no match then it returns NIL( DFA ) */
char *buf;
{
X   register NFAPTR nfa;
X   int  	   adv;
X   DFALINKPTR	   dfa_list = NIL(DFALINK);
X
X   DB_ENTER( "Match_dfa" );
X   DB_PRINT( "dfa", ("Matching %s", buf) );
X
X   /* Run each of the DFA's on the input string in parallel, we terminate
X    * when all DFA's have either failed or ACCEPTED, if more than one DFA
X    * accepts we build a list of all accepting DFA's sorted on states with
X    * those matching in a higher numbered state heading the list. */
X
X   do {
X      adv = FALSE;
X
X      for( nfa = _nfa; nfa != NIL( NFA ); nfa = nfa->next )
X	 if( nfa->status != (char) FAIL && nfa->status != (char) ACCEPT ) {
X	    adv++;
X	    nfa->status = _shift_dfa( nfa->dfa, buf );
X
X	    /* Construct the list of matching DFA's */
X	    if( nfa->status == (char) ACCEPT ) {
X	       DFALINKPTR dl;
X
X	       TALLOC( dl, 1, DFALINK );
X	       dl->dl_meta  = nfa->dfa->node;
X	       dl->dl_per   = _substr( nfa->dfa->pstart, nfa->dfa->pend );
X	       dl->dl_state = nfa->dfa->states - nfa->dfa->c_state;
X
X	       if( dfa_list == NIL(DFALINK) )
X	          dfa_list = dl;
X	       else {
X		  DFALINKPTR tdli = dfa_list;
X		  DFALINKPTR tdlp = NIL(DFALINK);
X
X		  for( ; tdli != NIL(DFALINK); tdli = tdli->dl_next ) {
X		     if( dl->dl_state >= tdli->dl_state )
X			break;
X		     tdlp = tdli;
X		  }
X
X		  if( tdli != NIL(DFALINK) ) {
X		     tdli->dl_prev = dl;
X		     dl->dl_next   = tdli;
X		  }
X
X		  if( tdlp != NIL(DFALINK) ) {
X		     tdlp->dl_next = dl;
X		     dl->dl_prev   = tdlp;
X		  }
X		  else
X		     dfa_list = dl;
X	       }
X
X	       DB_PRINT( "dfa", ("Matched [%s]", dl->dl_meta->CE_NAME) );
X	    }
X	 }
X
X      buf++;
X   }
X   while ( adv );
X
X   for( nfa = _nfa; nfa != NIL( NFA ); nfa = nfa->next ) {
X      nfa->status = 0;
X      nfa->dfa->c_state = nfa->dfa->states;
X   }
X
X   DB_RETURN( dfa_list );
}
X
X
PUBLIC void
Check_circle_dfa()/*
====================
X   This function is called to test for circularities in the DFA lists
X   constructed from %-meta targets. */
{
X   register NFAPTR nfa;
X
X   for( nfa = _nfa; nfa != NIL(NFA); nfa = nfa->next )
X      if( Test_circle( nfa->dfa->node, FALSE ) )
X	 Fatal( "Detected circular dependency in inference graph at [%s]",
X		nfa->dfa->node->CE_NAME );
}
X
X
PUBLIC void
Add_nfa( name )/*
=================
X   Given name, build a DFA and add it to the NFA.  The NFA is maintained as
X   a singly linked list of DFA's. */
char *name;
{
X   NFAPTR nfa;
X
X   TALLOC(nfa, 1, NFA);
X   nfa->dfa = _build_dfa(name);
X
X   if( _nfa != NIL(NFA) ) nfa->next = _nfa;
X
X   _nfa = nfa;
}
X
X
static DFAPTR
_build_dfa( name )/*
====================
X   Construct a dfa for the passed in cell name.  The routine returns a struct
X   that represents a finite state machine that can recognize a regular
X   expression with exactly one '%' sign in it.  The '%' symbol is used as a
X   wildcard character that will match anything except the character that
X   immediately follows it or NUL.
X
X   The Construction of DFA's is well know and can be found in Hopcroft and
X   Ullman or any other book discussing formal language theory.
X   A more practical treatise can be found in Compilers, Aho, Sethi and Ullman.
*/
char *name;
{
X   DFAPTR   dfa;
X   int      nstates;
X   register STATEPTR sp;
X   STATEPTR per_state = NIL(STATE);
X   int      pcount=0;
X   int      end_percent=FALSE;
X
X   nstates = strlen(name)+2;
X
X   /* Allocate a DFA node and the right number of states. */
X   TALLOC(dfa, 1, DFA);
X   TALLOC(sp=dfa->c_state=dfa->states, nstates, STATE);
X   dfa->node = Def_cell( name );
X
X   /* Now construct the state table for the DFA */
X   do {
X      if( *name == '%' ) {
X	 if( pcount++ > 0 )
X	    Error( "Only one %% allowed within a %%-meta target" );
X
X	 sp->symbol   = 0;
X	 sp->action   = START_PERCENT;
X	 sp->no_match = sp->match = per_state = sp+1;
X	 end_percent  = TRUE;
X      }
X      else {
X	 sp->symbol   = *name;
X	 sp->no_match = per_state;
X
X	 if( *name == '\0' ) {
X	    sp->action = ACCEPT;
X	    sp->match  = dfa->states;
X	 }
X	 else {
X	    sp->action = NO_ACTION;
X	    sp->match  = sp+1;
X	 }
X
X	 if( end_percent ) {
X	    sp->action |= END_PERCENT;
X	    end_percent = FALSE;
X	 }
X      }
X      
X      sp++; 
X   }
X   while( *name++ );
X
X   return(dfa);
}
X
X
static char
_shift_dfa( dfa, data )/*
=========================
X   Take a given dfa and advance it based on the current state, the shift
X   action in that state, and the current data value. */
DFAPTR dfa;
char   *data;
{
X   register STATEPTR sp = dfa->c_state;
X   char c = *data;
X
X   /* Check if it is a START_PERCENT action if so then we need to save
X    * a pointer to the start of the string and advance to the next state. */
X   if( sp->action & START_PERCENT ) {
X      dfa->pstart = data;
X      sp++;
X   }
X
X   /* Now check if the current char matches the character expected in the
X    * current state.  If it does then perform the specified action, otherwise
X    * either shift it or fail.  We fail if the next state on no-match is
X    * NIL. */
X   if( sp->symbol == c ) {
X      if( sp->action & END_PERCENT ) dfa->pend = data;
X      if( sp->action & ACCEPT ) return(ACCEPT);
X      dfa->c_state = sp->match;
X   }
X   else if( (dfa->c_state = sp->no_match) == NIL(STATE) || !c )
X      return(FAIL);
X
X   return(NO_ACTION);
}
SHAR_EOF
chmod 0640 dmake/percent.c ||
echo 'restore of dmake/percent.c failed'
Wc_c="`wc -c < 'dmake/percent.c'`"
test 7050 -eq "$Wc_c" ||
	echo 'dmake/percent.c: original size 7050, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/quit.c ==============
if test -f 'dmake/quit.c' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/quit.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/quit.c' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/quit.c,v 1.1 91/05/06 15:23:25 dvadura Exp $
-- SYNOPSIS -- end the dmake session.
-- 
-- DESCRIPTION
-- 	Handles dmake termination.
--
-- AUTHOR
--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
--
-- COPYRIGHT
--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
-- 
--      This program is free software; you can redistribute it and/or
--      modify it under the terms of the GNU General Public License
--      (version 1), as published by the Free Software Foundation, and
--      found in the file 'LICENSE' included with this distribution.
-- 
--      This program is distributed in the hope that it will be useful,
--      but WITHOUT ANY WARRANTY; without even the implied warrant of
--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--      GNU General Public License for more details.
-- 
--      You should have received a copy of the GNU General Public License
--      along with this program;  if not, write to the Free Software
--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--
-- LOG
--     $Log:	quit.c,v $
X * Revision 1.1  91/05/06  15:23:25  dvadura
X * dmake Release Version 3.7
X * 
*/
X
#include "extern.h"
X
static	void	_handle_quit ANSI((char*));
static	int	_dont_quit = 0;
X
X
PUBLIC void
Quit()/*
======== Error or quit */
{
X   if( _dont_quit ) return;
SHAR_EOF
true || echo 'restore of dmake/quit.c failed'
fi
echo 'End of part 27, continue with part 28'
echo 28 > _shar_seq_.tmp
exit 0

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.