gno/usr.orca.bin/udl/common.c
1997-12-08 16:07:19 +00:00

895 lines
20 KiB
C

/*
* udl - Convert EOL formats freely between MS-DOS (CR/LF), Unix/Amiga (LF),
* and Apple (CR).
*
* Routines common to both the Unix and Apple IIgs versions.
*
* $Id: common.c,v 1.10 1997/12/08 16:07:19 gdr Exp $
*
* Copyright (c) 1993-1995 Soenke Behrens, Devin Reade
*/
#ifdef __GNO__
#pragma noroot
#endif
#include "common.h"
extern char *strdup(const char *);
/*
* convert_gs() ... convert files to use CR as EOL
*
* Inputs:
* FILE *infile File to read from
* FILE *outfile File to write to
*
* Outputs:
* None
*/
void convert_gs(FILE *infile, FILE *outfile) {
unsigned char a;
unsigned char *in_bufpos;
unsigned char *out_bufpos;
unsigned char *in_bufend;
unsigned char *out_bufend;
size_t file_remain;
in_bufpos = in_buffer;
out_bufpos = out_buffer;
(void) fseek(infile,0L,SEEK_END);
file_remain = ftell(infile);
rewind(infile);
in_bufend = in_buffer + my_fread(infile,BUFFERSIZE);
out_bufend = out_buffer + BUFFERSIZE;
while (file_remain != 0) {
a = *in_bufpos;
in_bufpos++;
if (in_bufpos >= in_bufend) {
file_remain -= in_bufend - in_buffer;
in_bufend = in_buffer + my_fread(infile,BUFFERSIZE);
in_bufpos = in_buffer;
}
if(a == LF) {
*out_bufpos = CR;
out_bufpos++;
if (out_bufpos == out_bufend) {
my_fwrite(out_buffer,outfile,BUFFERSIZE);
out_bufpos = out_buffer;
}
} else if(a == CR) {
*out_bufpos = CR;
out_bufpos++;
if (out_bufpos == out_bufend) {
my_fwrite(out_buffer,outfile,BUFFERSIZE);
out_bufpos = out_buffer;
}
if (*in_bufpos == LF && file_remain != 0) {
in_bufpos++;
if (in_bufpos >= in_bufend) {
file_remain -= in_bufend - in_buffer;
in_bufend = in_buffer + my_fread(infile, BUFFERSIZE);
in_bufpos = in_buffer;
}
}
} else {
*out_bufpos = a;
out_bufpos++;
if (out_bufpos == out_bufend) {
my_fwrite(out_buffer,outfile,BUFFERSIZE);
out_bufpos = out_buffer;
}
}
}
/* Check for remainder in output buffer */
if (out_bufpos != out_buffer)
my_fwrite(out_buffer,outfile,(int)(out_bufpos - out_buffer));
}
/*
* convert_messy() ... convert files to use CR/LF as EOL
*
* Inputs:
* FILE *infile File to read from
* FILE *outfile File to write to
*
* Outputs:
* None
*/
void convert_messy (FILE *infile, FILE *outfile) {
unsigned char a;
unsigned char *in_bufpos;
unsigned char *out_bufpos;
unsigned char *in_bufend;
unsigned char *out_bufend;
size_t file_remain;
in_bufpos = in_buffer;
out_bufpos = out_buffer;
(void) fseek(infile,0L,SEEK_END);
file_remain = ftell(infile);
rewind(infile);
in_bufend = in_buffer + my_fread(infile, BUFFERSIZE);
out_bufend = out_buffer + BUFFERSIZE;
while (file_remain != 0) {
a = *in_bufpos;
in_bufpos++;
if (in_bufpos >= in_bufend) {
file_remain -= in_bufend - in_buffer;
in_bufend = in_buffer + my_fread(infile, BUFFERSIZE);
in_bufpos = in_buffer;
}
if(a == LF) {
*out_bufpos = CR;
out_bufpos++;
if (out_bufpos == out_bufend) {
my_fwrite(out_buffer,outfile,BUFFERSIZE);
out_bufpos = out_buffer;
}
*out_bufpos = LF;
out_bufpos++;
if (out_bufpos == out_bufend) {
my_fwrite(out_buffer,outfile,BUFFERSIZE);
out_bufpos = out_buffer;
}
} else if(a == CR) {
*out_bufpos = CR;
out_bufpos++;
if (out_bufpos == out_bufend) {
my_fwrite(out_buffer,outfile,BUFFERSIZE);
out_bufpos = out_buffer;
}
*out_bufpos = LF;
out_bufpos++;
if (out_bufpos == out_bufend) {
my_fwrite(out_buffer,outfile,BUFFERSIZE);
out_bufpos = out_buffer;
}
if (*in_bufpos == LF && file_remain != 0) {
in_bufpos++;
if (in_bufpos >= in_bufend) {
file_remain -= in_bufend - in_buffer;
in_bufend = in_buffer + my_fread(infile, BUFFERSIZE);
in_bufpos = in_buffer;
}
}
} else {
*out_bufpos = a;
out_bufpos++;
if (out_bufpos == out_bufend) {
my_fwrite(out_buffer,outfile,BUFFERSIZE);
out_bufpos = out_buffer;
}
}
}
/* Check for remainder in output buffer */
if (out_bufpos != out_buffer)
my_fwrite(out_buffer,outfile,(int)(out_bufpos - out_buffer));
}
/*
* convert_tunix() ... convert files to use LF as EOL
*
* Inputs:
* FILE *infile File to read from
* FILE *outfile File to write to
*
* Outputs:
* None
*/
void convert_tunix (FILE *infile, FILE *outfile) {
unsigned char a;
unsigned char *in_bufpos;
unsigned char *out_bufpos;
unsigned char *in_bufend;
unsigned char *out_bufend;
size_t file_remain;
in_bufpos = in_buffer;
out_bufpos = out_buffer;
(void) fseek(infile,0L,SEEK_END);
file_remain = ftell(infile);
rewind(infile);
in_bufend = in_buffer + my_fread(infile, BUFFERSIZE);
out_bufend = out_buffer + BUFFERSIZE;
while (file_remain != 0) {
a = *in_bufpos;
in_bufpos++;
if (in_bufpos >= in_bufend) {
file_remain -= in_bufend - in_buffer;
in_bufend = in_buffer + my_fread(infile, BUFFERSIZE);
in_bufpos = in_buffer;
}
if(a == CR) {
*out_bufpos = LF;
out_bufpos++;
if (out_bufpos == out_bufend) {
my_fwrite(out_buffer,outfile,BUFFERSIZE);
out_bufpos = out_buffer;
}
if (*in_bufpos == LF && file_remain != 0) {
in_bufpos++;
if (in_bufpos >= in_bufend) {
file_remain -= in_bufend - in_buffer;
in_bufend = in_buffer + my_fread(infile, BUFFERSIZE);
in_bufpos = in_buffer;
}
}
} else {
*out_bufpos = a;
out_bufpos++;
if (out_bufpos == out_bufend) {
my_fwrite(out_buffer,outfile,BUFFERSIZE);
out_bufpos = out_buffer;
}
}
}
/* Check for remainder in output buffer */
if (out_bufpos != out_buffer)
my_fwrite(out_buffer,outfile,(int)(out_bufpos - out_buffer));
}
/*
* convert_fast_gs() ... convert files to use CR as EOL
* Do not care about differing EOL chars in the same file,
* do not allow '\0' bytes, and replace in-vitro if possible.
*
* Inputs:
* FILE *infile File to read from
* FILE *outfile File to write to
*
* Outputs:
* int FALSE if no conversion took place, TRUE otherwise
*/
int convert_fast_gs(FILE *infile, FILE *outfile) {
unsigned char a;
unsigned char *in_bufpos;
unsigned char *in_bufend;
size_t file_remain;
enum file_format infile_type;
in_bufpos = in_buffer;
(void) fseek(infile,0L,SEEK_END);
file_remain = ftell(infile);
rewind(infile);
in_bufend = in_buffer + my_fread(infile,BUFFERSIZE);
*in_bufend = '\0';
infile_type = get_file_format (in_buffer);
switch (infile_type) {
case apple:
if (verbose)
printf("%s: %s is already in Apple format, skipping.\n",
program_name,current_file);
return (FALSE);
break;
case tunix:
/* Replace "in-vitro", so out_buffer isn't used */
while (file_remain != 0) {
a = *in_bufpos;
if (a == LF)
*in_bufpos++ = CR;
else if (a == '\0') { /* End of buffer reached */
/* Write changed buffer out */
my_fwrite(in_buffer,outfile,(int)(in_bufend - in_buffer));
/* And reload it */
file_remain -= in_bufend - in_buffer;
in_bufend = in_buffer + my_fread(infile, BUFFERSIZE);
*in_bufend = '\0';
in_bufpos = in_buffer;
} else in_bufpos++;
}
return (TRUE);
break;
case dos:
/* This I couldn't speed up, so use the existing thing */
convert_gs (infile, outfile);
return (TRUE);
break;
case binary:
return (FALSE);
break;
default:
fprintf(stderr,"%s: Fatal internal error\n",program_name);
exit (EXIT_FAILURE);
break;
} /* switch */
}
/*
* convert_fast_messy() ... convert files to use CR/LF as EOL
* Just check if it's already in DOS format.
*
* Inputs:
* FILE *infile File to read from
* FILE *outfile File to write to
*
* Outputs:
* int FALSE if no conversion took place, TRUE otherwise
*/
int convert_fast_messy (FILE *infile, FILE *outfile) {
unsigned char *in_bufend;
enum file_format infile_type;
in_bufend = in_buffer + my_fread(infile, BUFFERSIZE);
*in_bufend = '\0';
infile_type = get_file_format (in_buffer);
switch (infile_type) {
case dos:
if (verbose)
printf("%s: %s is already in MS-DOS format, skipping.\n",
program_name,current_file);
return (FALSE);
break;
case tunix: /* drop through */
case apple:
/* Wasn't able to speed this up, call old routine */
convert_messy (infile, outfile);
return (TRUE);
break;
case binary:
return (FALSE);
break;
default:
fprintf(stderr,"%s: Fatal internal error\n",program_name);
exit (EXIT_FAILURE);
break;
} /* switch */
}
/*
* convert_fast_tunix() ... convert files to use LF as EOL
* Do not care about differing EOL chars in the same file,
* do not allow '\0' bytes, and replace in-vitro if possible.
*
* Inputs:
* FILE *infile File to read from
* FILE *outfile File to write to
*
* Outputs:
* int FALSE if no conversion took place, TRUE otherwise
*/
int convert_fast_tunix (FILE *infile, FILE *outfile) {
unsigned char a;
unsigned char *in_bufpos;
unsigned char *in_bufend;
size_t file_remain;
enum file_format infile_type;
in_bufpos = in_buffer;
(void) fseek(infile,0L,SEEK_END);
file_remain = ftell(infile);
rewind(infile);
in_bufend = in_buffer + my_fread(infile, BUFFERSIZE);
*in_bufend = '\0';
infile_type = get_file_format (in_buffer);
switch (infile_type) {
case tunix:
if (verbose)
printf("%s: %s is already in Unix format, skipping.\n",
program_name,current_file);
return (FALSE);
break;
case apple:
/* Replace "in-vitro", so out_buffer isn't used */
while (file_remain != 0) {
a = *in_bufpos;
if (a == CR)
*in_bufpos++ = LF;
else if (a == '\0'){ /* End of buffer reached */
/* Write changed buffer out */
my_fwrite(in_buffer,outfile,(int)(in_bufend - in_buffer));
/* And reload */
file_remain -= in_bufend - in_buffer;
in_bufend = in_buffer + my_fread(infile, BUFFERSIZE);
*in_bufend = '\0';
in_bufpos = in_buffer;
} else in_bufpos++;
}
return (TRUE);
break;
case dos:
/* Couldn't speed it up, so use old routine */
convert_tunix (infile, outfile);
return (TRUE);
break;
case binary:
return (FALSE);
break;
default:
fprintf(stderr,"%s: Fatal internal error\n", program_name);
exit (EXIT_FAILURE);
break;
} /* switch */
}
/*
* get_file_format() ... look at a buffer and find out what the EOL
* character is. If no EOL character is found, print an error message
* and exit.
*
* Inputs:
* unsigned char *buffer Buffer to search through, terminated
* by '\0'.
*
* Output:
* enum file_format tunix, dos, apple, or binary
*/
enum file_format get_file_format (unsigned char *buffer) {
unsigned char c;
enum file_format result = unknown;
while ((c = *buffer++) != '\0') {
if (c == LF) {
result = tunix;
break;
} else if (c == CR) {
if (*buffer == LF)
result = dos;
else
result = apple;
break;
}
}
if (result == unknown) {
if (verbose)
printf("%s: No EOL found on the first %d bytes "
"of %s. Might be a binary file. File skipped\n",
program_name,BUFFERSIZE, current_file);
result = binary;
}
return (result);
}
/*
* tryopen() ... try to open a file, exit if unsuccesful
*
* Inputs:
* char *name Name of file to be opened
* char *mode Mode string for fopen() call
*
* Output:
* FILE * File identifier of successful fopen()
*/
FILE *tryopen (char *name, char *mode) {
FILE *tmp;
if ((tmp = fopen(name,mode)) == NULL) {
fprintf(stderr,"%s: Unable to open file %s\n",program_name, name);
exit (EXIT_FAILURE);
} else
return (tmp);
}
/*
* my_fread() ... read data into global buffer and exit if I fail
*
* Inputs:
* FILE *infile File to read from
* int howmuch Number of bytes to read
*
* Output:
* int Number of bytes actually read
*/
int my_fread(FILE *infile, int howmuch) {
int result;
result = (int)fread(in_buffer, 1, howmuch, infile);
if (ferror(infile)) {
fprintf(stderr,"%s: Error while reading data\n",program_name);
exit (EXIT_FAILURE);
}
return (result);
}
/*
* my_fwrite() ... write data from global buffer to file
*
* Inputs:
* unsigned char *buffer Buffer to write out
* FILE *outfile File to write to
* int howmuch Number of bytes to write
*
* Output:
* None
*/
void my_fwrite (unsigned char *buffer, FILE *outfile, int howmuch) {
fwrite(buffer, 1, howmuch, outfile);
if (ferror(outfile)) {
fprintf(stderr,"%s: Error while writing data\n",program_name);
exit (EXIT_FAILURE);
}
return;
}
/*
* cleanup() ... called in case of an exit(). Frees memory I allocated.
*
* Inputs:
* None
*
* Output:
* None
*/
void cleanup (void) {
char **p;
free (program_name);
free (current_file);
free (in_buffer);
free (out_buffer);
free (tempfile);
if (pathList) {
p = pathList;
while(*p) free(*p++);
free (pathList);
}
if (tempfile)
remove (tempfile);
}
/*
* usage() ... print out a usage string gotten from udluse.c
*
* Inputs:
* None
*
* Outputs:
* None
*/
void usage (void) {
extern char use1[]; /* from udluse.c */
#ifdef __GNO__
extern char use2[];
#endif
fprintf(stderr,"%s",use1);
#ifdef __GNO__
if(!needsgno())
fprintf(stderr,"%s",use2);
#endif
return;
}
/*
* build_file_list() build the list of files to process
*
* Precondition:
* file is the file name to be added to the pathList
* recurse if non-zero, directories will be recursed
*
* Postcondition:
* pathList will be a NULL-terminated array of strings. Each
* string is a partial pathname (relative to rootdir) of a file
* to convert.
*
* Note: This is a recursive routine that uses up (3 * sizeof(char *))
* bytes of stack with each level of subdirectories.
*/
void build_file_list(char *file, short recurse) {
char *thisdir;
DIR *dir;
struct dirent *entry;
#ifdef __DJGPP__ /* chdir() doesn't accept dir names ending in '\\' */
if(file[strlen(file)-1] == '\\')
file[strlen(file)-1] = '/';
#endif
/* check for stack overflow */
recursionDepth++;
#ifdef OVERFLOW_CHECK
if ((recursionDepth * BYTES_PER_DEPTH + BASESIZE) > STACKSIZE) {
fprintf(stderr,"%s: Exceeded permitted nesting depth (%d levels)\n"
"Aborted.\n",program_name,recursionDepth);
exit(EXIT_FAILURE);
}
#endif
if (stat(file,&tstat)!=0) {
fprintf(stderr,"%s: Couldn't stat %s. File skipped\n",program_name,file);
--recursionDepth;
return;
}
if (recurse && S_ISDIR(tstat.st_mode)) {
char tstr[2];
/*
* It is a directory. recurse through it.
*/
/* save our state */
tstr[0] = dirbrk;
tstr[1] = '\0';
if (*currentDirectory) {
thisdir = strdup(currentDirectory);
} else {
thisdir = malloc(1);
if (thisdir != NULL) *thisdir='\0';
}
if (thisdir == NULL) {
perror("Couldn't duplicate current directory");
exit (EXIT_FAILURE);
}
if (*currentDirectory) strcat(currentDirectory,tstr);
strcat(currentDirectory,file);
if (currentDirectory[strlen(currentDirectory)-1] == dirbrk)
currentDirectory[strlen(currentDirectory)-1] = '\0';
/* recurse */
if ((dir = opendir(file)) == NULL) {
fprintf(stderr,"%s: Couldn't open %s. Directory skipped.\n",
program_name,currentDirectory);
} else {
if (chdir(file) !=0) {
fprintf(stderr,"couldn't cd to %s\n",currentDirectory);
exit (EXIT_FAILURE);
}
#ifdef READDIR_RETURNS_DOT
entry = readdir(dir); /* for "." */
entry = readdir(dir); /* for ".." */
#endif
while ((entry = readdir(dir))!=NULL) {
/* ignore hidden files */
#ifdef BROKEN_DIRENT_STRUCT
if (*(entry->d_name)!='.') build_file_list((entry->d_name)-2,1);
#else
if (*(entry->d_name)!='.') build_file_list(entry->d_name,1);
#endif
}
if (*thisdir) {
if ((chdir(rootdir)!=0) || (chdir(thisdir)!=0)) {
fprintf(stderr,"couldn't cd to %s\n",thisdir);
exit (EXIT_FAILURE);
}
} else {
if (chdir(rootdir)!=0) {
fprintf(stderr,"couldn't cd to calling directory\n");
exit (EXIT_FAILURE);
}
}
}
/* restore our state */
strcpy(currentDirectory,thisdir);
free(thisdir);
} else if (S_ISREG(tstat.st_mode)) {
/* It is a normal file. Add it to the pathList */
add_to_pathList(currentDirectory, file);
}
--recursionDepth;
return;
}
void add_to_pathList(char *thisdir, char *file) {
char **p;
/* expand the pathList if necessary */
if (pathSlotsUsed >= pathSlots) {
pathSlots += PATHLIST_QUANTUM;
#if BROKEN_REALLOC
if ((pathList==NULL) &&
((pathList = malloc((pathSlots+1) * sizeof(char *)))==NULL)) {
fprintf(stderr,"%s: Couldn't expand pathList\n",program_name);
exit (EXIT_FAILURE);
} else {
if ((p = realloc(pathList, (pathSlots+1) * sizeof(char *)))==NULL) {
fprintf(stderr,"%s: Couldn't expand pathList\n",program_name);
exit (EXIT_FAILURE);
}
pathList = p;
}
#else
if ((p = realloc(pathList,(pathSlots+1) * sizeof(char *)))==NULL) {
fprintf(stderr,"%s: Couldn't expand pathList\n",program_name);
exit (EXIT_FAILURE);
} else pathList = p;
#endif
}
/* add in the current directory and filename to the pathList */
pathList[pathSlotsUsed] = malloc(strlen(thisdir)+strlen(file)+2);
if (pathList[pathSlotsUsed] == NULL) {
fprintf(stderr,"%s: Couldn't duplicate filename %s%c%s\n",program_name,
thisdir,dirbrk,file);
exit (EXIT_FAILURE);
}
if (*thisdir) {
sprintf(pathList[pathSlotsUsed],"%s%c%s",thisdir,dirbrk,file);
} else {
strcpy(pathList[pathSlotsUsed],file);
}
pathSlotsUsed++;
pathList[pathSlotsUsed] = NULL;
return;
}
/* Mktemp() construct a unique file name
*
* This routine is slightly different than the Unix standard one,
* thus the capitalization.
*
* Inputs:
* base Template to construct the name upon. It should
* be in the format "nameXXXXXX" where all "X" are replaced
* in such a way that the resulting name is unique. There
* should be at least one, at most 15 "X" in the base name.
* base may contain a full or partial path.
*
* Outputs:
* Mktemp() returns a pointer to a dynamically allocated string
* containing a unique file name.
*
*/
char *Mktemp(const char *base)
{
static char id[16] = "AAAAAAAAAAAAAAA";
char *p1,*p2,*st;
if ((st = malloc(strlen(base) + 1)) == NULL)
{
fprintf(stderr,"%s: memory allocation failure\n", program_name);
exit (EXIT_FAILURE);
}
st = strcpy(st,base);
if (*st == '\0')
{
free (st);
if ((st = strdup("TXXXXXXX")) == NULL)
{
fprintf(stderr,"%s: memory allocation failure\n", program_name);
exit (EXIT_FAILURE);
}
}
/* Replace all "X" with part of ID string */
for(p1 = st + strlen(st) - 1,p2 = &id[14];
p1 >= st && p2 >= id && *p1 == 'X';
p1--,p2--)
*p1 = *p2;
/* Update ID string to "count" one further */
for(p1 = &id[14];p1 >= id;)
if(*p1 == 'Z')
{
*p1 = 'A';
p1--;
} else {
*p1 += 1;
break;
}
/* Make sure the file name does not already exist */
#ifdef __GNO__
if (needsgno() == TRUE) {
#endif
if (stat(st,&tstat) == 0)
{
free (st);
st = Mktemp (base);
}
#ifdef __GNO__
} else { /* ORCA/Shell doesn't like stat one little bit */
FILE *fp;
if ((fp = fopen(st,"r")) != NULL)
{
fclose(fp);
free (st);
st = Mktemp (base);
} else if ((fp = fopen(st,"a")) == NULL) {
free(st);
st = Mktemp (base);
} else {
fclose(fp);
}
}
#endif
return st;
}
/* get_path() ... extract path from filename
*
* Inputs:
* name A file name containing a full, partial or no path.
*
* Outputs:
* Pointer to a string in static memory containing the path
* to the given file, or an empty string if "name" contained
* no path. The string can hold MAXPATHLEN characters.
*/
char *get_path (const char *name)
{
int i;
strcpy(filebuffer, name);
for (i = (int)strlen(filebuffer) - 1; i > 0 && filebuffer[i] != dirbrk; i--)
; /* empty loop to find end of path in name */
if (i != 0)
++i;
filebuffer[i] = '\0';
return filebuffer;
}
/* End Of File */