From:	SMTP%"RELAY-INFO-VAX@CRVAX.SRI.COM" 23-SEP-1993 18:56:30.50
To:	EVERHART
CC:	
Subj:	RE: need vms way to split large file to many smaller; like unix "split"

Message-Id: <9309191713.AA02947@uu3.psi.com>
Date: Sun, 19 Sep 93 13:00:56 EDT
From: Jerry Leichter <leichter@lrw.com>
To: INFO-VAX@sri.com
Subject: RE: need vms way to split large file to many smaller; like unix "split"
X-Vms-Mail-To: UUCP%"swcramer@silver.ucs.indiana.edu"

	I have a large file on VMS, that I can not pull into any of the
	editors.  I am looking for a way to split the file up into smaller,
	more manageable files.  I know there is a command on unix "split -n"
	that will perform this task but I am looking for a way to do this same
	task within VMS without having to transfer the file over to unix.

split is a really trivial utility.  Here's the DECUS splita program.  It was
originally written to split DECUS archives, but I long ago modified it to do
general "splitting" operations.  Note that it will not produce useful results
for "binary" files.

(Note:  This code uses the DECUS C getredirection() package.  That's been
distributed so many times before that I haven't included it.  If you don't
have it, just comment out the line that calls getredirection(); the only
thing you'll loose is the ability to redirect the progress messages.)

							-- Jerry

/*
 * Split an archive or text file into managable pieces.
 */

/*)BUILD	$(TKBOPTIONS) = {
			TASK	= ...SPA
		}
*/

#ifdef	DOCUMENTATION

title	splita	Split an Archive or Text File into Smaller Pieces
index		Split an archive or text file into smaller pieces

synopsis

	splita [-byte_limit] [-f[m]] input_file output_model

description

	Splits a file into smaller files (output_model.001, etc.).  By
	default, the file is a DECUS C archive, in which case splits will
	occur at the end of archive elements, and an identifying header,
	which describes the contents of the file and which archx will
	interpret as calling for the creation of an empty file on the null
	device, will be inserted at the beginning of each file produced.

	If -f is specified, the file is treated as a simple text file.  Splits
	may then occur after any newline.  If the option is given as -fm, a
	marker line is inserted at the beginning and end of each created file.
	This is useful if the parts of the file are sent through mailers that
	may append garbage like extra blank lines.  A marker line is exactly
	the following:

	--------------------[Cut here]--------------------

	There are 20 dashes before and after the "[Cut here]".  In addition,
	splita will add an identifying header before the leading marker line.
	The format of the header is:

	Part nnn, file ffff

	where "nnn" is three digits, with possible leading 0's.

	The byte_limit (default 50000) may be set by an option.

	If no output_model is present, the input_file is used instead.  In
	all cases, everything after the first "." in the model used is
	discarded.

diagnostics

	File error messages only.

author

	Martin Minow
	Jerry Leichter

bugs

	Can only produce up to 999 parts.
	Perhaps markers would be useful in archive mode, too?

#endif
/*
 * Edit history
 * 0.0 ??-???-??  MM	Invention
 * 1.0  2-Oct-86 JSL	Added -f[m].  Options can now occur anywhere, not
 *			just as the first command-line argument.  Bugs
 *			fixed:  byte_limit wasn't being initialized to
 *			anything (effectively, 0).  The header lines inserted
 *			in split archives used the current output file name,
 *			rather than the input file name.  Those lines now
 *			refer to _nl:, rather than nl: - just in case someone
 *			is silly enough to assign something as the null
 *			device!
 * 1.1 22-Oct-86 JSL	Bugfix:  Get the bytelimit value from the argument
 *			currently being looked at, not always from argument 1!
 */

#include	<stdio.h>
#include	<ctype.h>
#ifdef vms
#include		<ssdef.h>
#include		<stsdef.h>
#define	IO_SUCCESS	(SS$_NORMAL | STS$M_INHIB_MSG)
#define	IO_ERROR	SS$_ABORT
#endif
/*
 * Note: IO_SUCCESS and IO_ERROR are defined in the Decus C stdio.h file
 */
#ifndef	IO_SUCCESS
#define	IO_SUCCESS	0
#endif
#ifndef	IO_ERROR
#define	IO_ERROR	1
#endif

#define EOS		0
#define	FALSE		0
#define	TRUE		1

char		line[513] = "<start of file>\n";
char		mark[] = "--------------------[Cut here]--------------------";
char		*inputname = NULL;
char		outname[513];
char		outfilename[513];
FILE		*outfd;
int		filecount;
int		linecount;
int		domark = FALSE;		/* Insert marker		*/
int		archive = TRUE; 	/* Handle input as archive	*/
long		bytecount;
long		bytelimit = 50000;

extern char		*strchr();
extern long		atol();

main(argc, argv)
int		argc;			/* Arg count			*/
char		*argv[];		/* Arg vector			*/
{	register char		*tp;
	register int		i;
	register int		oargc;

#ifdef vms
	argc = getredirection(argc, argv);
#endif

	oargc = argc;
	for (i = 1; i < oargc; i++) {
	    tp = argv[i];
	    if (tp[0] == '-') {
		argc--;
		if (isdigit(tp[1])) {
			bytelimit = atol(&tp[1]);
		} else if (tp[1] == 'f') {
		    archive = FALSE;
		    if (tp[2] != 'm' && tp[2] != EOS)
			usage();
		    domark = (tp[2] == 'm');
		} else
		    usage();
	    } else if (inputname == NULL) {
		inputname = tp;
		strcpy(outname, inputname);
	    } else
		strcpy(outname, tp);
	}

	if (argc <= 1 || argc > 3)
	    usage();

	if (freopen(inputname, "r", stdin) == NULL) {
	    perror(inputname);
	    exit(IO_ERROR);
	}

	/*
	 * Mash the '.' in the output model
	 */
	if ((tp = strchr(outname, '.')) == NULL)
	    tp = outname + strlen(outname);
	*tp = EOS;
	outfd = NULL;
	filecount = 0;
	linecount = 0;
	openanother();
	process();
	closeout();
	exit(IO_SUCCESS);
}

process()
/*
 * Process archive open on stdin
 */
{
	while (fgets(line, sizeof line, stdin) != NULL) {
	    if (outfd == NULL
	     || (bytecount >= bytelimit
	      && (!archive
		  || (  line[0] == '-'
		     && line[1] == 'h'
		     && line[2] == '-'
		     )
	          )
	         )
		) {
		    closeout();
		    openanother();
	    }
	    linecount++;
	    bytecount += strlen(line);
	    fputs(line, outfd);
	}
}

openanother()
{
	filecount++;
	sprintf(outfilename, "%s.%03d", outname, filecount);
#ifdef vms
	{
	    int		channel;
	    extern FILE	*fdopen();

	    if ((channel = creat(outfilename, 0, "rat=cr", "rfm=var")) == -1)
		outfd = NULL;
	    else outfd = fdopen(channel, "w");
	}
#else
	outfd = fopen(outfilename, "w");
#endif
	if (outfd == NULL) {
	    perror(outfilename);
	    exit(IO_ERROR);
	}
	printf("%s starts at %s", outfilename, line);
	if (strchr(line, '\n') == NULL)
	    putchar('\n');
	bytecount = 0;
	linecount = 0;
	if (archive)
	    fprintf(outfd, "-h- _nl: (%s, part %d)\n", inputname, filecount);
	if (domark) {
	    fprintf(outfd, "Part %03d, file %s\n", filecount, inputname);
	    fprintf(outfd, "%s\n", mark);
	}
}

closeout()
{
	if (outfd != NULL) {
	    if (domark)
		fprintf(outfd, "%s\n", mark);
	    fclose(outfd);
	    printf("%s finished, %d records, %ld bytes\n",
		outfilename, linecount, bytecount);
	}
}

usage()
{
	    fprintf(stderr,
	"Usage: splita [-byte_limit] [-f[m]] input_file [output_model]\n");
	    exit(IO_ERROR);
}

