summaryrefslogtreecommitdiff
path: root/usr/src/lib/libcmd/common/cat.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libcmd/common/cat.c')
-rw-r--r--usr/src/lib/libcmd/common/cat.c381
1 files changed, 381 insertions, 0 deletions
diff --git a/usr/src/lib/libcmd/common/cat.c b/usr/src/lib/libcmd/common/cat.c
new file mode 100644
index 0000000000..884726e572
--- /dev/null
+++ b/usr/src/lib/libcmd/common/cat.c
@@ -0,0 +1,381 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1992-2007 AT&T Knowledge Ventures *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Knowledge Ventures *
+* *
+* 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) 2006-05-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;
+
+ 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:
+ if (flags&S_FLAG)
+ {
+ while (states[*++cp]==T_NEWLINE)
+ line++;
+ cp--;
+ }
+ do
+ {
+ cp++;
+ 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))
+ {
+ 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;
+}