"Fossies" - the Fresh Open Source Software Archive

Member "schily-2021-09-18/paste/paste.c" (20 Aug 2021, 6833 Bytes) of package /linux/privat/schily-2021-09-18.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* @(#)paste.c  1.22 21/08/20 Copyright 1985-2021 J. Schilling */
    2 #include <schily/mconfig.h>
    3 #ifndef lint
    4 static  const char sccsid[] =
    5     "@(#)paste.c    1.22 21/08/20 Copyright 1985-2021 J. Schilling";
    6 #endif
    7 /*
    8  *  Paste some files together
    9  *
   10  *  Copyright (c) 1985-2021 J. Schilling
   11  */
   12 /*
   13  * The contents of this file are subject to the terms of the
   14  * Common Development and Distribution License, Version 1.0 only
   15  * (the "License").  You may not use this file except in compliance
   16  * with the License.
   17  *
   18  * See the file CDDL.Schily.txt in this distribution for details.
   19  * A copy of the CDDL is also available via the Internet at
   20  * http://www.opensource.org/licenses/cddl1.txt
   21  *
   22  * When distributing Covered Code, include this CDDL HEADER in each
   23  * file and include the License file CDDL.Schily.txt from this distribution.
   24  */
   25 
   26 #include <schily/mconfig.h>
   27 #include <schily/stdio.h>
   28 #include <schily/stdlib.h>
   29 #include <schily/unistd.h>  /* For sys/types.h to make off_t available */
   30 #include <schily/standard.h>
   31 #define GT_COMERR       /* #define comerr gtcomerr */
   32 #define GT_ERROR        /* #define error gterror   */
   33 #include <schily/schily.h>
   34 #include <schily/nlsdefs.h>
   35 
   36 #define MIN_LINELEN 4096        /* Min line size  */
   37 #define INCR_LINELEN    4096        /* Increment for line size */
   38 #define MAX_FILES   (256-3)     /* Max # of files */
   39 
   40 LOCAL   BOOL    eofp[MAX_FILES];    /* Files that did hit EOF */
   41 LOCAL   FILE    *filep[MAX_FILES] = {0}; /* Files to work on */
   42 LOCAL   char    *delim;
   43 LOCAL   int delimlen;
   44 LOCAL   int empty;
   45 
   46 LOCAL   char    *line;          /* Output line */
   47 LOCAL   size_t  linelen = MIN_LINELEN;
   48 LOCAL   int linesize = -1;
   49 
   50 LOCAL   void    usage   __PR((int exitcode));
   51 EXPORT  int main    __PR((int ac, char ** av));
   52 LOCAL   void    paste   __PR((int n));
   53 LOCAL   void    spaste  __PR((FILE *f));
   54 LOCAL   int parsedelim __PR((char *d));
   55 
   56 LOCAL void
   57 usage(exitcode)
   58     int exitcode;
   59 {
   60     error("Usage:   paste [options] file1...filen\n");
   61     error("Options:\n");
   62     error("\td=list\t\tuse 'list' as delimiter instead of 'tab'.\n");
   63     error("\t-e\t\tdo not output empty lines.\n");
   64     error("\t-s\t\tpaste lines of one file instead of one line per file.\n");
   65     error("\twidth=#,w=#\tmaximum output linewidth (default infinite).\n");
   66     error("\t-help\t\tPrint this help.\n");
   67     error("\t-version\tPrint version information and exit.\n");
   68     exit(exitcode);
   69 }
   70 
   71 EXPORT int
   72 main(ac, av)
   73     int ac;
   74     char    *av[];
   75 {
   76     int i = 0;          /* Count # of input files */
   77 
   78     char    *options = "help,version,d*,e,s,width#,w#";
   79     int help    = 0;
   80     int prvers  = 0;
   81     int ser = 0;
   82     int cac;
   83     char    * const *cav;
   84 
   85     save_args(ac, av);
   86 
   87     (void) setlocale(LC_ALL, "");
   88 
   89 #ifdef  USE_NLS
   90 #if !defined(TEXT_DOMAIN)   /* Should be defined by cc -D */
   91 #define TEXT_DOMAIN "paste" /* Use this only if it weren't */
   92 #endif
   93     { char  *dir;
   94     dir = searchfileinpath("share/locale", F_OK,
   95                     SIP_ANY_FILE|SIP_NO_PATH, NULL);
   96     if (dir)
   97         (void) bindtextdomain(TEXT_DOMAIN, dir);
   98     else
   99 #if defined(PROTOTYPES) && defined(INS_BASE)
  100     (void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
  101 #else
  102     (void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
  103 #endif
  104     (void) textdomain(TEXT_DOMAIN);
  105     }
  106 #endif  /* USE_NLS */
  107 
  108     cac = --ac;
  109     cav = ++av;
  110 
  111     if (getallargs(&cac, &cav, options, &help, &prvers,
  112                     &delim, &empty, &ser,
  113                     &linesize, &linesize) < 0) {
  114         errmsgno(EX_BAD, "Bad flag: %s.\n", cav[0]);
  115         usage(EX_BAD);
  116     }
  117     if (help)
  118         usage(0);
  119 
  120     if (prvers) {
  121         /* CSTYLED */
  122         gtprintf("Paste release %s (%s-%s-%s) Copyright (C) 1985-2021 %s\n",
  123                 "1.22",
  124                 HOST_CPU, HOST_VENDOR, HOST_OS,
  125                 _("Jörg Schilling"));
  126         exit(0);
  127     }
  128 
  129     if (delim) {
  130         delimlen = parsedelim(delim);
  131         if (delimlen == 0)
  132             comerrno(EX_BAD, "No delimiter.\n");
  133     } else {
  134         delim = "\t";
  135         delimlen = 1;
  136     }
  137     cac = ac;
  138     cav = av;
  139     for (; getfiles(&cac, &cav, options); cac--, cav++) {
  140         if (i >= MAX_FILES)
  141             comerrno(EX_BAD, "Cannot paste more than %d files.\n",
  142                 MAX_FILES);
  143         if (streql(*cav, "-"))
  144             filep[i++] = stdin;
  145         else if ((filep[i++] = fileopen(*cav, "r")) == (FILE *)NULL)
  146             comerr("Cannot open '%s'.\n", *cav);
  147         if (ser)
  148             spaste(filep[i-1]);
  149     }
  150 
  151     if (i == 0) {
  152         errmsgno(EX_BAD, "No files given.\n");
  153         usage(EX_BAD);
  154     }
  155     if (ser)
  156         return (0);
  157 
  158     if (linesize > 0)
  159         linelen = linesize;
  160     if ((line = malloc(linelen+2)) == NULL)
  161         comerr("Cannot malloc space for line.\n");
  162 
  163     paste(i);
  164     return (0);
  165 }
  166 
  167 LOCAL void
  168 paste(n)
  169     int n;      /* # of files to read from */
  170 {
  171     int k;
  172     register char   *lp;    /* pointer to line */
  173     register char   *ep;    /* pointer to end of line */
  174     register int    c;
  175     register FILE   *fp;
  176     register int    i;
  177 
  178     for (i = 0; i < n; i++)
  179         eofp[i] = FALSE;
  180     ep = &line[linelen];
  181 
  182     for (k = 0; k < n; ) {  /* Stop when all files hit EOF */
  183         lp = line;
  184         for (i = 0; i < n; i++) {
  185             if (!eofp[i]) {     /* No EOF on this file yet? */
  186                 fp = filep[i];
  187             again:
  188                 while ((c = getc(fp)) != EOF &&
  189                     c != '\n' && lp < ep)
  190                     *lp++ = c;
  191 
  192                 if (lp >= ep) {
  193                     char    *new = NULL;
  194                     static  BOOL didwarn = FALSE;
  195 
  196                     if (linesize < 0) {
  197                         /*
  198                          * Use dynamic line length,
  199                          */
  200                         linelen += INCR_LINELEN;
  201                         new = realloc(line,
  202                             linelen+2 + INCR_LINELEN);
  203                     } else {
  204                         didwarn = TRUE;
  205                     }
  206                     if (new == NULL) {
  207                         if (!didwarn)
  208                             errmsg(
  209                     "Cannot realloc space for line.\n");
  210                         didwarn = TRUE;
  211                     } else {
  212                         linelen += INCR_LINELEN;
  213                         lp += new - line;
  214                         ep = &new[linelen];
  215                         line = new;
  216                         goto again;
  217                     }
  218                     while ((c = getc(fp)) != EOF &&
  219                         c != '\n')
  220                         ;
  221                 }
  222             } else {        /* Avoid EOFing twice   */
  223                 c = '\n';   /* so pretend eol.  */
  224             }
  225 
  226             if (c == EOF) {
  227                 eofp[i] = EOF;
  228                 k++;        /* One file less */
  229             }
  230 
  231             if (i == (n-1)) {   /* Last file in line? */
  232                 *lp++ = '\n';
  233                 *lp   = '\0';
  234                 break;      /* Quit loop to print line */
  235             } else {        /* Add field delimiter */
  236                 c = delim[i%delimlen];
  237                 if (c)
  238                     *lp++ = c;
  239             }
  240         }
  241 
  242         /*
  243          * Print only if at least one file did have a line (k <  n).
  244          * With -e, print only lines that have more than delimiters.
  245          */
  246         if (lp-line > n || (!empty && k < n))
  247             filewrite(stdout, line, lp-line);
  248     }
  249 }
  250 
  251 LOCAL void
  252 spaste(f)
  253     FILE    *f;
  254 {
  255     register int    len;
  256     register int    i;
  257     register int    c;
  258 
  259     if ((len = fgetaline(f, &line, &linelen)) > 0) {
  260         for (i = 0; ; i++) {
  261             if (line[len-1] == '\n')
  262                 len--;
  263             filewrite(stdout, line, len);
  264             if ((len = fgetaline(f, &line, &linelen)) <= 0)
  265                 break;
  266             c = delim[i%delimlen];
  267             if (c)
  268                 putchar(c);
  269         }
  270     }
  271     putchar('\n');
  272     fclose(f);
  273 }
  274 
  275 LOCAL int
  276 parsedelim(d)
  277     char    *d;
  278 {
  279     int len = 0;
  280     int c;
  281 static  char    del[MAX_FILES];
  282 
  283     while (*d) {
  284         if ((c = *d++) != '\\') {
  285             del[len++] = c;
  286         } else {
  287             switch (c = *d++) {
  288 
  289             case '0':
  290                 c = 0;
  291                 break;
  292             case 't':
  293                 c = '\t';
  294                 break;
  295             case 'n':
  296                 c = '\n';
  297                 break;
  298             }
  299             del[len++] = c;
  300         }
  301         if (len >= MAX_FILES)
  302             break;
  303     }
  304     delim = del;
  305     return (len);
  306 }