[comp.sys.ibm.pc] File concatenation using Microsoft C under MS-DOS?

gibbons@druco.ATT.COM (GibbonsT) (06/09/90)

Here's a problem I've been battling... any pointer would be
appreciated.

  What's the quickest way to concatenate one large file (~100K) to 
  another using Microsoft C under MS_DOS?  Write now I'm just opening 
  the two files and reading from one and append to the other, but it
  is rather slow.  The DOS "copy" command can do this much more 
  quickly using "copy A + B" but I can't figure out how to run
  "copy" from a C program.  I've tried calling "copy" with a 
  spawnl() command but that didn't work so i made a batch file
  that called copy and then tried to spawnl() the batch file,
  but that didn't work.  So, any suggestions? Any I overlooking
  something extremely obvious?

Thanks in advance,
Tom Gibbons,    gibbons@druco.att.com

silver@xrtll.uucp (Hi Ho Silver) (06/10/90)

In article <4891@druco.ATT.COM> gibbons@druco.ATT.COM (GibbonsT) writes:
$  What's the quickest way to concatenate one large file (~100K) to 
$  another using Microsoft C under MS_DOS?  Write now I'm just opening 
$  the two files and reading from one and append to the other, but it
$  is rather slow.  The DOS "copy" command can do this much more 
$  quickly using "copy A + B" but I can't figure out how to run
$  "copy" from a C program.  I've tried calling "copy" with a 
$  spawnl() command but that didn't work so i made a batch file
$  that called copy and then tried to spawnl() the batch file,
$  but that didn't work.  So, any suggestions? Any I overlooking
$  something extremely obvious?

   As far as trying to invoke a child process, you can't use spawn for
what you're trying:

- you can't spawn copy since it's ain internal command and spawn will
  only run .com and .exe commands

- you can't spawn a batch file since it requires command.com

   The ways around these are to use tye system() call, which passed
your argument to a copy of the command processor (basically, it comes up
with the equivalent of a spawn to "command /c your-commands-here").

   I assume your C solution involved simply reading the files one
character at a time.  This is not a good way to do it, since there's a
certain amount of overhead in each read you do and it adds up like crazy.
The way to do it is to find the commands in your implementation of C that
allow you to read and write large blocks at a time.  If memory serves,
the Turbo C calls are blockread() and blockwrite(), which will read and
write as much (up to 64K) of a file as you want them to.  This speeds
things up tremendously.  I'm sure MSC has equivalent calls.
-- 
   /Nikebo \ Nikebo says "Nikebo knows how to post.  Just do it."\silver@xrtll/
  /---------\_____________________________________________________\----------/
 /yunexus!xrtll!silver (L, not 1)\ Hi Ho Silver \   just silver for short   /
/Silver:  Ever Searching for SNTF \  Life sucks. \  someone buy me a BEER! /

count0@pnet51.orb.mn.org (Roy Silvernail) (06/11/90)

gibbons@druco.ATT.COM (GibbonsT) writes:
>
>  What's the quickest way to concatenate one large file (~100K) to 
>  another using Microsoft C under MS_DOS? [...]
>  I've tried calling "copy" with a 
>  spawnl() command but that didn't work 
 
I think you'll be able to do it with system(). 
--
Roy M. Silvernail | Imported from Alaska, where Hell really does freeze over!
"You'll be lookin' for me on another label!" (here's 3 of 'em...)
UUCP: {amdahl!bungia, uunet!rosevax, crash}!orbit!pnet51!count0
ARPA: crash!orbit!pnet51!count0@nosc.mil
INET: count0@pnet51.orb.mn.org

toma@tekgvs.LABS.TEK.COM (Tom Almy) (06/11/90)

[The question was how to concatenate files in the fastest manner].

Assuming you want to use stdio calls (using open, read, and write would be
fastest) do this

FILE *infile, *outfile;
#define BUFSIZE 32768 /* or some other large multiple of 512 */
char *cbuf;
int count;

infile = fopen(sourceFileName,"rb");	/* open in binary mode */
outfile = fopen(concatFileName,"ab");	/* same for destination file */
setbuf(infile,NULL);			/* Do your own buffering */
setbuf(outfile,NULL);
cbuf = malloc(BUFSIZE);

while ((count = fread(cbuf,sizeof(char),BUFSIZE,infile)) > 0)
	fwrite(cbuf,sizeof(char),count,outfile);

free(cbuf);
fclose(infile);
fclose(outfile);


It is important to both specify binary mode (to eliminate the crlf <-> \n
translation) and to use a large buffer, which is in turn better done by
yourself so a single buffer can be used.

Tom Almy
toma@tekgvs.labs.tek.com
Standard Disclaimers Apply

det@hawkmoon.MN.ORG (Derek E. Terveer) (06/12/90)

In article <4891@druco.ATT.COM> gibbons@druco.ATT.COM (GibbonsT) writes:
> 
> Here's a problem I've been battling... any pointer would be
> appreciated.
> 
>   What's the quickest way to concatenate one large file (~100K) to 
>   another using Microsoft C under MS_DOS?  Write now I'm just opening 
>   the two files and reading from one and append to the other, but it
>   is rather slow.

Its probably slow if you are either copying a character at a time or using a
small buffer.  Try allocating a large buffer.  Here is a set of useful
functions that we use in UUPC (you could use the append() function to append
the desired file -- see the man page (cp.tex)):


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	cp.tex
#	cp.c
#	mv.c
#	append.c
#	global.h
#	reverse_.c
#	getmem.c
#	lower.c
#	stripsla.c
#	ftrunc.c
# This archive created: Tue Jun 12 02:26:22 1990
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'cp.tex'" '(5069 characters)'
if test -f 'cp.tex'
then
	echo shar: "will not over-write existing file 'cp.tex'"
else
sed 's/^X//' << \SHAR_EOF > 'cp.tex'
X% @(#) cp.3 +9"
X% this is LaTeX
X% \input{../../tex/mymacros}
X\documentstyle{article}
X% \addtolength{\textwidth}{2.5in}
X% \addtolength{\textheight}{3in}
X% \setlength{\topmargin}{-1.6in}
X\begin{document}
X\pagestyle{mystyle}
X\markboth{CP(3)}{CP(3)}
X\begin{description}
X\item[NAME] \
X
Xcp, mv, append --- copy, move, and append files
X
X\item[SYNOPSIS] \
X
X\begin{em}
Xint cp(src,dst) \\
Xint mv(src,dst) \\
Xint append(src,dst)
X
Xchar *src; \\
Xchar *dst;
X
X\end{em}
X
X\item[DESCRIPTION] \
X
XThe {\em cp}, {\em mv}, and {\em append} functions provide simple, general-purpose file
Xcopy and move capabilities from within a C program.  
X{\em Mv} and {\em append} are front ends for {\em cp}, which is
Xthe workhorse function of the three.
XThe {\em src} and {\em dst} arguments are the source and destination path names,
Xrespectively,
Xof the files to be copied, moved, or appended.
XThese path names may be in either MS-DOS or Unix format.
XA source or destination name of
X"--" is considered to be the standard input or standard output, respectively.
X
XBy default, {\em cp} copies an entire source file to a destination file,
Xdestroying the original destination file in the process; the original source
Xfile remains pristine.  {\em Mv} does the same thing as {\em cp} but removes
Xthe original source file upon {\bf successfully} copying the file.  {\em Append}, as its name implies,
Xpresets the destination file's file pointer to the end of the file just before
Xthe copy is performed, thus causing copied data to be appended to the end of
Xthe
Xdestination file; the original source file is untouched.
X
XTo alter the default behaviour of {\em cp}, i.e., copying entire files,
Xone must call {\em cp} with the special
Xsource file name {\bf CPOFFSET}\footnote{The constant {\bf CPOFFSET} is
Xan impossible MS-DOS file name that is defined
Xin "global.h".} before calling {\em cp} again with the actual file names to be
Xcopied.  The changed behaviour of {\em cp}, effected by {\bf CPOFFSET}, remains
Xin effect until {\em cp} is called with real file names, after which {\em
Xcp}'s
Xbehaviour reverts back to the default.
XWhen called with {\em CPOFFSET},
X{\em Cp} interprets the {\em dst} argument as two
Xfile-offset, seek-type pairs, as follows:
X\begin{quote}
X\tt
X"srcoffset[,seektype] [dstoffset[,seektype]]"
X\end{quote}
XWhere {\tt srcoffset} is the offset, in bytes, of the source file pointer and
X{\tt dstoffset} is the offset, in bytes, of the destination file pointer.
X{\tt Seektype} is
Xthe type of seek to perform for each of the two file pointers and
Xmay be one of
X"0", "1", or "2", where "0" indicates an absolute offset (from the beginning of
Xthe file), "1" indicates a
Xrelative offset (from the current position of the file pointer), and "2"
Xindicates an offset from the end of the file.\footnote{These same byte offset
Xand seek type
Xarguments are passed, without change, to {\em lseek}(2).}
XThe brackets are not entered literally, but, rather, indicate that the destination offset, {\tt dstoffset}, is optional, as are the {\tt seektype} arguments.
XThe default for all values is zero, i.e., each file pointer is reset to the beginning
Xof the file before a copy.  Thus, in the absence of an explicit call to {\em
Xcp} with {\bf CPOFFSET}
Xspecifying the desired file pointer offsets, it is as if one had coded:
X\begin{quote}
X\tt
Xcp(CPOFFSET,"0,0 0,0");
Xcp(src,dst);
X\end{quote}
X
X\item[EXAMPLE] \
X
X\begin{quote}
X\tt
Xchar src[BUFSIZ]; \\
Xchar dst[BUFSIZ]; \\
Xchar dst2[BUFSIZ]; \\
X/* prompt the user for a file name */ \\
Xprintf("Enter source file name: "); \\
Xgets(src); \\
Xtmpnam(dst); \\
X/* copy the source file to a temp file */ \\
Xcp(src,dst); \\
X/* now move the just copied tmp file to another location */ \\
Xprintf("Enter a tmp file name: "); \\
Xgets(dst2); \\
Xmv(dst,dst2); \\
X/* append the file to a log file */ \\
Xappend(dst2,"/usr/users/biffy/mylog"); \\
X/* now copy the source file starting at byte 100 \\
X * to the middle of the dst file */ \\
Xsprintf(dst2,"100 154000"); \\
Xcp(CPOFFSET,dst2); \\
Xcp(src,dst); \\
X\end{quote}
X
X\item[EXIT STATUS] \
X
XSUCCESS (i.e., 0) for success, various non-zero values for failure.
X
X\item[SEE ALSO] \
X
X{\em memavl}(3),
X{\em memmax}(3),
X{\em chmod}(2),
X{\em lseek}(2),
X{\em open}(2),
X{\em rename}(2),
X{\em setmode}(3),
X{\em stat}(2),
X{\em utime}(2)
X
X\item[DIAGNOSTICS] \
X
Xcp: can't copy {\it src} to itself! \\
Xcp: can't reset stdin! \\
Xcp: can't open {\it src} \\
Xcp: out of memory! \\
Xcp: out of memory! using emergency tiny buffer (64 bytes) \\
Xcp: can't reset stdout! \\
Xcp: can't create {\it dst} \\
Xcp: requested src lseek(x,y) failed! \\
Xcp: requested dst lseek(x,y) failed! \\
Xmv: no such file or directory
X
X\item[CAVEATS] \
X
XIt is possible that the memory allocation scheme employed by {\em cp} may
Xnot be very friendly in
Xa multi-tasking environment\footnote{E.g. {\em windows}}
Xsince it allocates just about every single byte it
Xcan get its filthy paws on.  {\em Cp} assumes that it is the
Xonly process running.
X
X\item[AUTHORS] \
X
XDerek Terveer (det@hawkmoon.MN.ORG) \\
XJoel Melohn (joelm@nightowl.MN.ORG)
X
X\end{description}
X\end{document}
SHAR_EOF
if test 5069 -ne "`wc -c < 'cp.tex'`"
then
	echo shar: "error transmitting 'cp.tex'" '(should have been 5069 characters)'
fi
fi
echo shar: "extracting 'cp.c'" '(6579 characters)'
if test -f 'cp.c'
then
	echo shar: "will not over-write existing file 'cp.c'"
else
sed 's/^X//' << \SHAR_EOF > 'cp.c'
X#define	MINOR "@(#) cp.c +55"
X#ifdef	SCCS
X static	char		       *stampcp		=	"@(#)cp.c	2.4";
X#ifndef	NOMINOR
X static	char		       *stamp_cp	=	MINOR;
X#endif
X#ifdef	DEBUG
X static	char		       *stamp_cp_debug	=	"@(#)debug";
X#endif
X#endif
X#undef	MINOR
X
X/* cp("-",destfile)	copies from stdin to destfile.
X * cp(srcfile,"-")	copies from srcfile to stdout.
X *
X * Before copying, cp() may be called with special file names that modify its
X * future actions:
X *
X *	cp(CPOFFSET,"srcoffset[,seektype][ dstoffset[,seektype]]")
X * defaults:		0	   SET	      0		 SET
X *
X * SEEK_SET = 0
X * SEEK_CUR = 1
X * SEEK_END = 2
X *
X * The CPOFFSET is an impossible file name in ms-dos and is defined in global.h.
X */
X
X#ifdef	MSDOS
X#include			<stdio.h>
X#include			<stdlib.h>
X#include			<fcntl.h>
X#include			<sys/types.h>
X#include			<sys/stat.h>
X#include			<io.h>
X#include			<string.h>
X#include			<malloc.h>
X#include			"global.h"
X#endif
X
Xint
Xcp(src,dst)
X
X	char		       *src;
X	char		       *dst;
X
X{
X#ifdef	MSDOS
X	char		       *buf;
X	size_t			bufsize;
X extern	int			debuglevel;
X static	long			dstoffset		=	0L;
X static	int			dstseektype		=	SEEK_SET;
X static	char			emergency[64];
X	int		     	fdst;
X	char		       *finaldst;
X	int		        fsrc;
X	boolean			fstdin			=	FALSE;
X	boolean			fstdout			=	FALSE;
X extern	char		       *getmem();
X extern	char		       *lower();
X	unsigned		minsize;
X	int			oldmode;
X	char		       *p;
X static	char			PID			=	"cp";
X unsign	int			r;
X static	long			srcoffset		=	0L;
X static	int			srcseektype		=	SEEK_SET;
X	int			st;
X	struct	stat	        stbuf;
X unsign	int			w;
X#else
X	char			cmd[BUFSIZ];
X#endif
X	char	control[32];
X
X
X#ifdef	MSDOS
X lower(src);
X#ifdef	DEBUG
X if (debuglevel>2) fprintf(stderr,"%s(%s,%s)\n",PID,src,dst);
X#endif
X if (strcmp(src,CPOFFSET)==SAME)
X   then
X    {char	*q;
X
X#ifdef	DEBUG
X     if (debuglevel>4) fprintf(stderr,"special file: %s\n",src);
X#endif
X     strcpy(control, dst);
X     if ((p=strchr(control,SPACE))) *p='\0';
X     if ((q=strchr(control,COMMA))) *q='\0';
X     srcoffset=atol(control);
X     if (q) srcseektype=atoi(q+1);
X     if (p++)
X       then
X	{if ((q=strchr(p,COMMA))) *q='\0';
X 	 dstoffset=atol(p);
X         if (q) dstseektype=atoi(q+1);
X	}
X       else dstoffset=0L;
X#ifdef	DEBUG
X     if (debuglevel>4) fprintf(stderr,"%s: request srcoffset %ld/%d dstoffset %ld/%d\n",PID,srcoffset,srcseektype,dstoffset,dstseektype);
X#endif
X     return(SUCCESS);
X    }
X lower(dst);
X if (strcmp(src,dst)==SAME && strcmp(src,"-")!=SAME)
X   then
X    {fprintf(stderr,"%s: can't copy %s to itself!\n",PID,src);
X     return(2);
X    }
X if ((fsrc=open(src,O_BINARY|O_RDONLY))==FAIL)
X   then
X    {if (strcmp(src,"-")==SAME)
X       then
X  	{fsrc=fileno(stdin);
X  	 if ((oldmode=setmode(fsrc,O_BINARY))==FAIL)
X  	   then
X  	    {perror(PID);
X	     fprintf(stderr,"%s: can't reset stdin!\n",PID);
X  	     return(FAIL);
X  	    }
X  	 fstdin=TRUE;
X  	}  /* - */
X       else
X        {perror(PID);
X	 fprintf(stderr,"%s: can't open %s\n",PID,src);
X         return(1);
X        }  /* src is - */
X    }  /* open src */
X if (!fstdin) fstat(fsrc,&stbuf);
X r=strlen(dst);
X /* calculate absolute min memory needed for writing path names
X  */
X if ((p=strrchr(src,SLASH)))
X   then r=minsize=r+strlen(p)+1;
X   else r=minsize=r+strlen(src)+2;
X /* now calculate desirable min memory
X  */
X if (fstdin)
X   then minsize=max(minsize,_memmax());
X   else minsize=max(minsize,stbuf.st_size);
X /* can this desired min be satisfied by the static buffer?
X  */
X if (minsize<=sizeof(emergency))
X   then
X    {buf=emergency;
X     bufsize=sizeof(emergency);
X#ifdef	DEBUG
X     if (debuglevel>7) printf("%s: static buffer satisfies memory need, use it instead of getmem(%u)\n",PID,minsize);
X#endif
X    }
X   else  /* no.. must allocate some memory */
X    {
X#ifdef	DEBUG
X     if (debuglevel>8)
X       then
X	{printf("%s: before getmem(): size=%ld",PID,stbuf.st_size);
X	 /* the following statement hangs the PC!  The only difference between
X	  * this and the next one (that works) is the leading underscore "_" on
X	  * memavl in the format string... very strange.
X	  * A  msc5.1 bug????
X	 printf(" _memavl()=%u",_memavl());
X	  */
X	 printf(" memavl()=%u",_memavl());
X	 printf(" _memmax()=%u\n",_memmax());
X	}
X#endif
X     if (!(bufsize=_memmax()) ||
X	 !(buf=getmem((bufsize=min(bufsize,minsize)))))
X       then
X        {fprintf(stderr,"%s: out of memory! ",PID);
X	 if (r>sizeof(emergency))
X           then
X            {fputc('\n',stderr);
X             return(FAIL);
X            }
X 	 fprintf(stderr,"using emergency tiny buffer (%d bytes)\n",sizeof(emergency));
X         buf=emergency;
X         bufsize=sizeof(emergency);
X        }  /* no memory */
X#ifdef	DEBUG
X     if (debuglevel>7) printf("%s: after getmem(): bufsize=%u _memavl()=%u _memmax()=%u\n",PID,bufsize,_memavl(),_memmax());
X#endif
X    }  /* allocate */
X if (strcmp(dst,"-")==SAME)
X   then
X    {fdst=fileno(stdout);
X     if ((oldmode=setmode(fdst,O_BINARY))==FAIL)
X       then
X  	{perror(PID);
X	 fprintf(stderr,"%s: can't reset stdout!\n",PID);
X  	 return(FAIL);
X  	}
X     fstdout=TRUE;
X    }  /* - */
X   else
X    {/* destination is a directory */
X     if (!stat(dst,&stbuf) && stbuf.st_mode&S_IFDIR)
X       then
X        {if ((p=strrchr(src,SLASH)))
X           then sprintf(buf,"%s/%s",dst,p+1);
X           else sprintf(buf,"%s/%s",dst,src);
X         finaldst=buf;
X        }
X       else finaldst=dst;
X     if (!dstoffset && dstseektype==SEEK_SET) unlink(finaldst);
X     if ((fdst=open(finaldst,O_BINARY|O_CREAT|O_WRONLY,0666))==FAIL)
X       then
X        {perror(PID);
X         free(buf);
X         if (!fstdin) close(fsrc);
X         fprintf(stderr,"%s: can't create %s\n",PID,finaldst);
X         return(1);
X        }
X    }  /* ! stdout */
X if (lseek(fsrc,srcoffset,srcseektype)==FAIL)
X   then fprintf(stderr,"%s: requested src lseek(%ld,%d) failed!\n",PID,srcoffset,srcseektype);
X if (lseek(fdst,dstoffset,dstseektype)==FAIL)
X   then fprintf(stderr,"%s: requested dst lseek(%ld,%d) failed!\n",PID,dstoffset,dstseektype);
X while ((r=read(fsrc,buf,bufsize))>0)
X  {w=write(fdst,buf,r);
X   if (w!=r)
X     then
X      {perror(PID);
X       free(buf);
X       if (!fstdin) close(fsrc);
X       close(fdst);
X       return(4);
X      }
X  }
X free(buf);
X#ifdef	DEBUG
X if (debuglevel>8) printf("%s: after free(): _memavl()=%u, _memmax()=%u\n",PID,_memavl(),_memmax());
X#endif
X if (!fstdin) close(fsrc);
X if (fstdin) setmode(fsrc,oldmode);
X close(fdst);
X if (r<0)
X   then
X    {perror(PID);
X     return(5);
X    }
X srcoffset=dstoffset=0L;
X srcseektype=dstseektype=SEEK_SET;
X return(SUCCESS);
X#else
X sprintf(cmd,"%s %s %s",PID,src,dst);
X return(system(cmd));
X#endif
X}  /* cp */
SHAR_EOF
if test 6579 -ne "`wc -c < 'cp.c'`"
then
	echo shar: "error transmitting 'cp.c'" '(should have been 6579 characters)'
fi
fi
echo shar: "extracting 'mv.c'" '(3755 characters)'
if test -f 'mv.c'
then
	echo shar: "will not over-write existing file 'mv.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mv.c'
X#define	MINOR "@(#) mv.c +52"
X#if defined(SCCS)
X static	char		       *stampmv		=	"@(#)mv.c	2.10";
X#if !defined(NOMINOR)
X static	char		       *stamp_mv	=	MINOR;
X#endif
X#if defined(DEBUG)
X static	char		       *stamp_mv_debug	=	"@(#)debug";
X#endif
X#endif
X#undef	MINOR
X
X#if defined(DEBUG)
X#include			<stdio.h>
X#else
X#define	NULL		0
X#endif
X#if defined(MSDOS)
X#include			<string.h>
X#include			<sys/types.h>
X#include			<sys/stat.h>
X#include			<sys/utime.h>
X#include			<fcntl.h>
X#include			"global.h"
X#endif
X
Xint
Xmv(src,dst)
X
X	char		       *src;
X	char		       *dst;
X
X{extern	char		       *append_file_to_path();
X#if !defined(MSDOS)
X	char			cmd[BUFSIZ];
X#endif
X#if defined(DEBUG)
X extern	int			debuglevel;
X#endif
X#if defined(MSDOS)
X	struct	stat	       	dstbuf;
X extern	char		       *getmem();
X regist	int			i;
X	struct	utimbuf		mtime;
X	char		       *newdst			=	NULL;
X regist	char		       *pd;
X regist	char		       *ps;
X	boolean			Rename			=	FALSE;
X	struct	stat	        srcbuf;
X extern	char		       *reverse_slashes();
X extern	char		       *strip_superfluous_slashes();
X#endif
X
X#if defined(DEBUG)
X if (debuglevel>3) fprintf(stderr,"mv(%s,%s)\n",src,dst);
X#endif
X
X#if defined(MSDOS)
X strip_superfluous_slashes(src,FALSE);
X strip_superfluous_slashes(dst,FALSE);
X
X /* source must exist before anything can be done
X  */
X if (stat(src,&srcbuf)) {perror("mv"); return(FAIL);}
X 
X /* if destination doesn't exist, create a bogus destination file
X  */
X if (stat(dst,&dstbuf))
X   then
X    {if ((i=open(dst,O_CREAT,S_IWRITE))==FAIL) {perror(dst); return(FAIL);}
X     fstat(i,&dstbuf);
X     close(i);
X    }
X
X /* We can rename the source file (instead of copying and deleting) if:
X  *	Its a file and both src and dst are on the same device, or
X  *	Its a directory and both src and dst are in the same directory (and
X  *	hence, on the same device
X  */
X if (srcbuf.st_dev==dstbuf.st_dev)
X   then
X    {reverse_slashes(src);
X     if (srcbuf.st_mode&S_IFREG)
X       then
X        {Rename=TRUE;
X         if (newdst=append_file_to_path(dst,src,dstbuf.st_mode&S_IFDIR)) dst=newdst;
X         unlink(dst);
X        }  /* file */
X       else if (srcbuf.st_mode&S_IFDIR)
X         then
X          {reverse_slashes(dst);
X	   if ((ps=strrchr(src,SLASH))) *ps='\0';
X	   if ((pd=strrchr(dst,SLASH))) *pd='\0';
X	   if (strcmp(src,dst)==SAME) Rename=TRUE;
X	   if (ps) *ps=SLASH;
X	   if (pd) *pd=SLASH;
X	   if (Rename) rmdir(dst);
X          }  /* dir */
X    }  /* same device */
X
X if (Rename)
X   then
X    {i=rename(src,dst);
X     if (newdst) free(newdst);
X     return(i);
X    }
X   else
X    {if ((i=cp(src,dst))) return(i);
X     mtime.modtime=srcbuf.st_mtime;
X     if (newdst=append_file_to_path(dst,src,dstbuf.st_mode&S_IFDIR)) dst=newdst;
X#if defined(DEBUG)
X     if (debuglevel > 4) printf("dst=`%s'\tnewdst=`%s'\n",dst,newdst);
X#endif
X     if (utime(dst,&mtime))
X       then
X        {if (dstbuf.st_mode&S_IWRITE)
X           then perror(dst);
X           else
X            {chmod(dst,S_IWRITE);
X             if (utime(dst,&mtime)) perror(dst);
X             chmod(dst,S_IREAD);
X            }  /* r/o */
X        }  /* couldn't reset mtime */
X     if (newdst) free(newdst);
X     unlink(src);
X    }  /* cp */
X return(SUCCESS);
X#else
X sprintf(cmd,"mv %s %s",src,dst);
X return(system(cmd));
X#endif
X}  /* mv */
X
Xchar *
Xappend_file_to_path(path,file,dir)
X
X	char		       *path;
X	char		       *file;
X	boolean			dir;	/* t if path is a dir */
X
X{	char		       *newpath;
X	char		       *p;
X
X if (dir)
X   then
X    {if ((p=strrchr(file,SLASH))) ++p; else p=file;	/* get basename */
X     if (!(newpath=getmem(strlen(path)+1+strlen(p)+1)))
X       then exit(FAIL);
X       else
X        {sprintf(newpath,"%s/%s",path,p);
X     	 return(newpath);
X        }
X    }  /* dst is a dir */
X return(NULL);
X}  /* append_file_to_path */
SHAR_EOF
if test 3755 -ne "`wc -c < 'mv.c'`"
then
	echo shar: "error transmitting 'mv.c'" '(should have been 3755 characters)'
fi
fi
echo shar: "extracting 'append.c'" '(554 characters)'
if test -f 'append.c'
then
	echo shar: "will not over-write existing file 'append.c'"
else
sed 's/^X//' << \SHAR_EOF > 'append.c'
X#define	MINOR "@(#) append.c +2"
X#if defined(SCCS)
X static	char		       *stampappend		=	"@(#)append.c	2.2";
X#ifndef	NOMINOR
X static	char		       *stamp_append		=	MINOR;
X#endif
X#if defined(DEBUG)
X static	char		       *stamp_append_debug	=	"@(#)debug";
X#endif
X extern	char		       *stamp_sum_version;
X#endif
X#undef	MINOR
X
X#include			<stdio.h>
X#include			"global.h"
X
Xint
Xappend(src,dst)
X
X	char		       *src;
X	char		       *dst;
X
X{	char			buf[6];
X extern	int			cp();
X
X sprintf(buf,"0 0,%d",SEEK_END);
X cp(CPOFFSET,buf);
X return(cp(src,dst));
X}  /* append */
SHAR_EOF
if test 554 -ne "`wc -c < 'append.c'`"
then
	echo shar: "error transmitting 'append.c'" '(should have been 554 characters)'
fi
fi
echo shar: "extracting 'global.h'" '(3327 characters)'
if test -f 'global.h'
then
	echo shar: "will not over-write existing file 'global.h'"
else
sed 's/^X//' << \SHAR_EOF > 'global.h'
X#define	MINOR "@(#) global.h +84"
X#if defined(SCCS)
X static char    *stampglobal_h  =       "@(#)global.h	2.10";
X#if !defined(NOMINOR)
X static char    *stamp_global_h =       MINOR;
X#endif
X#endif
X#undef	MINOR
X
X#include			<ctype.h>
X
X#define	ALL		-1
X#define	ASTERISK	'*'
X#define	AT		'@'
X#define	BACKSLASH	'\\'
X#define	BACKWARD	-1
X#define	BANG		'!'
X#define	BINARYMODE	'b'
X#define	BOTH		0
X#define	COLON		':'
X#define	COMMA		','
X#define	COMMAND_MODE	0
X#define	COMMENT		'#'
X#define	COMPOSE_ESCAPE  TILDE
X#define	COPYFILE	"Mail/MailSent"
X#define	CORRUPT		"_Corrupt"
X#define	CPOFFSET	".offset"	/* offset flag for cp() */
X#define	CR		'\r'
X#define	CRONTABS	"cron/crontabs"
X#define	CRONLASTTIME	"cron/lasttime"
X#define	CWDSIZE		66
X#define	DASH		'-'
X#define	DEADFILE	"dead.let"
X#define	DIGITS		"0123456789"
X#define	DIGITSANDSPACE	"0123456789 "
X#define	DOLLAR		'$'
X#define	DOT		'.'
X#define	DRIVE_SELECT	COLON
X#define	EXISTS		0
X#define	FAIL		-1
X#define	FAILED		-1
X#define	FALSE		0
X#define	FIRST		0
X#define	FORWARD		"Forward to"
X#define	GETTYDEFS       "gettydefs"
X#define	GRADE_LP        'p'             /* grade for lp files */
X#define	GRADE_MAIL      'f'             /* grade for mail */
X#define	GRADE_NEWS      'u'             /* grade for news files */
X#define	GRADE_UUTO      'k'             /* grade for uuto'd files */
X#define	GREATER_THAN	'>'
X#define	HELPFILE	"c:/usr/lib/mail/help"
X#define	H_FORWARD	1
X#define	INPUT_MODE	1
X#define	KILOBYTE	1024
X#define	LAST		1
X#define	LEFT_PAREN	'('
X#define	LESS_THAN	'<'
X#define	LOGFILE		"LOGFILE"
X#define	MAILWIDTH	80		/* max width for headers in mail */
X#define	MASTER		1
X#define	MAXDOSPATH	140	/* max path name in dos, comprising drive
X				 * prefix, full directory path, and final
X				 *  file name
X				 */
X#define	MAXLETTERS	400
X#define	MAXRANGE	30
X#define	MAXREPLIES	100
X#define	MAXSEQLEN	6
X#define	MBOXFILE	"mbox"
X#define	MEGABYTE	1048576
X#define	NEW		3
X#define	NONE		0
X#define	NOSCROLL	0
X#define	PASSWD		"passwd"
X#define	PERCENT		'%'
X#define	PIPE		'|'
X#define	PLUS		'+'
X#define	QUOTE		'"'
X#define	READ		2
X#define	READABLE        4
X#define	RIGHT_PAREN	')'
X#define	SAME		0
X#define	SBUFSIZ		124
X#define	SCROLL		1
X#define	SECS_PER_DAY	86400
X#define	SECS_PER_HOUR	3600
X#define	SEMICOLON	';'
X#define	SEPCHAR		'/'
X#define	SFILENAME	"SEQF"
X#define	SLASH		'/'
X#define	SLAVE		0
X#define	SPACE		' '
X#define	STDOUT		2
X#define	SUCCESS		0
X#define	SYSTEMS		"Systems"
X#define	TAB		'	'
X#define	TEXTMODE	't'
X#define	TFILENAME	"%.8ld.Tmp"   /* nnnnnnnn.Tmp */
X#define	TILDE		'~'
X#define	TRUE		1
X#define	UNDERSCORE	'_'
X#define	UNREAD		1
X#define	WHITE  		" 	"	/* MUST have a space and a tab! */
X#define	WRITABLE        1
X#define	XMAILER		"X-Mailer: "  	/* mailer version header */
X#define	XQTDIR		"_Xqtdir"
X#define	XREQACK		"X-Acknowledgement-To: "  /* reqack mail header */
X#define	boolean		short
X#define	drivespec(path)	(isalpha(*(path)) && *(path+1)==DRIVE_SELECT)
X#define	fullpath(path)	(drivespec(path) && (*(path+2)==SLASH||(*(path+2)==BACKSLASH)) || !drivespec(path) && (*path==SLASH||*path==BACKSLASH))
X#define	plural(i)	((i)==1?"":"s")
X#define	reg		register
X#define	regist		register
X#define	relpath(path)	(drivespec(path) && *(path+2)!=SLASH || !drivespec(path) && *path!=SLASH)
X#define	then
X#define	unsign		unsigned
X#define max(x,y)	(((x) > (y)) ? (x) : (y))
X#define min(x,y)	(((x) < (y)) ? (x) : (y))
SHAR_EOF
if test 3327 -ne "`wc -c < 'global.h'`"
then
	echo shar: "error transmitting 'global.h'" '(should have been 3327 characters)'
fi
fi
echo shar: "extracting 'reverse_.c'" '(312 characters)'
if test -f 'reverse_.c'
then
	echo shar: "will not over-write existing file 'reverse_.c'"
else
sed 's/^X//' << \SHAR_EOF > 'reverse_.c'
X#define MINOR "@(#) reverse_.c +2"
X#ifdef SCCS
X static	char	*stampreverse_slashes	=	"@(#)";
X#ifndef NOMINOR
X static	char	*stamp_reverse_slashes	=	MINOR;
X#endif
X#endif
X
Xchar *reverse_slashes(s)
X
Xchar	*s;
X
X{char	*p;
X 
X for (p=s; *p; ++p) if (*p=='\\') *p='/';
X return(p);
X}  /* reverse_slashes */
SHAR_EOF
if test 312 -ne "`wc -c < 'reverse_.c'`"
then
	echo shar: "error transmitting 'reverse_.c'" '(should have been 312 characters)'
fi
fi
echo shar: "extracting 'getmem.c'" '(767 characters)'
if test -f 'getmem.c'
then
	echo shar: "will not over-write existing file 'getmem.c'"
else
sed 's/^X//' << \SHAR_EOF > 'getmem.c'
X#define	MINOR "@(#) getmem.c +20"
X#if defined(SCCS)
X static	char		       *stampgetmem		=	"@(#)getmem.c	2.4";
X#ifndef	NOMINOR
X static	char		       *stamp_getmem		=	MINOR;
X#endif
X#if defined(DEBUG)
X static	char		       *stamp_getmem_debug	=	"@(#)debug";
X#endif
X#endif
X#undef	MINOR
X
X#include			<stdio.h>
X
Xchar *
Xgetmem(bytes)
X
X	int			bytes;
X
X{
X#if defined(DEBUG)
X extern	int			debuglevel;
X#endif
X extern	char		       *malloc();
X	char		       *p;
X
X#if defined(DEBUG)
X if (debuglevel>30) fprintf(stderr,"getmem(%u), ",(unsigned)bytes);
X#endif
X if (!(p=malloc((unsigned)bytes))) fprintf(stderr,"getmem: can't allocate %u bytes!\n",(unsigned)bytes);
X#if defined(DEBUG)
X if (debuglevel>40) printf("address returned from malloc = %x\n", p);
X#endif
X return(p);
X}  /* getmem */
SHAR_EOF
if test 767 -ne "`wc -c < 'getmem.c'`"
then
	echo shar: "error transmitting 'getmem.c'" '(should have been 767 characters)'
fi
fi
echo shar: "extracting 'lower.c'" '(277 characters)'
if test -f 'lower.c'
then
	echo shar: "will not over-write existing file 'lower.c'"
else
sed 's/^X//' << \SHAR_EOF > 'lower.c'
X#define MINOR "@(#) lower.c +5"
X#ifdef SCCS
X static	char	*stamplower	=	"@(#)lower.c	2.2";
X#ifndef NOMINOR
X static	char	*stamp_lower	=	MINOR;
X#endif
X#endif
X
X#include		<ctype.h>
X
Xchar *lower(s)
X
Xchar	*s;
X
X{char	*p;
X
X for (p=s; *p; ++p) *p=tolower(*p);
X return(s);
X}  /* lower */
SHAR_EOF
if test 277 -ne "`wc -c < 'lower.c'`"
then
	echo shar: "error transmitting 'lower.c'" '(should have been 277 characters)'
fi
fi
echo shar: "extracting 'stripsla.c'" '(990 characters)'
if test -f 'stripsla.c'
then
	echo shar: "will not over-write existing file 'stripsla.c'"
else
sed 's/^X//' << \SHAR_EOF > 'stripsla.c'
X#define MINOR "@(#) stripsla.c +1"
X#if defined(SCCS)
X static	char	  	       *stampstrip_superfluous_slashes	=	"@(#)stripsla.c	1.2";
X#if !defined(NOMINOR)
X static	char		       *stamp_strip_superfluous_slashes	=	MINOR;
X#endif
X#if defined(DEBUG)
X static	char		       *stamp_strip_superfluous_debug	=	"@(#)debug";
X#endif
X#endif
X#undef	MINOR
X
X#include			"global.h"
X
X/* Strip multiple superfluous slashes from a path name.
X * Dos 2.11 chokes on path names that
X * contain concatenated slashes... unix just ignores these.
X *
X * /usr/spool/uucppublic/receive/root//ihnp4/testfile
X * 	gets converted to:
X * /usr/spool/uucppublic/receive/root/ihnp4/testfile
X */
X
Xchar *
Xstrip_superfluous_slashes(path,keep_last_slash)
X
X	char		        path[];
X	boolean			keep_last_slash;
X
X{
X	char		       *p;
X	char		       *q;
X
X for (p=q=path+1; *p; ++p)
X  {if (*p!=SLASH || *(p-1)!=SLASH) *q++ = *p;
X  }
X if (keep_last_slash && *(p-1)==SLASH) *q++ = SLASH;
X *q='\0';
X return(path);
X}  /* strip_superfluous_slashes */
SHAR_EOF
if test 990 -ne "`wc -c < 'stripsla.c'`"
then
	echo shar: "error transmitting 'stripsla.c'" '(should have been 990 characters)'
fi
fi
echo shar: "extracting 'ftrunc.c'" '(2091 characters)'
if test -f 'ftrunc.c'
then
	echo shar: "will not over-write existing file 'ftrunc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ftrunc.c'
X#define	MINOR "@(#) ftrunc.c +20"
X#if defined(SCCS)
X static	char	*stampftrunc		=	"@(#)ftrunc.c	2.2";
X#ifndef	NOMINOR
X static	char	*stamp_ftrunc		=	MINOR;
X#endif
X#if defined(DEBUG)
X static	char	*stamp_ftrunc_debug	=	"@(#)debug";
X#endif
X#endif
X#undef	MINOR
X
X#include			<stdio.h>
X#include			<dos.h>
X#include			<fcntl.h>
X#include			"global.h"
X
X/*
X * Truncate a file with fileno "handle" to byte "offset" relative to the given
X * origin, "org".
X */
X
Xint
Xftrunc(handle,offset,org)
X
X	int			handle;
X	long			offset;
X	int			org;
X
X{
X void	far		       *buf;
X#if defined(DEBUG)
X extern	int			debuglevel;
X#endif
X	int			errcode;
X union	REGS			inregs;
X union	REGS			outregs;
X static	char		       *pid			=	"ftrunc";
X unsign	int			written;
X
X   /*
X   if (_dos_open(path,O_RDWR,&handle)!=0)
X     then
X      {perror(pid);
X       printf("%s: can't open `%s'\n",pid,path);
X       return(FAIL);
X      }
X#if defined(DEBUG)
X   if (debuglevel>13) printf("%s: handle=%d\n",pid,handle);
X#endif
X    */
X
X   /* seek to offset */
X   inregs.h.ah = 0x42;
X   inregs.h.al = org;
X   inregs.x.bx = handle;
X   inregs.x.cx = (offset & 0xFFFF0000) >> 16;
X   inregs.x.dx = offset & 0x0000FFFF;
X#if defined(DEBUG)
X   if (debuglevel>13) printf("%s: offset=%ld, cx=%u dx=%u\n",pid,offset,inregs.x.cx,inregs.x.dx);
X   intdos(&inregs,&outregs);
X#endif
X   if (errcode=outregs.x.cflag ? outregs.x.ax : 0)
X     then
X      {printf("%s: can't seek to %ld from %d, errcode=%d\n",pid,offset,org,errcode);
X       return(errcode);
X      }
X#if defined(DEBUG)
X   if (debuglevel>13) printf("%s: seek successful; now at dx=%u ax=%u\n",pid,outregs.x.dx,outregs.x.ax);
X#endif
X
X /* now truncate the file */
X   if (_dos_write(handle,buf,(unsigned)0,&written)!=0)
X     then
X      {perror(pid);
X       printf("%s: can't write to file\n",pid);
X       return(FAIL);
X      }
X#if defined(DEBUG)
X   if (debuglevel>13) printf("%s: bytes written=%u\n",pid,written);
X#endif
X
X /* close file */
X /*
X   if (_dos_close(handle)!=0)
X     then
X      {perror(pid);
X       printf("%s: can't close file\n",pid);
X       return(FAIL);
X      }
X */
X return(SUCCESS);
X} /*ftrunc*/
SHAR_EOF
if test 2091 -ne "`wc -c < 'ftrunc.c'`"
then
	echo shar: "error transmitting 'ftrunc.c'" '(should have been 2091 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
Derek Terveer		det@hawkmoon.MN.ORG