Logo Search packages:      
Sourcecode: ksh version File versions  Download package

cat.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 1992-2007 AT&T Intellectual Property          *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                    by AT&T Intellectual Property                     *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                  David Korn <dgk@research.att.com>                   *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * David Korn
 * Glenn Fowler
 * AT&T Bell Laboratories
 *
 * cat
 */

#include <cmd.h>
#include <fcntl.h>

static const char usage[] =
"[-?\n@(#)$Id: cat (AT&T Research) 2007-07-17 $\n]"
USAGE_LICENSE
"[+NAME?cat - concatenate files]"
"[+DESCRIPTION?\bcat\b copies each \afile\a in sequence to the standard"
"     output. If no \afile\a is given, or if the \afile\a is \b-\b,"
"     \bcat\b copies from standard input starting at the current location.]"

"[b:number-nonblank?Number lines as with \b-n\b but omit line numbers from"
"     blank lines.]"
"[d:dos-input?Input files are opened in \atext\amode which removes carriage"
"     returns in front of new-lines on some systems.]"
"[e?Equivalent to \b-vE\b.]"
"[n:number?Causes a line number to be inserted at the beginning of each line.]"
"[s?Equivalent to \b-S\b for \aatt\a universe and \b-B\b otherwise.]"
"[t?Equivalent to \b-vT\b.]"
"[u:unbuffer?The output is not delayed by buffering.]"
"[v:show-nonprinting?Causes non-printing characters (whith the exception of"
"     tabs, new-lines, and form-feeds) to be output as printable charater"
"     sequences. ASCII control characters are printed as \b^\b\an\a,"
"     where \an\a is the corresponding ASCII character in the range"
"     octal 100-137. The DEL character (octal 0177) is copied"
"     as \b^?\b. Other non-printable characters are copied as \bM-\b\ax\a"
"     where \ax\a is the ASCII character specified by the low-order seven"
"     bits.  Multibyte characters in the current locale are treated as"
"     printable characters.]"
"[A:show-all?Equivalent to \b-vET\b.]"
"[B:squeeze-blank?Multiple adjacent new-line characters are replace by one"
"     new-line.]"
"[D:dos-output?Output files are opened in \atext\amode which inserts carriage"
"     returns in front of new-lines on some systems.]"
"[E:show-ends?Causes a \b$\b to be inserted before each new-line.]"
"[S:silent?\bcat\b is silent about non-existent files.]"
"[T:show-blank?Causes tabs to be copied as \b^I\b and formfeeds as \b^L\b.]"

"\n"
"\n[file ...]\n"
"\n"

"[+SEE ALSO?\bcp\b(1), \bgetconf\b(1), \bpr\b(1)]"
;

#define RUBOUT    0177

/* control flags */
#define B_FLAG          (1<<0)
#define E_FLAG          (1<<1)
#define F_FLAG          (1<<2)
#define N_FLAG          (1<<3)
#define S_FLAG          (1<<4)
#define T_FLAG          (1<<5)
#define U_FLAG          (1<<6)
#define V_FLAG          (1<<7)
#define D_FLAG          (1<<8)
#define d_FLAG          (1<<9)

/* character types */
#define T_ENDBUF  1
#define T_CONTROL 2
#define T_NEWLINE 3
#define T_EIGHTBIT      4
#define T_CNTL8BIT      5

#define printof(c)      ((c)^0100)

/*
 * called for any special output processing
 */

static int
vcat(register char* states, Sfio_t *fdin, Sfio_t *fdout, int flags)
{
      register unsigned char* cp;
      register unsigned char* cpold;
      register int            n;
      register int            m;
      register int            line = 1;
      register unsigned char* endbuff;
      unsigned char*          inbuff;
      int               printdefer = (flags&(B_FLAG|N_FLAG));
      int               lastchar;
      int               lastline;

      unsigned char           meta[4];

      meta[0] = 'M';
      meta[1] = '-';
      for (;;)
      {
            /* read in a buffer full */
            if (!(inbuff = (unsigned char*)sfreserve(fdin, SF_UNBOUND, 0)))
                  return sfvalue(fdin) ? -1 : 0;
            if ((n = sfvalue(fdin)) <= 0)
                  return n;
            cp = inbuff;
            lastchar = *(endbuff = cp + --n);
            *endbuff = 0;
            if (printdefer)
            {
                  if (states[*cp]!=T_NEWLINE || !(flags&B_FLAG))
                        sfprintf(fdout,"%6d\t",line);
                  printdefer = 0;
            }
            while (endbuff)
            {
                  cpold = cp;
                  /* skip over printable characters */
                  if (mbwide())
                        while ((n = (m = mbsize(cp)) < 2 ? states[*cp++] : (cp += m, states['a'])) == 0);
                  else
                        while ((n = states[*cp++]) == 0);
                  if (n==T_ENDBUF)
                  {
                        if (cp>endbuff)
                        {
                              if (!(n = states[lastchar]))
                              {
                                    *endbuff = lastchar;
                                    cp++;
                              }
                              else
                              {
                                    if (--cp > cpold)
                                          sfwrite(fdout,(char*)cpold,cp-cpold);
                                    if (endbuff==inbuff)
                                          *++endbuff = 0;
                                    cp = cpold = endbuff;
                                    cp[-1] = lastchar;
                                    if (n==T_ENDBUF)
                                          n = T_CONTROL;
                                    
                              }
                              endbuff = 0;
                        }
                        else n = T_CONTROL;
                  }
                  if (--cp>cpold)
                        sfwrite(fdout,(char*)cpold,cp-cpold);
                  switch(n)
                  {
                        case T_CNTL8BIT:
                              meta[2] = '^';
                              do
                              {
                                    n = (*cp++)&~0200;
                                    meta[3] = printof(n);
                                    sfwrite(fdout,(char*)meta,4);
                              }
                              while ((n=states[*cp])==T_CNTL8BIT);
                              break;
                        case T_EIGHTBIT:
                              do
                              {
                                    meta[2] = (*cp++)&~0200;
                                    sfwrite(fdout,(char*)meta,3);
                              }
                              while ((n=states[*cp])==T_EIGHTBIT);
                              break;
                        case T_CONTROL:
                              do
                              {
                                    n = *cp++;
                                    sfputc(fdout,'^');
                                    sfputc(fdout,printof(n));
                              }
                              while ((n=states[*cp])==T_CONTROL);
                              break;
                        case T_NEWLINE:
                              lastline = line;
                              if (flags&S_FLAG)
                              {
                                    while (states[*++cp]==T_NEWLINE)
                                          line++;
                                    cp--;
                              }
                              do
                              {
                                    cp++;
                                    if (flags&E_FLAG)
                                          sfputc(fdout,'$');
                                    sfputc(fdout,'\n');
                                    if(line > lastline)
                                    {
                                          if (flags&E_FLAG)
                                                sfputc(fdout,'$');
                                          sfputc(fdout,'\n');
                                    }
                                    if (!(flags&(N_FLAG|B_FLAG)))
                                          continue;
                                    line++;
                                    if (cp < endbuff)
                                          sfprintf(fdout,"%6d\t",line);
                                    else printdefer = 1;
                              }
                              while (states[*cp]==T_NEWLINE);
                              break;
                  }
            }
      }
}

int
b_cat(int argc, char** argv, void* context)
{
      register int            n;
      register int            flags = 0;
      register char*          cp;
      register Sfio_t*  fp;
      char*             mode;
      int               att;
      int               dovcat=0;
      char              states[UCHAR_MAX+1];

      NoP(argc);
      cmdinit(argc, argv, context, ERROR_CATALOG, 0);
      att = !strcmp(astconf("UNIVERSE", NiL, NiL), "att");
      mode = "r";
      for (;;)
      {
            switch (optget(argv, usage))
            {
            case 'A':
                  flags |= T_FLAG|E_FLAG|V_FLAG;
                  continue;
            case 'B':
                  flags |= S_FLAG;
                  continue;
            case 'b':
                  flags |= B_FLAG;
                  continue;
            case 'E':
                  flags |= E_FLAG;
                  continue;
            case 'e':
                  flags |= E_FLAG|V_FLAG;
                  continue;
            case 'n':
                  flags |= N_FLAG;
                  continue;
            case 's':
                  flags |= att ? F_FLAG : S_FLAG;
                  continue;
            case 'S':
                  flags |= F_FLAG;
                  continue;
            case 'T':
                  flags |= T_FLAG;
                  continue;
            case 't':
                  flags |= T_FLAG|V_FLAG;
                  continue;
            case 'u':
                  flags |= U_FLAG;
                  continue;
            case 'v':
                  flags |= V_FLAG;
                  continue;
            case 'd':
                  mode = "rt";
                  continue;
            case 'D':
                  flags |= d_FLAG;
                  continue;
            case ':':
                  error(2, "%s", opt_info.arg);
                  break;
            case '?':
                  error(ERROR_usage(2), "%s", opt_info.arg);
                  break;
            }
            break;
      }
      argv += opt_info.index;
      if (error_info.errors)
            error(ERROR_usage(2), "%s", optusage(NiL));
      memset(states, 0, sizeof(states));
      if (flags&V_FLAG)
      {
            memset(states, T_CONTROL, ' ');
            states[RUBOUT] = T_CONTROL;
            memset(states+0200, T_EIGHTBIT, 0200);
            memset(states+0200, T_CNTL8BIT, ' ');
            states[RUBOUT|0200] = T_CNTL8BIT;
            states['\n'] = 0;
      }
      if (flags&T_FLAG)
            states['\t'] = T_CONTROL;
      states[0] = T_ENDBUF;
      if (att)
      {
            if (flags&V_FLAG)
            {
                  states['\n'|0200] = T_EIGHTBIT;
                  if (!(flags&T_FLAG))
                  {
                        states['\t'] = states['\f'] = 0;
                        states['\t'|0200] = states['\f'|0200] = T_EIGHTBIT;
                  }
            }
      }
      else if (flags)
      {
            if (!(flags&T_FLAG))
                  states['\t'] = 0;
      }
      if (flags&(V_FLAG|T_FLAG|N_FLAG|E_FLAG|B_FLAG|S_FLAG))
      {
            states['\n'] = T_NEWLINE;
            dovcat = 1;
      }
      if (flags&B_FLAG)
            flags |= S_FLAG;
      if (flags&d_FLAG)
            sfopen(sfstdout, NiL, "wt");
      if (cp = *argv)
            argv++;
      do
      {
            if (!cp || streq(cp,"-"))
            {
                  fp = sfstdin;
                  if (flags&D_FLAG)
                        sfopen(fp, NiL, mode);
            }
            else if (!(fp = sfopen(NiL, cp, mode)))
            {
                  if (!(flags&F_FLAG))
                        error(ERROR_system(0), "%s: cannot open", cp);
                  error_info.errors = 1;
                  continue;
            }
            if (flags&U_FLAG)
                  sfsetbuf(fp, (void*)fp, -1);
            if (dovcat)
                  n = vcat(states, fp, sfstdout, flags);
            else if (sfmove(fp, sfstdout, SF_UNBOUND, -1) >= 0 && sfeof(fp))
                  n = 0;
            else
                  n = -1;
            if (fp != sfstdin)
                  sfclose(fp);
            if (n < 0 && errno != EPIPE)
            {
                  if (cp)
                        error(ERROR_system(0), "%s: read error", cp);
                  else
                        error(ERROR_system(0), "read error");
            }
            if (sferror(sfstdout))
                  break;
      } while (cp = *argv++);
      if (sfsync(sfstdout))
            error(ERROR_system(0), "write error");
      if (flags&d_FLAG)
            sfopen(sfstdout, NiL, "w");
      return error_info.errors;
}

Generated by  Doxygen 1.6.0   Back to index