📄 csplit.c
字号:
/* * Donated to public domain * * Designation: CSplit * * Description: 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 program implements the following specifications: * * 1) a. Combine multiple source files. * b. Split source into 90 line sections. * c. Add header and trailer marker lines delimiting each * section and file. * 2) a. Delete any trailing whitespace. * b. Replace tabs with spaces honoring tabstop boundaries. * c. Default to 4 columns per tabstop. * d. Allow user to specify alternate tabstop column number. * 3) a. Wrap lines longer than 75 characters long using the C * "\ at the end of a line" notation (using space break). * b. Distinguish wrapped lines from user-continued lines by * inserting a line with a single "\" character between the * two lines that contain the wrapped text. * 4) a. Calculate a CRC for each section and include it in the * section trailer marker lines. * 5) a. Provide a help display for program usage when the * program is executed without parameters. * 6) a. Provide as detailed of explanation as possible when * an unexpected condition occurs. * b. Attempt to continue execution for all but the most severe * errors. * * * Syntax: * * Split: CSPLIT [/tn] [/wn] [/ln] [/sc] outfile src.ext [ ... ] *|* Extract: CSPLIT /x infile [ ... ] * * Where: /t n - For TAB character expansion, the number of columns * for each TAB stop. (defaults to every 4 columns) * /w n - For width control, the column number to be used for * breaking long lines. (the default is column 75) * /l n - For length control, the number of lines to limit|* each section or 0 for no split. (default is 90) * /s c - Use 'c' as an alternate line separator character * instead of the default separator character, '>'.|* Ignored for extraction - matches separator found|* in extract file. However, the extract file must|* only use one separator character. * infile - Input file name. An extension indicates that the * file contains the sections in proper consecutive|* order ready for extraction. Otherwise, infile.001,|* infile.002, etc., will be used.|* 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 only under non-ANSI compiling conditions. *|* Notes: Paths are supported for all filenames, however, the paths|* are not preserved internally during the split operation.|* The extraction process will therefore only create files in|* the current directory. * * Revision History: ( thanks to all the contributors ) * * 08/31/93 Fred Cole Original draft * 09/05/93 Fred Cole Added CRC calculation and extraction ability. * Fixed a line wrap problem. * 09/14/93 Fred Cole Added conditional compilation directives to * allow non-ANSI filespec support. Squashed an * extract() function 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 Fred Cole Fixed a cleanup() function bug. * 12/09/93 Keith Campbell / TS * Fixed bug with options preceded by '-' and fixed * tempfile opening bug. * 01/02/94 David Nugent / FC * Additions for findfirst/findnext support for * MSC6 (& 7) and OS/2 in initlist() routine and * portable.h header file. * 01/02/94 Auke Reitsma / FC * Increased number of chars 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 * redundant line increment. *--- v2.0 -------------------------------------------------------------- * 07/23/94 Keith Campbell / FC * Modified to not abort extraction when a CRC * mismatch occurs - just issue warning message. * 07/30/94 Auke Reitsma / FC * Added multiple file extraction ability. * 09/17/94 Keith Campbell / FC * Added version separator lines. * 10/28/94 Bob Stout / FC * Added separator character, width and length * command line options. * 12/18/94 Fred Cole Revised code to facilitate maintenance. * 12/27/94 Fred Cole Limited the minimum width for breaking long * lines to column 55 since this is the length * of the longest separator line. * 01/15/95 David Gersic / FC * Modified the line wrap logic to handle long * sequences of characters lacking whitespace. *--- v2.1 -------------------------------------------------------------- * 10/30/95 Phi Nguyen / FC * Added file extraction messages. * 10/31/95 Fred Cole Added ability to extract unconcatenated files. * Added path support except for extracted files * ( i.e., paths are not preserved internally ). * 11/06/95 Fred Cole Corrected tabstop calculation on wrapped lines. * 11/07/95 Fred Cole Increased max section length to SHRT_MAX lines. * 11/08/95 Bob Stout / FC * Disable the split logic when a 0 section length * is specified with the /L command line option. *--- v2.2 -------------------------------------------------------------- * 11/22/95 Fred Cole Modified logic to ignore leading whitespace added * to separator lines ( mail reader quoting? ). * 11/22/95 Doug Nazar (DN2) / FC * Modified sscanf() format specifiers to correctly * convert CRC values for 32 bit platforms. * 11/22/95 Fred Cole Changed TRUE/FALSE enum to macros to accommodate * systems where these identifiers already exist. * 11/29/95 Bob Stout / FC * Added unsigned casts to allow signed 'length' to * be compared to SHRT_MAX on 16-bit platforms. * 11/29/95 Doug Nazar (DN2) / FC * Added setbuf() statement to unbuffer stdout. * 06/02/96 Fred Cole Renamed TRUE/FALSE macros to avoid possible * identifier conflicts. * 06/02/96 Darin McBride / FC * Modified logic to allow source files located on * on another drive to be processed. This change * assumes that ':' is not a valid character for a * file name. * 06/02/96 Fred Cole Corrected error in extract logic when file does * not exist. */#include <ctype.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <limits.h>#include "csplit.h"char tempfile[MAXFSPEC + 1]; /* necessary evils - global variables */FILE *finp = NULL;FILE *fout = NULL;FILE *ftmp = NULL;SLST *head = NULL;SLST *cur = NULL;int main (int argc, char *argv[]){ char sepchar = SEP_CDEF; char outfile[MAXFSPEC + 1]; char *sptr = 0; int argndx = 1; int chr = 0; int extract = B_FALSE; int length = LENDEF; int retc = 0; int tabstop = TABDEF; int width = WIDDEF; setbuf (stdout, 0); /* DN2: buffered output fix */ printf ("\nCSplit %s (pd) 1993-1996 by Fred Cole\n", VERSION); printf ("This executable program is public domain.\n\n"); if (1 == argc) { disp_help (); return SYNTAX; } while (('/' == argv[argndx][0]) || ('-' == argv[argndx][0])) { chr = toupper (argv[argndx][1]); switch (chr) { case '?': case 'H': /* /H,/? help option */ disp_help (); return SYNTAX; case 'X': /* /X extract option */ extract = B_TRUE; break; case 'T': /* /T tab option */ tabstop = atoi (&argv[argndx][2]); if ((tabstop < TABMIN) || (tabstop > TABMAX)) printf ("Invalid tab parameter \"%s\" (%d-%d).\n", argv[argndx], TABMIN, TABMAX); if (tabstop < TABMIN) tabstop = TABMIN; else if (tabstop > TABMAX) tabstop = TABMAX; break; case 'W': /* /W width option */ width = atoi (&argv[argndx][2]); if ((width < WIDMIN) || (width > WIDMAX)) printf ("Invalid width parameter \"%s\" (%d-%d).\n", argv[argndx], WIDMIN, WIDMAX); if (width < WIDMIN) width = WIDMIN; else if (width > WIDMAX) width = WIDMAX; break; case 'L': /* /L length option */ if (('0' == argv[argndx][2]) && ('\0' == argv[argndx][3])) length = 0; else { length = atoi (&argv[argndx][2]); if ((length < LENMIN) || ((unsigned)length > LENMAX)) printf ("Invalid length parameter \"%s\" (0,%d-%d).\n", argv[argndx], LENMIN, LENMAX); if (length < LENMIN) length = LENDEF; else if ((unsigned)length > LENMAX) length = LENMAX; } break; case 'S': /* /S separator character option */ sscanf (&argv[argndx][2], "%c", &sepchar); if (0 == isgraph (sepchar)) { printf ("Invalid input parameter \"%s\".\n", argv[argndx]); sepchar = SEP_CDEF; } break; default: printf ("Ignoring unknown input parameter \"%s\".\n", argv[argndx]); } ++argndx; } if (B_TRUE == extract) { if (argndx == argc) { printf ("No file argument specified for extraction.\n"); return SYNTAX; } /* AR: handle multiple files; break on error */ for ( ; argndx < argc; ++argndx) if (NOERR != (retc = extr_file (argv[argndx], sepchar))) break; cleanup (); return retc; } if ((argc - argndx) < 2) { printf ("Missing input and/or output file name arguments.\n"); disp_help (); return SYNTAX; } if (NULL != (sptr = strrchr (argv[argndx], '\\'))) /* ignore path */ { if (NULL != (sptr = strchr (sptr, '.'))) *sptr = '\0'; /* truncate any ext */ } else if (NULL != (sptr = strchr (argv[argndx], '.'))) { *sptr = '\0'; /* truncate any ext */ } if (strlen (argv[argndx]) > MAXFSPEC) { printf ("Output file name argument too long.\n"); return SYNTAX; } strncpy (outfile, argv[argndx], MAXFSPEC); outfile[MAXFSPEC] = '\0'; /* ensure termination */ if (NOERR != (retc = init_list (argc, argv, ++argndx))) { cleanup (); return retc; } retc = split_src (head, outfile, length, width, tabstop, sepchar); cleanup (); return retc;}/* * add_list - Add a file name to linked list of files to be processed. */SLST *add_list (char *fname){ SLST *new = NULL; if (NULL == (new = (SLST *)malloc (sizeof(SLST)))) { puts ("Error allocating memory.\n"); } else { strcpy (new->srcfile, fname); new->next = NULL; if (NULL == cur) head = new; else cur->next = new; } cur = new; return cur;}/* * cleanup - Just a convenient way to provide centralized housekeeping. */void cleanup (void){ free_list (); if (NULL != finp) fclose (finp); if (NULL != fout) fclose (fout); if (NULL != ftmp) fclose (ftmp); /* Now, does it really exist? */ if (NULL != (ftmp = fopen (tempfile, "r"))) { fclose (ftmp); remove (tempfile); }}/* * csp_fgets - A custom fgets() function that expands * tabs, deletes trailing whitespace and * performs line wrapping. */char *csp_fgets (char *s, int len, FILE * fp, int tabstop){ static char sbuf[LLENMAX * 2]; /* big enough for TAB expansion */ static char *beg = sbuf; static int tofs = 0; static int wrap = B_FALSE; char *e = 0; char *w = 0; char *p = s; char *q = 0; int ch = 0; int cnt = 0; int i = 0; int spaces = 0; if (B_TRUE == wrap) /* if line wrap */ { tofs += (int)(beg - sbuf); /* adj. TAB column offset */ strcpy (s, "\\\n"); memmove (sbuf, beg, strlen (beg) + 1); /* DG: Modification for */ beg = sbuf; /* DG: long lines w/o WS */ wrap = B_FALSE; return s; } while ((cnt < len-1) && ('\n' != ch)) { /* get next char from buffer */ if (0 == (ch = *beg++)) /* if buffer empty */ { memset (sbuf, 0, sizeof (sbuf)); beg = fgets (sbuf, LLENMAX, fp); /* grab another string */ if (NULL == beg) /* if end of file... */ { beg = sbuf; *beg = 0; if (0 == cnt) return NULL; /* and buffer empty */ } else { w = e = &sbuf[i = strlen (sbuf)]; /* find 1st trailing ws char */ while ((w > sbuf) && (isspace (*(w - 1)))) --w; if (('\n' == *(e - 1)) || /* if terminated w/newline char */ (i < (len-1))) /* or unterminated short line */ { *w++ = '\n'; /* terminate with newline char */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -