cut.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#
/* cut : cut and paste columns of a table (projection of a relation) */
/* Release 1.5; handles single backspaces as produced by nroff */
#include <ctype.h>
#include <limits.h>
#include <locale.h>
#include <wchar.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/* as input args */
void bfunc();
void bnfunc();
void cfunc();
void ffunc();
void process_list(char *list);
void diag(const char *s);
void usage(void);
int dellen;
int supflag = 0;
int rstart[MAX_RANGES];
int rend[MAX_RANGES];
int nranges = 0;
char dummy[MB_LEN_MAX];
int bufsiz;
int
{
int c;
char *list;
int status = 0;
void (*funcp)();
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
switch (c) {
case 'b':
usage();
bflag++;
break;
case 'c':
usage();
cflag++;
break;
case 'd':
if (dellen == -1) {
diag("no delimiter specified");
diag("invalid delimiter");
dflag++;
break;
case 'f':
usage();
fflag++;
break;
case 'n':
nflag++;
break;
case 's':
supflag++;
break;
case '?':
usage();
}
/* you must use one and only one option -b, -c, or -f */
usage();
/*
* Make sure combination of options is correct
*/
if (nflag) {
"cut: -n may only be used with -b\n"));
usage();
}
}
if (dflag)
"cut: -d may only be used with -f\n"));
if (supflag)
"cut: -s may only be used with -f\n"));
usage();
}
}
if (cflag) {
} else if (bflag) {
if (nflag)
else
} else { /* fflag */
}
if (nranges == 0)
diag("no list specified");
filenr = 0;
do { /* for all input files */
else
"cut: cannot open %s\n"),
status = 1;
continue;
}
(*funcp)();
return (status);
}
void
char *list;
{
int inrange = 0;
int start = 0;
int num = 0;
char *p;
int i, j;
int tmp;
/* first, parse list of ranges */
do {
p = rlist;
switch (*p) {
case '-':
if (inrange)
diag("invalid range specifier");
inrange = 1;
if (num == 0)
start = 1;
else {
num = 0;
}
break;
case '\0':
case ',':
case ' ':
case '\t':
/*
* this is temporary - it will change
* when the isblank() routine becomes
* available.
*/
if (nranges == MAX_RANGES)
diag("too many ranges specified");
if (inrange) {
if (num == 0)
diag("ranges must be "
"increasing");
nranges++;
} else {
nranges++;
}
num = 0;
start = 0;
inrange = 0;
if (*p == '\0')
continue;
break;
default:
if (!isdigit(*p))
diag("invalid character in range");
rlist++;
continue;
}
rlist++;
} while (*p != '\0');
/* then, consolidate ranges where possible */
for (i = 0; i < (nranges - 1); i++) {
for (j = i + 1; j < nranges; j++) {
rstart[i] = 0;
rend[i] = 0;
break;
}
}
}
/* then, weed out the zero'ed/consolidated entries */
for (i = 0; i < nranges; ) {
for (j = i; j < (nranges - 1); j++) {
}
nranges--;
diag("Internal error processing input");
} else {
i++;
}
}
/* finally, sort the remaining entries */
for (i = 0; i < (nranges - 1); i++) {
for (j = i+1; j < nranges; j++) {
}
}
}
#ifdef DEBUG
/* dump ranges */
for (i = 0; i < nranges; i++) {
rend[i]);
}
#endif
}
/* called when -c is used */
/* print out those characters selected */
void
cfunc()
{
wint_t c; /* current character */
int pos = 0; /* current position within line */
int inrange = 0; /* is 'pos' within a range */
int rndx = 0; /* current index into range table */
if (c == '\n') {
(void) putchar('\n');
/* reset per-line variables */
pos = 0;
inrange = 0;
rndx = 0;
} else {
pos++;
/*
* check if current character is within range and,
* if so, print it.
*/
if (!inrange)
inrange = 1;
if (inrange) {
(void) putwchar(c);
inrange = 0;
rndx++;
/*
* optimization -
* check for last range index
* and eat chars until newline
* if so.
*/
}
}
}
}
}
void
bfunc() /* called when -b is used but -n is not */
{
int c; /* current character */
int pos = 0; /* current position within line */
int inrange = 0; /* is 'pos' within a range */
int rndx = 0; /* current index into range table */
if (c == L'\n') {
(void) putchar('\n');
/* reset per-line variables */
pos = 0;
inrange = 0;
rndx = 0;
} else {
pos++;
/*
* check if current character is within range and,
* if so, print it.
*/
if (!inrange)
inrange = 1;
if (inrange) {
(void) putchar(c);
inrange = 0;
rndx++;
/*
* optimization -
* check for last range index
* and eat chars until newline
* if so.
*/
}
}
}
}
}
void
bnfunc() /* called when -b -n is used */
{
wint_t c; /* current character */
int pos = 0; /* current position within line */
int inrange = 0; /* is 'pos' within a range */
int rndx = 0; /* current index into range table */
int wlen; /* byte length of current wide char */
if (c == '\n') {
(void) putchar('\n');
/* reset per-line variables */
pos = 0;
inrange = 0;
rndx = 0;
} else {
diag("invalid multibyte character");
/*
* when trying to figure this out, remember that
* pos is actually pointing to the start byte of
* the next char.
*/
/*
* if char starts after beginning of range,
* for the moment, consider it in range.
*/
if (!inrange)
inrange = 1;
/*
* If tail of the multibyte is out of the range.
* do not print the character.
* (See XCU4)
*/
if (inrange)
inrange = 0;
rndx++;
}
/*
* if we still think the character is in range
* after the above, we print it.
*/
if (inrange)
(void) putwchar(c);
}
}
}
wchar_t *
{
wint_t c;
int charcnt;
/* alloc the line buffer if it isn't already there */
diag("unable to allocate enough memory");
}
charcnt = 0;
if (c == '\n') {
return (linebuf);
} else {
charcnt++;
/*
* there is no line length limitation so we
* have to be ready to expand the line buffer.
*/
diag("unable to allocate "
"enough memory");
}
*cp++ = c;
}
}
return (linebuf);
} else
return (NULL);
}
void
ffunc() /* called when -f is used */
{
int fpos; /* current field position within line */
int inrange; /* is 'pos' within a range */
int rndx; /* current index into range table */
int need_del; /* need to put a delimiter char in output */
/* first, prune out line with no delimiters */
#if !defined(__lint) /* lint doesn't grok "%ws" */
if (!supflag)
#endif
continue;
}
/* init per-line variable */
fpos = 1;
inrange = 0;
rndx = 0;
need_del = 0;
/* why continue processing if no more ranges? */
break;
/* find the next field delimiter */
if (!inrange)
inrange = 1;
if (inrange) {
if (need_del)
/*
* if there are no more delimiters
* and we are in the range, print
* out the rest of the line.
*/
#if !defined(__lint) /* lint doesn't grok "%ws" */
#endif
break;
}
else
need_del = 1;
inrange = 0;
rndx++;
}
}
}
(void) putchar('\n');
}
}
void
diag(const char *s)
{
exit(2);
}
void
usage(void)
{
"usage: cut -b list [-n] [filename ...]\n"
" cut -c list [filename ...]\n"
" cut -f list [-d delim] [-s] [filename]\n"));
exit(2);
}