⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 csplit.c

📁 C语言库函数的源代码,是C语言学习参考的好文档。
💻 C
📖 第 1 页 / 共 3 页
字号:
/* +++Date last modified: 05-Jul-1997 */

/*
 * 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 + -