home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hall of Fame
/
HallofFameCDROM.cdr
/
comp
/
pakutl12.lzh
/
PAKSORT.C
< prev
next >
Wrap
Text File
|
1988-09-10
|
15KB
|
610 lines
/*
PAKSORT.C Sort contents of .PAK archive.
Copyright 1988, Michael J. Housky
Released to the Public Domain ... *no* rights reserved.
*/
/*
Update log:
******************************************************************************
Version 1.2, 10 September 1988: Released to public domain.
Also relocated stderr fprintf's to stdout so error messages
can be captured with command-line redirection.
P.S. I only observe about 2% improvement with read/write over
fread/fwrite, but it *is* smaller. (mjh)
******************************************************************************
Version 1.1, 9 September 1988: used read, write, tell, lseek, open,
close instead of fread, fwrite, ftell, etc. This caused a 12% or so
speedup in the operation. jjn
******************************************************************************
Version 1.0, 25 August 1988: First version.
******************************************************************************
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#include "dirfn.h"
#include "pakdefn.h"
#define BUF_SIZE 4096 /* buffer size for sort/copy step */
typedef struct /* stored directory format: */
{
long floc; /* byte location of header in file */
long slen; /* stored (packed) length of file */
long olen; /* original (unpacked) length of file */
unsigned ddate; /* DOS date of update */
unsigned dtime; /* DOS time of update */
char fname[13]; /* filename */
} pak_dir;
/* ------------ Global data: */
FILE_TYPE *file_list = NULL; /* list of files (malloc'ed) */
unsigned char pak_buf[BUF_SIZE]; /* buffer for reading pakfile data */
pak_hdr fhdr; /* buffer for reading pakfile header */
long pakloc; /* location in input file */
long pakloc,paklen; /* length of input file */
char order[33]; /* sort order from argument */
char fpath[128]; /* full path\name of file */
char *fnptr; /* location of filename in fpath */
char pak_mark[2] = {PAK_MARK,0};
/*
read_pakhdr: Read header of .PAK member file
Reads next header sequentially from file.
Returns 0 if good header, and global fhdr has header.
Returns +1 if end of file marker found.
Returns -1 if bad header or read error.
*/
int read_pakhdr( int );
int read_pakhdr( fp )
int fp;
{
int i;
register int j;
i = 0;
j = read(fp, (char *)&i, 1); /* get file marker */
if ( i != PAK_MARK || j == -1) /* error if not correct */
return -1;
j = read(fp, (char*)&fhdr, PAK_HDRLEN);
/* read header, follows mark */
if ( j>=1 && fhdr.type==0 ) /* type 0 header is an EOF mark */
return 1; /* end of file mark seen */
if ( j!=PAK_HDRLEN || fhdr.slen<0L || fhdr.olen<fhdr.slen )
return -1; /* invalid header seen */
pakloc = tell(fp); /* note start of data and test */
if ( pakloc+fhdr.slen > paklen ) /* for all data present */
return -1; /* no: presume truncated file */
return 0;
} /* read_pakhdr */
/*
pak_getdir: Build directory of .PAK file headers.
Sequentially read and validate all headers within pakfile. Build malloc-ed
table of headers found.
Returns:
0 = success, *pdirp = pointer to malloc-ed directory.
1 = out of memory;
-1 = read/seek error or bad header.
*/
int pak_getdir( int, pak_dir** );
int pak_getdir( fp, pdirp )
int fp;
pak_dir **pdirp;
{
register int i;
int n,k;
long l,hdrloc;
pak_dir *pd;
/* Read the first header: */
hdrloc = tell(fp);
i = read_pakhdr(fp);
if ( i )
{
printf("Invalid header seen.\n");
return -1;
}
pd = (pak_dir*) malloc( (k=32)*sizeof(pak_dir) );
if ( pd==NULL )
{
printf("Out of memory.\n");
return -1; /* out of memory error */
}
n = 0;
do /* loop once for each new entry found, with */
{ /* n=#headers found, k=directory size */
if ( n >= k ) /* test for current table full */
{
/* add 10 more entries to directory: */
pd = (pak_dir*) realloc( (char*)pd, (k+=16)*sizeof(pak_dir) );
if ( pd==NULL )
{
printf("Out of memory.\n");
return -1; /* out of memory error */
}
}
pd[n].floc = hdrloc; /* store header location */
pd[n].slen = fhdr.slen; /* copy stored length */
pd[n].olen = fhdr.olen; /* copy original length */
pd[n].ddate = fhdr.ddate; /* copy DOS date */
pd[n].dtime = fhdr.dtime; /* copy DOS time */
strcpy(pd[n].fname,fhdr.fname); /* copy file name */
++n; /* and increment file count */
hdrloc += fhdr.slen+PAK_HDRLEN+1;
l = lseek( fp, hdrloc, SEEK_SET );
if ( l == -1L )
{
printf("Seek error.\n");
free( (char*)pd );
return -1;
}
i = read_pakhdr(fp);
} while ( i==0 );
if ( i<0 ) /* test for error */
{
printf("Invalid header seen.\n");
free( (char*)pd );
return -1;
}
*pdirp = pd;
return n;
} /* pak_getdir */
/*
dir_cmp: Directory entry compare function for sort.
Input:
lp: pointer to "left" entry
rp: pointer to "right" entry
order: sort order
Return:
0 if entries are equal
positive if left "greater than" right
negative if left "less than" right
*/
int dir_cmp( pak_dir*, pak_dir*, char* );
int dir_cmp( lp, rp, order )
pak_dir *lp,*rp;
char *order;
{
register int i,j;
int lc,rc;
char *lcp,*rcp;
for ( i=j=0; j==0; i+=2 )
{
switch( order[i] )
{
case 'F': /* compare full fileid */
j = strcmp( lp->fname, rp->fname );
break;
case 'N': /* compare name only */
lc = *(lcp = lp->fname);
rc = *(rcp = rp->fname);
while ( (j=lc-rc)==0 && lc!=0 )
{
lc = *++lcp;
if ( lc=='.' )
lc = 0;
rc = *++rcp;
if ( rc=='.' )
rc = 0;
}
break;
case 'X': /* compare .ext only */
/* find start of left extension: */
for ( lc=*(lcp = lp->fname); lc; )
{
++lcp;
lc = ( lc=='.' ) ? 0 : *lcp;
}
/* find start of right extension: */
for ( rc=*(rcp = rp->fname); rc; )
{
++rcp;
rc = ( rc=='.' ) ? 0 : *rcp;
}
/* return regular string compare of remainder of names: */
j = strcmp( lcp, rcp );
break;
case 'D': /* compare unsigned date: */
j = (lp->ddate > rp->ddate) - (lp->ddate < rp->ddate);
break;
case 'T': /* compare unsigned time: */
j = (lp->dtime > rp->dtime) - (lp->dtime < rp->dtime);
break;
case 'S': /* compare (long) size: */
j = (lp->olen > rp->olen) - (lp->olen < rp->olen);
break;
case '\0':
return 0;
}
if ( order[i+1] == '-' )
j = -j;
}
return j;
} /* dir_cmp */
/*
pak_sort: Sort one .PAK file.
A simple (slow, but small and sure) routine is used here to
sort the directory without the overhead of qsort and recursion.
If this sort is replaced with an unstable sort (like quicksort) then
the dir_cmp function should be changed to return compare of original
file location if all fields in order[] compare equal. This will preserve
sort stability ... i.e. input order is preserved on equal entries.
Return value is 0 if all files were originally in order,
or 1 if output order is different from input order.
*/
int pak_sort( pak_dir*, int, char* );
int pak_sort( pdir, n, order )
pak_dir *pdir;
int n;
char *order;
{
register int i,j;
int i0,j0,k,r;
pak_dir tdir;
r = 0;
for ( j0=1; j0<n; ++j0 )
{
i = i0 = j0-1; /* starting entry # to compare */
for ( j=j0; j<n; ++j )
{
k = dir_cmp( pdir+i, pdir+j, order );
if ( k>0 )
{ /* out of order */
i = j; /* will swap at end */
}
}
if ( i != i0 ) /* if out of order */
{
tdir = pdir[i]; /* swap smallest entry */
pdir[i] = pdir[i0]; /* (at most n-1 times) */
pdir[i0] = tdir;
r = 1; /* tell caller that input was */
/* not in order */
}
}
return r;
} /* pak_sort */
/*
pak_write: Copy packed source files to dest in sorted order.
*/
int pak_write( int, int, pak_dir*, int );
int pak_write( src, dst, dirp, n )
int src; /* opened source file */
int dst; /* opened dest file */
pak_dir *dirp; /* sorted directory of source */
int n; /* number of entries in source directory */
{
register int i,j;
int k;
long len,start,end;
long l;
for ( i=0; i<n; ++i )
{ /* once for each member file */
printf(" Copying: %-13s - loc=%-6ld len=%-6ld\n",
dirp[i].fname,
dirp[i].floc,
dirp[i].slen+1+PAK_HDRLEN );
/* point to start of member, test for error: */
l = lseek(src, dirp[i].floc, SEEK_SET);
if ( l == -1L )
{
printf("Seek error.\n");
return -1;
}
/* compute length and copy member to destination: */
len = dirp[i].slen+1+PAK_HDRLEN;
for ( end=0; end<len; )
{
start = end;
end = start+(k=BUF_SIZE);
if (end>len)
k = (int)((end=len)-start);
j = read(src,pak_buf,k);
if ( j != k )
{
printf("Read error.\n");
return -1;
}
j = write(dst,pak_buf,k);
if ( j != k )
{
printf("Write error.\n");
return -1;
}
}
}
/* Add EOF mark to (end of) destination: */
j = write(dst, pak_mark, sizeof(pak_mark));
if ( j != sizeof(pak_mark) )
{
printf("Write error.\n");
return -1;
}
return 0;
} /* pak_write */
/*
pak_dosort: Read/sort/rewrite one .PAK file.
Returns 0 if successful, or errorlevel for DOS on error:
1 = Can't open/read source. (missing or invalid pakfile)
2 = Can't create/write dest (maybe disk or directory full)
3 = Can't delete old source file. (read-only)
4 = Can't rename temp file to source name. (???)
*/
int pak_dosort( char* );
int pak_dosort( fn )
char *fn;
{
register int i,j;
int n;
pak_dir *pdir; /* pointer to (malloced) directory */
/* built by pak_getdir */
int src; /* source file */
int dst; /* dest file */
char srcname[81]; /* save source filename */
strcpy( fnptr, fn ); /* make full path to file */
printf("\nSearching: %s\n",fpath); /* and identify */
src = open( fpath, O_RDONLY | O_BINARY ); /* and open file */
if ( src == -1 )
{
printf("Can't open.\n", fpath);
return 1;
}
paklen = filelength(src); /* get file length in global */
pdir = NULL; /* clear directory pointer */
n = pak_getdir( src, &pdir ); /* get directory */
if ( n<1 )
{
printf("Invalid file format, not changed.\n");
close(src);
return 1;
}
i = pak_sort( pdir, n, order );
if ( i==0 )
{
printf("Already in order, not changed.\n");
free( (char*)pdir );
return 0;
}
/* pakfile is not in order, create sorted copy & rename: */
strcpy( srcname, fpath );
strcpy( fnptr, "PAKSRTMP.$$$" );
dst = open( fpath,
O_CREAT | O_TRUNC | O_WRONLY | O_BINARY,
S_IREAD | S_IWRITE);
if ( dst==-1 )
{
printf("Can't create: %s\n", fpath );
free( (char*)pdir );
return 1;
}
j = pak_write( src, dst, pdir, n ); /* copy source to dest tempfile */
close(src); /* unconditionally close source */
free( (char*)pdir ); /* and release directory mem */
i = close(dst); /* close dest file */
if ( j || (i == -1) ) /* if error on write or close */
{
if ( !j ) /* identify close error */
printf("Can't close: %s\n",fpath);
unlink(fpath);
return 2;
}
j = unlink(srcname); /* delete source */
if ( j )
{ /* can't delete, read-only? */
printf( "Can't delete original.\n");
unlink(fpath); /* delete sorted temp copy */
return 3; /* return error */
}
j = rename( fpath, srcname );
if ( j )
{
printf("Rename error: %d, original unsorted data lost!\n");
printf("Sorted data retained in temp output file for recovery:\n");
printf("%s\n",fpath);
return 4;
}
return 0;
} /* pak_dosort */
/*
PKASORT.C main program
*/
int main(int,char **);
int main( argc, argv )
int argc;
char **argv;
{
register int
i,j;
int k;
long len;
int addext;
int num_files;
/* First, identify self and examine paramter: */
printf("\nPAKSORT v1.2\n");
if ( argc<2 )
{
printf("Usage: paksort <fname> [<order>]\n");
printf("<order> is one or more of: \n");
printf(" F+ or F-: sort by full filename.ext,\n");
printf(" N+ or N-: sort by filename,\n");
printf(" X+ or X-: sort by .ext,\n");
printf(" D+ or D-: sort by date,\n");
printf(" T+ or T-: sort by time,\n");
printf(" S+ or S-: sort by (unpacked) file size,\n");
printf(" [Note: + gives ascending order, - gives descending order.]\n");
printf("The default order is D+T+F+\n");
return 0;
}
/* Parameter valid, find path and decide about default extension */
strcpy( order, "D+T+F+" ); /* set default order */
if ( argc > 2 )
{
k = strlen(argv[2]);
if ( (k&1) || (k>=sizeof(order)) )
{
printf( "Invalid sort order\n" );
return 1;
}
strcpy( order, argv[2] );
strupr( order );
for ( i=0; i<k; i+=2 )
{
switch( order[i] )
{
default:
printf("Invalid sort order\n");
return 1;
case 'N': case 'F': case 'X':
case 'D': case 'T': case 'S':
/* break */;
}
switch( order[i+1] )
{
default:
printf("Invalid sort order\n");
return 1;
case '+': case '-':
/* break */;
}
}
}
strcpy( fpath, argv[1] ); /* extract path, find end */
i = strlen(fpath); /* index of last character */
addext = 1; /* presume no extension */
while ( --i >= 0 ) /* search backward thru argument */
{
j = fpath[i];
if ( j=='\\' || j==':' )
break; /* colon or backslash ends search */
if ( j=='.' )
addext = 0; /* period found, no default */
}
fnptr = fpath+i+1;
strupr(fpath); /* uppercase for display */
if ( addext )
strcat(fpath,".PAK"); /* add default extension */
num_files = get_files(fpath,0,&file_list);
if (num_files < 0)
{
printf("Too many files: out of memory.\n");
return(1);
}
if (num_files < 1)
{
printf("Cannot find file(s): %s\n",argv[1]);
return(1);
}
/* Now, list contents of each file: */
for (i = 0; i < num_files; ++i)
{
j = pak_dosort( file_list[i].filename );
if ( j )
return j;
}
return 0;
} /* main */