home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
programs
/
sort
/
ssort.lbr
/
SSORT.CQ
/
SSORT.C
Wrap
Text File
|
1985-02-09
|
22KB
|
880 lines
/*
* SSORT.C - Selecta-SORT
* version 1.0
* This is a modified version of LEXSORT which permits a command line
* option to select the collating sequence from a "magic" file.
* The name was changed only due to the fact that LEXSORT was no longer
* (if it ever was) appropriate. LEXSORT.LBR should be retired.
*
* Differences from LEXSORT.C:
*
* The only changed functions were options() and usage(). Two functions
* were added: get_collating_sequence(), collate_file().
* Four #defines were added: INPUT, ABSOLUTE, FUDGE, COLLATE_NAME.
* The signon message was changed. Globals were not modified.
*
* Harvey Moran 2/26/84
*
* To build with BDS C vers 1.5:
* cc ssort -o -e 3800
* casm lexlate
* asm lexlate.DDz ;choose drives (D) to suit
* ddt
* f100,1000,0 (not necessary, makes file compares of '.crl' meaningful)
* iLEXLATE.HEX
* g0
* save 4 lexlate.crl
* l2 ssort lexlate
*
* Usage:
*
* SSORT <infile> <outfile> [-c<index 0 to n>] [-k<key field selections>]
*
* -c<n> seletcs the n'th sort order precedence table from the
* "magic" file SSORT.OVL to be overlayed into lexlate(). See
* SORTORDR.ASM for the definition of these tables. ASseMble and LOAD
* SORTORDR.ASM, then rename to SSORT.OVL.
* If -c is not used, the default remains the same lexicographical
* increasing order sort from LEXSORT (or whatever you "wire" into
* LEXLATE.CRL).
*
* All other command line syntax remains the same as LEXSORT.
*
* Harvey Moran 2/26/84
*
* =====================================================================
* LEXSORT.C (modified SORT3.C for lexicographical ordering) HRM 11/6/83
* version 1.0
* To build with BDS C vers 1.5:
* cc lexsort -o -e 3400
* casm lexlate
* asm lexlate.DDz ;choose drives (D) to suit
* ddt
* f100,1000,0 (not necessary, makes file compares of '.crl' meaningful)
* iLEXLATE.HEX
* g0
* save 4 lexlate.crl
* l2 lexsort lexlate
*
* Usage: lexsort <infile> <outfile> [-k<sort key list>]
*
* where <sort key list> is:
*
* A comma separated list of column numbers or ranges
* specifing the sort key positions.
* e.g.
* lexsort messy.dat neat.dat -k3-5,7-9,1-2,12
*
* specifies that:
* the input file is MESSY.DAT
* the output file is NEAT.DAT
*
* The primary sort key is columns 3 thru 5
* The first secondary sort key is columns 7 thru 9
* The next secondary sort key is columns 1 thru 2
* The last secondary sort key is columns 12 thru end of line
*
* A sort key of 1 column may be specified as 3-3 for example.
* A sort key which goes to end of line need NOT be the last one.
*
* The leftmost column is numbered 1.
* The default sort key is the entire line.
*
* Implementation note:
*
* LEXLATE.CSM contains function lexlate() which determines the
* character ordering for the character set. This concept includes
* the notion of totally INGOREing some characters. The LEXLATE.CSM
* provided IGNOREs all characters but space, A-Z, a-z, 0-9. It also
* treats 'A' as less than but adjacent to 'a', etc. If a specified
* key field consists entirely of IGNORE characters, it is considered
* the lowest order for that key. A line which has no entry for the
* specified key field (because it is too short) will be the next lowest
* order in the sort for that field.
*
* Derived from: SORT3.C by H.R. Moran, Jr. 11/5/83
* changes made:
* 1) Re-format, indent, and comment to suit me, including deletion
* of some extraneous declarations and code lines.
* 2) Re-write compar(), and include use of lexlate()
* 3) Add options() to allow key field selections.
*
* SORT3.C comments follow:
* ---------------------------------------------------------------------------
* Sort/Merge from Software Tools
*
* Last Modified : 21 September 1982
*
* Converted from Software Tools RATFOR to BDS C by Leor Zolman
* Sep 2, 1982
*
* Usage: sort <infile> <outfile>
*
* Main variables have been made external; this is pretty much in
* line with the RATFOR call-by-name convention anyway.
*
* Requires lots of disk space, up to around three times the length
* of the file file being sorted. This program is intended for files
* bigger than memory; simpler, faster sorts can be implemented for
* really short files (like ALPH.C)
* -leor
*
* Compile & Link:
* A>cc sort.c -e2800 -o
* A>l2 sort
* (or...)
* A>cc sort.c -e2900 -o
* A>clink sort
*
*/
#include <bdscio.h>
#define SIGNON "ssort version 1.0 - 2/26/84 - hrm\n"
#define FUDGE 0xe /* offset into the lexlate function for table address */
#define COLLATE_NAME collate_file()
/* #define DEBUG */ /* enables debug printout when defined */
#define BOOL int /* BOOlean */
#define PROC int /* PROCedure */
#define TRIAD int /* -1, 0, or +1 */
#define IGNORE 0xff /* lexlate() token to ignore the character */
#define VERBOSE 1 /* give running account of file activity */
#define MAXLINE 200 /* longest line we want to deal with */
#define NBUFS 7 /* Max number of open buffered files */
#define MAXPTR 3000 /* Max number of lines (set for dict) */
#define MERGEORDER (NBUFS-1) /* Max # of intermediate files to merge */
#define NAMESIZE 20 /* Max Filename size */
#define LOGPTR 13 /* smallest value >= log (base 2) of MAXPTR */
#define EOS '\0' /* string termination character */
#define FILE struct _buf
#define stderr 4
#define fputc putc
char name[NAMESIZE], name2[NAMESIZE + 10];
FILE buffers[NBUFS + 1]; /* up to NBUFS general-purp. buffered files */
FILE *infil[MERGEORDER + 1]; /* tmp file ptrs for sort operation */
unsigned linptr[MAXPTR + 1], nlines;
int temp;
unsigned maxtext; /* max # of chars in main text buffer */
/*
* KEY FIELD selection support variables - hrm
*/
#define MAXFIELDS 20
#define FIELDS struct _fields
FIELDS {
int _numfields;
int _strtcol[MAXFIELDS];
int _stopcol[MAXFIELDS];
} sortfields;
#define FASTLOCAL
#ifdef FASTLOCAL
/*
* FAST locals for compar()
*/
struct {
unsigned i, j;
unsigned k, l;
unsigned x1, x2;
unsigned len_i, len_j;
char c1, c2;
} z;
#endif
#ifdef DEBUG
char spacebuffer[200];
#endif
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
/*!!!!!!!!!!!!!!!! WARNING (H.Moran) !!!!!!!!! */
/*! The algorithm INSISTS that THIS name be the LAST global ! */
/*! ! */
char *linbuf; /* text area starts after this variable */
/* */
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
main(argc, argv)
int argc;
char *argv[];
{
int min(), gtext();
FILE *infile, *outfile; /* main input and output streams */
FILE *tmpfile;
unsigned high, lim, low;
BOOL more_text;
puts(SIGNON);
linbuf = endext(); /* start of text buffer area */
maxtext = topofmem() - endext() - 500;
tmpfile = buffers[0];
options(&argc, argv); /* process command line options */
if ( argc != 3 ) {
usage("");
}
infile = buffers[1];
if ( fopen(argv[1], infile) == ERROR ) {
puts("Can't open ");
puts(argv[1]);
exit(-1);
}
#if VERBOSE
fputs("Beginning initial formation run\n", stderr);
#endif
high = 0; /* Initial formation of runs: */
do {
more_text = gtext(infile);
quick(nlines);
high++;
makfil(high, tmpfile);
ptext(tmpfile);
fclout(tmpfile);
} while ( more_text );
fclose(infile); /* free up the input file buffer */
#if VERBOSE
fputs("Beginning merge operation\n", stderr);
#endif
for ( low = 1; low < high; low += MERGEORDER ) { /* merge */
lim = min(low + MERGEORDER - 1, high);
gopen(low, lim); /* open files */
high++;
makfil(high, tmpfile);
merge(lim - low + 1, tmpfile);
fclout(tmpfile); /* terminate, flush and close file */
gremov(low, lim);
}
/*
* Now write the sorted output file:
*/
#if VERBOSE
fputs("Merge complete. Writing output file.\n", stderr);
#endif
gname(high, name); /* create name of result file */
infile = buffers[0];
if ( fopen(name, infile) == ERROR ) {
puts("Something's screwy; I can't open ");
puts(name);
exit(-1);
}
outfile = buffers[1];
while ( fcreat(argv[2], outfile) == ERROR ) {
puts("Can't create ");
puts(argv[2]);
puts("\nEnter another name to call the output: ");
gets(name2);
argv[2] = &name2;
}
while ( fgets(linbuf, infile) ) {
fputs(linbuf, outfile);
fputs("\r\n", outfile);
}
fclout(outfile);
fabort(infile->_fd);
unlink(name);
}
PROC
options(pac, av)
int *pac;
char *av[];
{
int i, j;
char *s;
sortfields._numfields = 1;
sortfields._strtcol[0] = 0;
sortfields._stopcol[0] = 32767;
for ( i = 1; i < *pac; ++i ) {
if ( *av[i] == '-' && tolower(av[i][1]) == 'c' ) {
get_collating_sequence(atoi(&av[i][2]));
for ( j = i; j < *pac; ++j ) /* remove options from av[] */
av[j] = av[j+1];
*pac -= 1;
}
if ( *av[i] == '-' && tolower(av[i][1]) == 'k' ) {
s = av[i] + 2;
for ( j = 0; isdigit(*s) && j < MAXFIELDS; ++j ) {
sortfields._strtcol[j] = 0;
while ( isdigit(*s) ) {
sortfields._strtcol[j] *= 10;
sortfields._strtcol[j] += (*s++ - '0');
}
if ( (sortfields._strtcol[j] -= 1) < 0 )
sortfields._strtcol[j] = 0;
sortfields._stopcol[j] = 32767;
if ( *s == '-' ) {
++s;
sortfields._stopcol[j] = 0;
while ( isdigit(*s) ) {
sortfields._stopcol[j] *= 10;
sortfields._stopcol[j] += (*s++ - '0');
}
if ( (sortfields._stopcol[j] -= 1) < 0 )
sortfields._stopcol[j] = 32767;
if ( *s != ',' )
break;
++s;
}
else if ( *s != ',' )
break;
else
++s;
sortfields._numfields++;
}
for ( j = i; j < *pac; ++j ) /* remove options from av[] */
av[j] = av[j+1];
*pac -= 1;
}
}
for ( i = 0; i < sortfields._numfields; ++i )
if ( sortfields._strtcol[i] > sortfields._stopcol[i] )
usage("ILLEGAL SORT KEY SPECIFICATION");
}
PROC
fclout(obuf)
FILE *obuf;
{
putc(CPMEOF, obuf);
fflush(obuf);
fclose(obuf);
}
/*
* Quick: Quicksort for character lines
*/
PROC
quick(nlines)
unsigned nlines;
{
unsigned i, j, lv[LOGPTR + 1], p, pivlin, uv[LOGPTR + 1];
int compar();
lv[1] = 1;
uv[1] = nlines;
p = 1;
while ( p > 0 )
if ( lv[p] >= uv[p] ) /* only 1 element in this subset */
p--; /* pop stack */
else {
i = lv[p] - 1;
j = uv[p];
pivlin = linptr[j]; /* pivot line */
while ( i < j ) {
for ( i++; compar(linptr[i], pivlin) < 0; i++ )
;
for ( j--; j > i; j-- )
if ( compar(linptr[j], pivlin) <= 0 )
break;
if ( i < j ) { /* out of order pair */
#ifdef DEBUG
printf("SWAPPING:\n%s\n%s\n\n",
&linbuf[linptr[i]], &linbuf[linptr[j]]);
#endif
temp = linptr[i];
linptr[i] = linptr[j];
linptr[j] = temp;
}
}
j = uv[p]; /* move pivot to position 1 */
temp = linptr[i];
linptr[i] = linptr[j];
linptr[j] = temp;
if ( (i - lv[p]) < (uv[p] - i) ) {
lv[p + 1] = lv[p];
uv[p + 1] = i - 1;
lv[p] = i + 1;
}
else {
lv[p + 1] = i + 1;
uv[p + 1] = uv[p];
uv[p] = i - 1;
}
p++;
}
}
/*
* Ptext: output text lines from linbuf onto the buffered output file given
*/
PROC
ptext(outfil)
FILE *outfil;
{
int i;
for ( i = 1; i <= nlines; i++ ) {
fputs(&linbuf[linptr[i]], outfil);
fputc('\0', outfil); /* terminate the line */
}
}
/*
* Gtext: Get text lines from the buffered input file provided, and
* place them into linbuf
*/
int
gtext(infile)
FILE *infile;
{
unsigned lbp, len;
nlines = 0;
lbp = 1;
do {
if ( (len = fgets(&linbuf[lbp], infile)) == NULL )
break;
len = strlen(&linbuf[lbp]);
linbuf[lbp + len - 1] = '\0';
nlines++;
linptr[nlines] = lbp;
lbp += len; /* drop '\n', but keep NULL at end of string */
} while ( lbp < (maxtext - MAXLINE) && nlines < MAXPTR );
return (len); /* return 0 if done with file */
}
/*
* Makfil: Make a temporary file having suffix 'n' and open it for
* output via the supplied buffer
*/
PROC
makfil(n, obuf) /* make temp file having suffix 'n' */
int n;
FILE *obuf;
{
FILE *fp;
char name[20];
gname(n, name);
if ( fcreat(name, obuf) == ERROR ) {
puts("Can't create ");
puts(name);
exit(-1);
}
}
/*
* Gname: Make temporary filename having suffix 'n'
*/
char *
gname(n, name)
char *name;
int n;
{
char tmptext[10];
strcpy(name, "TEMP"); /* create "TEMPn.$$$" */
strcat(name, itoa(tmptext, n));
strcat(name, ".$$$");
return (name); /* return a pointer to it */
}
/*
* Itoa: convert integer value n into ASCII representation at strptr,
* and return a pointer to it
*/
char *
itoa(strptr, n)
char *strptr;
int n;
{
int length;
if ( n < 0 ) {
*strptr++ = '-';
strptr++;
n = -n;
}
if ( n < 10 ) {
*strptr++ = (n + '0');
*strptr = '\0';
return (strptr - 1);
}
else {
length = strlen(itoa(strptr, n/10));
itoa(&strptr[length], n % 10);
return (strptr);
}
}
/*
* Gopen: open group of files low...lim
*/
PROC
gopen(low, lim)
int lim, low;
{
int i;
#if VERBOSE
fprintf(stderr, "Opening temp files %d-%d\n", low, lim);
#endif
for ( i = 1; i <= (lim - low + 1); i++ ) {
gname(low + i - 1, name);
if ( fopen(name, buffers[i]) == ERROR ) {
puts("Can't open: ");
puts(name);
exit(-1);
}
infil[i] = &buffers[i];
}
}
/*
* Remove group of files low...lim
* (should use "close" instead of "fabort" for MP/M II)
*/
PROC
gremov(low, lim)
int lim, low;
{
int i;
#if VERBOSE
fprintf(stderr, "Removing temp files %d-%d\n", low, lim);
#endif
for ( i = 1; i <= (lim - low + 1); i++ ) {
fabort(infil[i]->_fd); /* forget about the file */
gname(low + i - 1, name);
unlink(name); /* and physically remove it */
}
}
/*
* Fputs: special version that doesn't epand LF's and aborts on error
*/
PROC
fputs(s, iobuf)
char *s;
FILE *iobuf;
{
char c;
while ( c = *s++ )
if ( putc(c, iobuf) == ERROR ) {
fputs("Error on file output\n", stderr);
exit(-1);
}
}
/*
* Merge: merge infil[1]...infil[nfiles] onto outfil
*/
PROC
merge(nfiles, outfil)
FILE *outfil;
{
char *fgets();
int i, inf, lbp, lp1, nf;
lbp = 1;
nf = 0;
for ( i = 1; i <= nfiles; i++) /* get one line from each file */
if ( fgets(&linbuf[lbp], infil[i]) != NULL ) {
nf++;
linptr[nf] = lbp;
lbp += MAXLINE; /* leave room for largest line */
}
quick(nf); /* make initial heap */
while ( nf > 0 ) {
lp1 = linptr[1];
fputs(&linbuf[lp1], outfil);
fputc('\0', outfil);
inf = lp1 / MAXLINE + 1; /* compute file index */
if ( fgets(&linbuf[lp1], infil[inf]) == NULL ) {
linptr[1] = linptr[nf];
nf--;
}
reheap(nf);
}
}
/*
* Reheap: propogate linbuf[linptr[1]] to proper place in heap
*/
PROC
reheap(nf)
unsigned nf;
{
unsigned i, j;
for ( i = 1; (i + i) <= nf; i = j ) {
j = i + i;
if ( j < nf && compar(linptr[j], linptr[j + 1]) > 0 )
j++;
if ( compar(linptr[i], linptr[j]) <= 0 )
break;
temp = linptr[i];
linptr[i] = linptr[j];
linptr[j] = temp;
}
}
/*
* Just like regular library version, except that NULL is also
* taken as a string terminator.
*/
char *
fgets(s, iobuf)
char *s;
FILE *iobuf;
{
int count, c;
char *cptr;
count = MAXLINE;
cptr = s;
if ( (c = getc(iobuf)) == CPMEOF || c == EOF )
return (NULL);
do {
if ( (*cptr++ = c) == '\n' ) {
if ( cptr>s+1 && *(cptr-2) == '\r' )
*(--cptr - 1) = '\n';
break;
}
if ( ! c )
break;
} while ( count-- && (c=getc(iobuf)) != EOF && c != CPMEOF );
if ( c == CPMEOF )
ungetc(c, iobuf); /* push back control-Z */
*cptr = '\0';
return (s);
}
PROC
usage(s)
char *s;
{
fprintf(stderr, "\n%s\nUsage:\n", s);
fputs("\tssort <infile> <outfile> [-c<collating sequence>] [-k<sort key list>]\n",
stderr);
fputs("where <sort key list> is:\n", stderr);
fputs(" a comma separated list of column numbers or ranges\n", stderr);
fputs("specifing the sort key columns\n\te.g.\n", stderr);
fputs("-k3-5,7-9,1-2,12\n\tspecifies that\n", stderr);
fputs(" the primary sort key is columns 3 thru 5\n", stderr);
fputs("the next secondary sort key is columns 7 thru 9\n", stderr);
fputs("the next secondary sort key is columns 1 thru 2\n", stderr);
fputs("the last secondary sort key is columns 12 thru end of line.\n",
stderr);
fputs("\nThe leftmost column is numbered 1.\n", stderr);
fputs("The default sort key is the entire line.\n", stderr);
fputs("\n-c<n> selects the n'th collating sequence from the \"magic\"\n", stderr);
fprintf(stderr, "file %s. Where sequences are numbered from zero.\n",
COLLATE_NAME);
exit();
}
/*
* Compar: Compare two strings; return 0 if equal, -1 if first is
* lexically smaller, or 1 if first is bigger
*/
TRIAD
compar(lp1, lp2)
unsigned lp1, lp2;
{
char lexlate();
#ifndef FASTLOCAL
struct {
unsigned i, j; /* string relative char positions being considered */
unsigned k, l; /* scratch for # keys, key columns */
unsigned x1, x2; /* string relative end of key field columns */
unsigned len_i, len_j; /* lengths of the two incoming strings */
char c1, c2; /* characters currently being considered */
} z;
#endif
z.len_i = strlen(&linbuf[lp1]);
z.len_j = strlen(&linbuf[lp2]);
for ( z.k = 0; z.k < sortfields._numfields; ++z.k ) {
z.l = sortfields._strtcol[z.k]; /* for each sort key */
z.i = lp1 + min(z.l, z.len_i);
z.j = lp2 + min(z.l, z.len_j);
z.l = sortfields._stopcol[z.k];
z.x1 = lp1 + min(z.l, z.len_i);
z.x2 = lp2 + min(z.l, z.len_j);
do { /* for each char position in a key */
while ( (z.c1=lexlate(linbuf[z.i])) == IGNORE )
if ( ++z.i > z.x1 )
break;
while ( (z.c2=lexlate(linbuf[z.j])) == IGNORE )
if ( ++z.j > z.x2 )
break;
if ( (z.i > z.x1) && (z.j <= z.x2) ) {
#ifdef DEBUG
printf("END FIELD LESS THAN:\n%s\n%s\n",
&linbuf[lp1], spaces(z.i-lp1));
printf("%s\n%s\n\n", &linbuf[lp2], spaces(z.j-lp2));
#endif
return (-1);
}
if ( (z.j > z.x2) && (z.i <= z.x1) ) {
#ifdef DEBUG
printf("END FIELD GREATER THAN:\n%s\n%s\n",
&linbuf[lp1], spaces(z.i-lp1));
printf("%s\n%s\n\n", &linbuf[lp2], spaces(z.j-lp2));
#endif
return (1);
}
if ( (z.i > z.x1) && (z.j > z.x2) )
break;
if ( z.c1 != z.c2 ) {
if ( z.c1 == IGNORE ) /* terminated on IGNORE class of char */
z.c1 = 0;
if ( z.c2 == IGNORE ) /* terminated on IGNORE class of char */
z.c2 = 0;
if ( z.c1 == z.c2 ) {
#ifdef DEBUG
printf("MAPPED MISMATCH EQUAL TO:\n%s\n%s\n",
&linbuf[lp1], spaces(z.i-lp1));
printf("%s\n%s\n\n", &linbuf[lp2], spaces(z.j-lp2));
#endif
return (0);
}
#ifdef DEBUG
if ( z.c1 < z.c2 ) {
printf("MAPPED MISMATCH LESS THAN:\n%s\n%s\n",
&linbuf[lp1], spaces(z.i-lp1));
printf("%s\n%s\n\n", &linbuf[lp2], spaces(z.j-lp2));
}
else {
printf("MAPPED MISMATCH GREATER THAN:\n%s\n%s\n",
&linbuf[lp1], spaces(z.i-lp1));
printf("%s\n%s\n\n", &linbuf[lp2], spaces(z.j-lp2));
}
#endif
return ((z.c1 < z.c2) ? -1 : 1);
}
++z.i;
++z.j;
} while ( 1 );
/*
* end of sort key field with equal keys, use next key field
*/
}
/*
* Final result at end of ALL sort key fields
*/
if ( z.c1 == IGNORE ) /* terminated on the IGNORE class of char */
z.c1 = 0;
if ( z.c2 == IGNORE ) /* terminated on the IGNORE class of char */
z.c2 = 0;
if ( z.c1 == z.c2 ) {
#ifdef DEBUG
printf("FINAL EQUAL TO:\n%s\n%s\n",
&linbuf[lp1], spaces(z.i-lp1));
printf("%s\n%s\n\n", &linbuf[lp2], spaces(z.j-lp2));
#endif
return (0);
}
#ifdef DEBUG
if ( z.c1 < z.c2 ) {
printf("FINAL LESS THAN:\n%s\n%s\n",
&linbuf[lp1], spaces(z.i-lp1));
printf("%s\n%s\n\n", &linbuf[lp2], spaces(z.j-lp2));
}
else {
printf("FINAL GREATER THAN:\n%s\n%s\n",
&linbuf[lp1], spaces(z.i-lp1));
printf("%s\n%s\n\n", &linbuf[lp2], spaces(z.j-lp2));
}
#endif
return ((z.c1 < z.c2) ? -1 : 1);
}
#ifdef DEBUG
spaces(n)
{
int i;
spacebuffer[0] = '\0';
for ( i = 0; i < n; ++i )
spacebuffer[i] = ' ';
spacebuffer[i++] = '^';
spacebuffer[i] = '\0';
return (spacebuffer);
}
#endif
PROC
get_collating_sequence(n)
int n;
{
int lexlate();
char *p;
int f;
#define INPUT 0
#define ABSOLUTE 0
if ( (f=open(COLLATE_NAME, INPUT)) < 0 ) {
fprintf(stderr, "Can't find file %s\n", COLLATE_NAME);
exit();
}
if ( seek(f, 2*n, ABSOLUTE) < 0 ) {
fprintf(stderr, "Error in seeking on file %s\n", COLLATE_NAME);
exit();
}
p = lexlate;
p += FUDGE;
if ( read(f, p, 2) != 2 ) {
fprintf(stderr, "Error in reading file %s\n", COLLATE_NAME);
exit();
}
fabort(f);
}
char *
collate_file()
{
return ("SSORT.OVL\0xxxxxxxxx");
}
.j-lp2));
}
else {
printf("FINAL GREATER THAN:\n%s\