📄 csplit.c
字号:
/*
* CSplit.C
* This program is used to process source files for the purpose
* of transmission through a FidoNet (tm) echo in such a manner
* as to circumvent over-size message problems.
*
* This process is specified as follows:
*
* 1) a. Combine multiple source files
* b. Split into 50-60 line sections
* c. Add header and trailer markers
* delimiting each section and file
* 2) a. Delete trailing whitespace
* b. Replace tabs with spaces
* c. Default to 4 spaces per tab
* d. Allow user to specify alternate
* number of spaces per tab
* 3) a. Wrap lines longer than 75 characters
* long using the C "\ at the end of a
* line" notation (using space break).
* b. Wrapped lines will be followed by a
* line with a single "\" character then
* followed by the remainder of the line.
* 4) a. Calculate a CRC for each section and
* include in the section trailer line
* 5) a. Provide a help display for program usage when
* the program is executed without parameters
*
* Syntax:
*
* Extract: CSPLIT /x infile
*
* Split: CSPLIT [/tn] outfile src.ext [ ... ]
*
* Where: n - For TAB expansion, the number of spaces to
* replace each TAB character (the default is 4)
* infile - Name of file that contains the parts properly
* placed in consecutive order for extraction
* outfile - Name of the output file(s). The extension will
* be ignored if specified and each output file will
* be named such that the section number will be the
* extension (e.g., outfile.001, outfile.002, etc..)
* src.ext - The first source file..etc Wildcard filespecs are
* supported under non-ANSI compiling conditions.
* Filenames are limited to "8.3" string lengths to
* avoid separator line length problems.
*
* 08/31/93 Fred Cole Original draft
* 09/05/93 FC Added CRC calculation, fixed line wrap problem,
* added extraction ability, fixed a couple of bugs
* 09/14/93 FC Added conditional compilation directives to
* allow non-ANSI, multi-compiler, filespec support
* Squashed extract() bug
* 11/21/93 Thad Smith Test for incomplete input file on extraction.
* Remove spaces added in message transmission.
* Default to 90 lines /section.
* Fix tab expansion.
* 12/03/93 FC Fix file cleanup() bug.
* 12/09/93 Keith Campbell / TS
* Fix bug with options preceded by '-', fix
* tempfile opening bug, eliminate unused variables.
* Make sepcrc same type as crc.
* 01/02/94 david nugent / FC
* Additions for findfirst/findnext support for
* MSC6 (& 7) for OS/2 in initlist() routine
* 01/02/94 Auke Reitsma / FC
* Increased number of characters read in to prevent
* line numbers from becoming out-of-sync with input
* 01/12/94 Chad Wagner / FC
* Correction to initlist() function to eliminate
* the redundant line increment
*
* Donated to public domain
*/
#include "csplit.h"
FILE *Fin = NULL, /* necessary evils - global variables */
*Fout = NULL,
*Ftmp = NULL;
char tempfile[FNAME+1];
SLST *head = NULL,
*cur = NULL;
int main(int argc, char **argv)
{
char *ext, line[81], outfile[FNAME+1], *s;
int argndx = 1,
tab2spac = TABDEF,
lines_per_sect = LINES,
j, key, lines, curpart, maxpart, rc;
unsigned short crc;
printf("\nCSplit - (pd) 1993 Revision %s by Fred Cole\n", VERSION);
puts("This executable program is in public domain.\n");
if (('/' == argv[1][0]) || ('-' == argv[1][0]))
{
if ('x' == tolower(argv[1][1])) /* if extract option */
{
if (argc < 3)
{
disp_help();
return(HELP);
}
rc = extract(argv[2]);
cleanup();
return(rc);
}
else if ('t' == tolower(argv[1][1])) /* if tab option */
{
tab2spac = atoi(&argv[1][2]);
if ((tab2spac < TABMIN) || (tab2spac > TABMAX))
tab2spac = TABDEF;
argndx++;
}
}
if ((argc - argndx) < 2)
{
disp_help();
return(HELP);
}
if (strlen(argv[argndx]) > FNAME)
{
printf("Output filename too long: %s\n", argv[argndx]);
cleanup();
return(OUTFILE);
}
strcpy(outfile, argv[argndx]);
if (NULL == (ext = strstr(outfile, "."))) /* ignore any ext */
ext = &outfile[strlen(outfile)];
*ext = 0; /* make temp file name */
strcpy(tempfile, outfile);
strcat(tempfile, ".$$$");
if (NULL == (Ftmp = fopen(tempfile, "w+t")))
{
printf("Error creating temp file: %s\n", tempfile);
cleanup();
return(PROCESS);
}
if (NOERR != initlist(argc, argv, argndx+1))
{
cleanup();
return(MEMORY);
}
for (cur = head, lines = 0; NULL != cur; cur = cur->next)
{
if (NULL == Fin)
{
if (NULL == (Fin = fopen(cur->srcfile, "rt")))
{
printf("Error opening source file: %s\n", cur->srcfile);
cleanup();
return(INFILE);
}
rc = fprintf(Ftmp, "%s%s%s%s\n",
SEP_ID, SEP_BF, cur->srcfile, SEP_AR);
if (0 == rc)
{
puts("Error writing output\n");
cleanup();
return(WRITE);
}
lines++;
}
while (NULL != Fin)
{
/*
* The function my_fgets() is equivalent to fgets() in that it
* too reads n-1 characters or up to a newline character. This
* function additionally expands TAB characters, deletes trailing
* whitespace and will wrap lines exceeding the specified length.
*/
s = my_fgets(line, LENGTH, Fin, tab2spac);
if (NULL == s)
{
if (feof(Fin))
{
fclose(Fin);
Fin = NULL;
rc = fprintf(Ftmp, "%s%s%s%s\n",
SEP_ID, SEP_EF, cur->srcfile, SEP_AR);
if (0 == rc)
{
puts("Error writing output\n");
cleanup();
return(WRITE);
}
lines++; /* adjust line count */
}
else
{
puts("Error reading input\n");
cleanup();
return(READ);
}
} /* endif NULL string */
else
{
if (EOF == fputs(line, Ftmp))
{
puts("Error writing output\n");
cleanup();
return(WRITE);
}
lines++; /* increment line count */
} /* endif non-NULL string */
} /*endwhile*/
} /*endfor*/
if (lines < lines_per_sect) /* if only one section */
maxpart = 1;
else
{
maxpart = lines / lines_per_sect;
if (lines % lines_per_sect < 5)/* if < 5 lines in last section */
{
lines_per_sect--; /* decrement lines per section */
maxpart = lines / lines_per_sect;
}
if ((maxpart > 0) && /* why can't those go on one line? */
(lines % lines_per_sect > 0))
maxpart++; /* perform ceil function */
}
curpart = 1;
/* warn user if 1st output filename already in use */
sprintf(ext, ".%03.3d", curpart); /* make 1st output file name */
if (NULL != (Fout = fopen(outfile, "rt")))
{
key = 0;
printf("Output file already exists: %s\n", outfile);
do
{
printf("Overwrite? (y/n) ");
key = getchar();
puts("");
j = key;
while (j != '\n')
j = getchar(); /* eat all extra keystrokes */
if (('n' == key) || ('N' == key))
{
cleanup();
return(OUTFILE);
}
} while (('y' != key) && ('Y' != key));
fclose(Fout);
Fout = NULL;
}
if (NULL == freopen(tempfile, "rt", Ftmp))
{
printf("Error reopening temp file: %s\n", tempfile);
cleanup();
return(PROCESS);
}
initcrctab();
while (NULL != Ftmp)
{
if (NULL == Fout)
{
sprintf(ext, ".%03.3d", curpart); /* make output file name */
if (NULL == (Fout = fopen(outfile, "w+t")))
{
printf("Error opening output file: %s\n", outfile);
cleanup();
return(OUTFILE);
}
rc = fprintf(Fout, "%s%s%d/%d%s\n",
SEP_ID, SEP_BP, curpart, maxpart, SEP_AR);
if (0 == rc)
{
puts("Error writing output\n");
cleanup();
return(WRITE);
}
}
crc = 0;
lines = 0;
while ((lines < lines_per_sect) && (NULL != Ftmp))
{
s = fgets(line, 80, Ftmp);
if (NULL == s)
{
if (feof(Ftmp))
{
fclose(Ftmp);
Ftmp = NULL;
}
else
{
puts("Error reading input\n");
cleanup();
return(READ);
}
} /*endif NULL string*/
else
{
crc = updcrc(crc, (unsigned char *)line, strlen(line));
if (EOF == fputs(line, Fout))
{
puts("Error writing output\n");
cleanup();
return(WRITE);
}
lines++; /* increment line count */
} /*endif non-NULL string*/
} /*endwhile*/
if (0 == fprintf(Fout, "%s%s%d/%d crc: %04x %s\n",
SEP_ID, SEP_EP, curpart, maxpart, crc, SEP_AR))
{
puts("Error writing output\n");
cleanup();
return(WRITE);
}
fclose(Fout);
Fout = NULL;
curpart++;
} /*endwhile*/
cleanup();
return(NOERR);
}
/*
* cleanup() - Just a convenient way to provide housekeeping
* for all the places the code returns from main.
*/
void cleanup(void)
{
freelist();
if (NULL != Fin) fclose(Fin);
if (NULL != Fout) fclose(Fout);
if (NULL != Ftmp) fclose(Ftmp);
if (NULL != (Ftmp = fopen(tempfile, "rt")))
{
fclose(Ftmp);
remove(tempfile);
}
}
void disp_help(void)
{
puts("This utility is used to process source files for the purpose");
puts("of transmission through a FidoNet (tm) echo in such a manner");
puts("as to circumvent over-size message problems.\n");
puts("Syntax:\n");
puts("Extract: CSPLIT /x infile\n");
puts("Split: CSPLIT [/tn] outfile src.ext [ ... ]\n");
puts("Where: n - For TAB expansion, the number of spaces to");
puts(" replace each TAB character (defaults to 4)");
puts(" infile - File name that contains the parts properly");
puts(" placed in consecutive order for extraction");
puts(" outfile - Name of the output file(s). The extension");
puts(" will be the sequential section/part number");
puts(" (e.g., outfile.001, outfile.002, etc. ...)");
#if !defined(__STDC__)
puts(" src.ext - Source file(s)..etc. (w/wildcard support)");
#else
puts(" src.ext - Source file(s)..etc. (no wildcard support)");
#endif
}
int extract(char *ifn)
{
static char line[(LENGTH+1)*2], line2[(LENGTH+1)*2];
char outfile[FNAME+1], *s;
int i, in_section, key, lines,
curpart, maxpart, pos_wrap,
sepmax, seppart,
sep_id_len = strlen(SEP_ID);
unsigned short crc, sepcrc;
if (NULL == (Fin = fopen(ifn, "rt")))
{
printf("Error opening input file: %s\n", ifn);
return(INFILE);
}
crc = curpart = maxpart = lines = 0;
in_section = pos_wrap = FALSE;
Fout = NULL;
initcrctab();
*line2 = 0;
while (NULL != Fin)
{
s = fgets(line, LENGTH*2, Fin); /* increase input size */
/* Auke Reitsma */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -