Logo Search packages:      
Sourcecode: yencode version File versions

yencode.c

/**************************************************************************************************
      $Header: /pub/cvsroot/yencode/src/yencode.c,v 1.30 2002/03/18 17:20:06 bboy Exp $

      Copyright (C) 2002  Don Moore <bboy@bboy.net>

      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation; either version 2 of the License, or
      (at Your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.

      You should have received a copy of the GNU General Public License
      along with this program; if not, write to the Free Software
      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**************************************************************************************************/

#include "y.h"


int         opt_verbose = 1;                                      /* Should the program be verbose in its operation? */
int         opt_debug = 0;                                              /* Debug output? */
size_t      opt_multipart_size = (size_t)0;           /* Split size for multipart if splitting is desired */
int         opt_overwrite = 0;                                    /* Overwrite existing files? */
char        *opt_output_dir = NULL;                         /* Write output to this directory */
char        *opt_extension = Y_EXT;                         /* File extension */
int         opt_line_length = Y_LL;                         /* Line length */
int         opt_keep_paths = 0;                                   /* Strip paths from filenames? */

YENCFILE    **input_files = (YENCFILE **)NULL;  /* List of files to process */
int         num_input_files = 0;                                  /* Number of items in files */

/* Optional common support files */
int         opt_sfv = 0;                                                /* Create .SFV file? */
char        *opt_sfv_filename = (char *)NULL;   /* SFV filename */
int         opt_crc = 0;                                                /* Create .CRC file? */
char        *opt_crc_filename = (char *)NULL;   /* CRC filename */


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      USAGE
      Display program usage information.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
usage(int status)
{
      if (status != EXIT_SUCCESS)
      {
            fprintf(stderr, _("Try `%s --help' for more information."), progname);
            fputs("\n", stderr);
      }
      else
      {
            printf(_("Usage: %s [OPTION]... FILE..."), progname);
            puts("");
      puts(_("Usenet file encoder."));
            puts("");
//          puts("----------------------------------------------------------------------------78");
            puts(_("  -d, --debug           output extra debugging information while running"));
            puts(_("  -e, --extension=EXT   use EXT for file extension instead of the default"));
            puts(_("  -f, --force           overwrite existing files, never prompt"));
            puts(_("  -l, --line=LEN        output lines that are LEN bytes in length"));
            puts(_("  -m, --multipart=SIZE  create multipart output each containing SIZE bytes"));
            puts(_("                        (defaults to 620k if SIZE is not specified)"));
            puts(_("  -o, --output=DIR      create output in DIR instead of the current dir"));
            puts(_("  -p, --paths           maintain paths in input filenames"));
            puts(_("  -q, --quiet           inhibit all messages written to the standard output"));
            puts(_("      --sfv=NAME        create SFV checksum file for all input files"));
            puts(_("      --crc=NAME        create CRC checksum file for all input files"));
            puts(_("      --help            display this help and exit"));
            puts(_("      --version         output version information and exit"));
            puts("");
      puts(_("Report bugs to bugs@yencode.org."));
      }
      exit(status);
}
/*--- usage() -----------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      CMDLINE
      Process command line options.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
cmdline(int argc, char **argv)
{
      int  optc, optindex;
      char *optstr;
      struct option const longopts[] =
      {
            {"debug",               no_argument,                  NULL, 'd'},
            {"extension",           required_argument,      NULL, 'e'},
            {"force",               no_argument,                  NULL, 'f'},
            {"line",                      required_argument,      NULL, 'l'},
            {"multipart",           optional_argument,      NULL, 'm'},
            {"output",              required_argument,      NULL, 'o'},
            {"paths",               no_argument,                  NULL, 'p'},
            {"quiet",               no_argument,                  NULL, 'q'},
            {"sfv",                       optional_argument,      0,          0},
            {"crc",                       optional_argument,      0,          0},
            {"help",                      no_argument,                  0,          0},
            {"version",             no_argument,                  0,          0},

            {NULL, 0, NULL, 0}
      };

      optstr = getoptstr(longopts);
      while ((optc = getopt_long(argc, argv, optstr, longopts, &optindex)) != -1)
      {
            switch (optc)
            {
                  case 0:
                        {
                              const char *opt = longopts[optindex].name;

                              if (!strcmp(opt, "version"))                                                  // --version
                              {
                                    printf("%s - " PACKAGE " " VERSION "\n", short_progname);
                                    exit(EXIT_SUCCESS);
                              }
                              else if (!strcmp(opt, "help"))                                                // --help
                                    usage(EXIT_SUCCESS);
                              else if (!strcmp(opt, "sfv"))                                                 // --sfv
                              {
                                    opt_sfv = 1;
                                    opt_sfv_filename = optarg;
                              }
                              else if (!strcmp(opt, "crc"))                                                 // --crc
                              {
                                    opt_crc = 1;
                                    opt_crc_filename = optarg;
                              }
                        }
                        break;

                  case 'd':                                                                                                   // -d, --debug
                        opt_debug = opt_verbose = 1;
                        break;

                  case 'e':                                                                                                   // -e, --extension=EXT
                        opt_extension = optarg;
                        break;

                  case 'f':                                                                                                   // -f, --force
                        opt_overwrite = 1;
                        break;

                  case 'l':                                                                                                   // -l, --line
                        opt_line_length = atoi(optarg);
                        if (opt_line_length > 254)
                              Warn(_("line lengths greater than 254 are not allowed by the yEnc specification"));
                        break;

                  case 'm':                                                                                                   // -m, --multipart=SIZE
                        opt_multipart_size = 620000;
                        if (optarg)
                              opt_multipart_size = human_file_size(optarg);
                        break;

                  case 'o':                                                                                                   // -o, --output=DIR
                        {
                              struct stat st;
                              if (stat(optarg, &st))
                                    ErrERR("%s", optarg);
                              if (!S_ISDIR(st.st_mode))
                                    Err("%s: %s", optarg, _("not a directory"));
                              opt_output_dir = optarg;
                              while (opt_output_dir[strlen(opt_output_dir)-1] == '/')
                                    opt_output_dir[strlen(opt_output_dir)-1] = '\0';
                        }
                        break;

                  case 'p':                                                                                                   // -p, --paths
                        opt_keep_paths = 1;
                        break;

                  case 'q':                                                                                                   // -q, --quiet
                        opt_debug = opt_verbose = 0;
                        break;

                        default:
                        usage(EXIT_FAILURE);
            }
      }

      /* Set these options for the routines in "error.c" in the library */
      err_debug = opt_debug;
      err_verbose = opt_verbose;

      while (optind < argc)
      {
            YENCFILE *y = yencfile_create(argv[optind++], opt_output_dir, YSUPPORT_NOT_SPECIAL, opt_multipart_size);
            if (y)
            {
                  input_files = (YENCFILE **)xrealloc(input_files, (num_input_files + 1) * sizeof(YENCFILE *));
                  input_files[num_input_files++] = y;
            }
      }

      /* Some input must be specified.. */
      if (!num_input_files)
      {
            Warn(_("no input files"));
            usage(EXIT_FAILURE);
      }

      /* Make sure split size is sane */
      if (opt_multipart_size && opt_multipart_size < opt_line_length)
      {
            Warn(_("multipart file size (from -m) may not be less than line length (%d)"), opt_line_length);
            usage(EXIT_FAILURE);
      }
}
/*--- cmdline() ---------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      Outputs a summary line showing filenames, compression factor, etc.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
output_summary(const char *infile, const char *outfile, int part, int tpart,
                              size_t rawlen, size_t enclen)
{
      struct stat st;
      size_t z;

      if (!opt_verbose)
            return;

      z = (stat(outfile, &st)) ? enclen : st.st_size;
      usermsg(infile, outfile, part, tpart, _("file OK"), "(%.1f%%)", PCT(rawlen,z));
}
/*--- output_summary() --------------------------------------------------------------------------*/


/* Macro to "output" a byte using the output buffer */
#define OUT(c)                                                                                                                            \
      outbuf[ob] = (unsigned char)c;                                                                                    \
      if (++ob == BUFSIZ)                                                                                                           \
      {                                                                                                                                               \
            if (out && (fwrite(outbuf, sizeof(unsigned char), ob, out) != ob))      \
                  ErrERR("%s", outfile);                                                                                      \
            ob = 0;                                                                                                                             \
      }

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      YENCODE_DATA
      Copies data from `in' to `out', storing values in crc, pcrc, elen, and dlen if specified.
      `max_size' is the max number of data bytes to encode.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static size_t
yencode_data(FILE *in, const char *infile, FILE *out, const char *outfile,
                         crc32_t *crcp, crc32_t *pcrcp, size_t *elen, size_t *dlen,
                         size_t max_size)
{
      unsigned char inbuf[BUFSIZ], outbuf[BUFSIZ];                /* Output buffer */
      register int      ob;                                                               /* Offset in outbuf */
      register int      ct;                                                               /* Counter in buf */
      register unsigned char c;                                                     /* Current character */
      register size_t linect = 0;                                             /* Number of bytes output this line */
      register size_t total = 0;                                                    /* Total bytes output */
      register size_t want, rb;                                                     /* Bytes we want to read & actually read */

      /* Set initial value for `want', reset output buffer */
      want = (max_size && (max_size < BUFSIZ)) ? max_size : BUFSIZ;
      ob = 0;

      while ((rb = fread(inbuf, sizeof(unsigned char), want, in)) > 0)
      {
            for (ct = 0; ct < rb; ct++)
            {
                  c = inbuf[ct];
                  total++;
                  if (crcp) CRC_UPDATE(*crcp, c);
                  if (pcrcp) CRC_UPDATE(*pcrcp, c);
                  c = YENCODE(c);
                  if (elen) *elen += 1;
                  if (dlen) *dlen += 1;
                  if (YSHOULD_ESCAPE(c,linect,opt_line_length))
                  {
                        OUT('=');
                        c = YESCAPE(c);
                        if (elen) *elen += 1;
                        linect++;
                  }
                  OUT(c);
                  linect++;
                  if (linect >= opt_line_length)
                  {
                        OUT('\r');
                        OUT('\n');
                        if (elen) *elen += 2;
                        linect = 0;
                  }
            }
            if (max_size && total >= max_size)
                  break;
            if (rb < want)
                  break;
            /* Set amount to read on the next pass */
            want = (max_size && (max_size - total < BUFSIZ)) ? max_size - total : BUFSIZ;
      }

      /* Close the current line if we've output any data */
      if (linect)
      {
            OUT('\r');
            OUT('\n');
            if (elen) *elen += 2;
      }

      if (ob && out && (fwrite(outbuf, sizeof(unsigned char), ob, out) != ob))
            ErrERR("%s", outfile);

      if (ferror(in))
            ErrERR("%s", infile);

      return (total);
}
/*--- yencode_data() ----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      YENCODE_FILE
      Encode single or multipart data.
      Returns 1 if encoded successfully, 0 if not (wierd return value so we can count the number
      of successful files)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static int
yencode_file(YENCFILE *f, FILE *in, size_t insize)
{
      FILE        *out = NULL;                                                            /* Output file */
      char        outfile[PATH_MAX];                                                /* Output file name */
      crc32_t     pcrc32, crc32;                                                          /* CRC value for this part, file */
      int         part = 0, p;                                                            /* This part number */
      size_t      encsize = 0, decsize = 0;                                   /* Encoded/decoded size for entire file */
      size_t      encpart = 0, decpart = 0;                                   /* Encoded/decoded size for this part */
      size_t      e, d;                                                                         /* Return data from yencode_data() */
      int         rv = 1;                                                                       /* Return value from yencode_data */
      size_t      headers;                                                                      /* Length of headers for this file */
      int         totalparts = 1;                                                   /* Total number of parts to this archive */

      if (opt_multipart_size && insize > opt_multipart_size)
      {
            totalparts = insize / opt_multipart_size;
            if (insize % opt_multipart_size)
                  totalparts++;
      }
      else
            totalparts = 1;

      CRC_START(crc32);
      while (!feof(in))
      {
            /* Set part counters */
            part++;
            encpart = decpart = e = d = 0;

            /* Open output file for this part */
            if (opt_multipart_size)
                  snprintf(outfile, sizeof(outfile), "%s-%03d.%s", f->output_prefix, part, opt_extension);
            else
                  snprintf(outfile, sizeof(outfile), "%s.%s", f->output_prefix, opt_extension);
            if (!(out = open_output_file(outfile, opt_overwrite, f->input_filename)))
                  return (0);

            /* Write headers */
            if (opt_multipart_size)
            {
                  headers = fprintf(out, "=ybegin part=%d total=%d line=%d size=%u name=%s\r\n",
                                part, totalparts, opt_line_length, insize, STRIP_PATH(f->input_filename));
                  {
                        size_t remaining = insize - decsize;
                        off_t  begin = decsize + 1;

                        if (remaining < opt_multipart_size)
                              headers += fprintf(out, "=ypart begin=%lu end=%lu\r\n",
                                                                          (unsigned long)begin, (unsigned long)(begin+remaining-1));
                        else
                              headers += fprintf(out, "=ypart begin=%lu end=%lu\r\n",
                                                                          (unsigned long)begin, (unsigned long)(begin+opt_multipart_size-1));
                  }
            }
            else
            {
                  headers = fprintf(out, "=ybegin line=%d size=%u name=%s\r\n",
                                                             opt_line_length, insize, STRIP_PATH(f->input_filename));
            }

            /* Fill this file */
            CRC_START(pcrc32);
            rv = yencode_data(in, f->input_filename, out, outfile, &crc32, &pcrc32, &e, &d, opt_multipart_size);
            encpart += e; decpart += d;
            encsize += e; decsize += d;
            CRC_FINISH(pcrc32);

            /* Write footers */
            if (opt_multipart_size)
            {
                  headers += fprintf(out, "=yend part=%d total=%d size=%u pcrc32=%08X",
                                                              part, totalparts, decpart, pcrc32);
            }
            else
            {
                  CRC_FINISH(crc32);
                  headers += fprintf(out, "=yend size=%u crc32=%08X\r\n", insize, crc32);
                  f->ok = 1;
                  f->crc = crc32;
            }

            /* Close this file */
            fclose(out);

            output_summary(f->input_filename, outfile, part, totalparts, decpart, encpart + headers);

            if (decsize >= insize)
                  break;
      }

      /* Append the final CRC to the last output file, and CRLF's to the rest */
      if (opt_multipart_size)
      {
            CRC_FINISH(crc32);

            for (p = 1; p <= part; p++)
            {
                  snprintf(outfile, sizeof(outfile), "%s-%03d.%s", f->output_prefix, p, opt_extension);
                  if (!(out = fopen(outfile, "a")))
                        ErrERR("%s", outfile);
                  if (p == part)
                        fprintf(out, " crc32=%08X\r\n", crc32);
                  else
                        fprintf(out, "\r\n");
                  fclose(out);
            }

            f->ok = 1;
            f->crc = crc32;
      }
      return (f->ok);
}
/*--- yencode_file() ----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      Encodes the specified file in yEnc format.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static int
yencode(YENCFILE *f)
{
      struct stat st;                                                                     /* File stat info */
      FILE              *fp;                                                                    /* Input file pointer */
      int               rv;

      /*
      **  Verify and open the file to be encoded
      */
      if (stat(f->input_filename, &st))
      {
            WarnERR("%s", f->input_filename);
            return (0);
      }
      if (!S_ISREG(st.st_mode))
      {
            Warn("%s: %s", f->input_filename, _("not a regular file"));
            return (0);
      }
      if (!(fp = fopen(f->input_filename, "rb")))
      {
            WarnERR("%s", f->input_filename);
            return (0);
      }

      /*
      **  Create the encoded file(s)
      */
      rv = yencode_file(f, fp, st.st_size);
      fclose(fp);

      return (rv);
}
/*--- yencode() ---------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      MAIN
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int
main(int argc, char **argv)
{
      register int ct, good;

      set_progname(argv[0]);
      setlocale(LC_ALL, "");
      bindtextdomain(PACKAGE, LOCALEDIR);
      textdomain(PACKAGE);
      cmdline(argc, argv);
      qsort(input_files, num_input_files, sizeof(YENCFILE *), yencfile_cmp);

      /*
      **  Encode all files
      */
      for (good = ct = 0; ct < num_input_files; ct++)
            good += yencode(input_files[ct]);

      /*
      **  Create support files if requested
      */
      if (good)
      {
            if (opt_sfv)
                  sfv_create(opt_sfv_filename, input_files, num_input_files, opt_output_dir);
            if (opt_crc)
                  crc_create(opt_crc_filename, input_files, num_input_files, opt_output_dir);
      }

      return (EXIT_SUCCESS);
}
/*--- main() ------------------------------------------------------------------------------------*/

/* vi:set ts=3: */

Generated by  Doxygen 1.6.0   Back to index