diff options
author | chin <none@none> | 2007-08-17 12:01:52 -0700 |
---|---|---|
committer | chin <none@none> | 2007-08-17 12:01:52 -0700 |
commit | da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968 (patch) | |
tree | 5280d3b78e289fe9551371ab6e7f15ef9944ea14 /usr/src/lib/libcmd/common/join.c | |
parent | 073dbf9103ef2a2b05d8a16e2d26db04e0374b0e (diff) | |
download | illumos-joyent-da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968.tar.gz |
6437624 RFE: Add ksh93 (as /usr/bin/ksh93) and libshell.so to OS/Net
6505835 AST tools and library (libpp) required for creating l10n messages for ksh93
PSARC/2006/550 Korn Shell 93 Integration
PSARC/2006/587 /etc/ksh.kshrc for ksh93
PSARC/2007/035 ksh93 Amendments
Contributed by Roland Mainz <roland.mainz@nrubsig.org>
--HG--
rename : usr/src/lib/libcmd/common/mapfile-vers => deleted_files/usr/src/lib/libcmd/common/mapfile-vers
rename : usr/src/lib/libcmd/common/placeholder.c => deleted_files/usr/src/lib/libcmd/common/placeholder.c
Diffstat (limited to 'usr/src/lib/libcmd/common/join.c')
-rw-r--r-- | usr/src/lib/libcmd/common/join.c | 816 |
1 files changed, 816 insertions, 0 deletions
diff --git a/usr/src/lib/libcmd/common/join.c b/usr/src/lib/libcmd/common/join.c new file mode 100644 index 0000000000..1687c898ca --- /dev/null +++ b/usr/src/lib/libcmd/common/join.c @@ -0,0 +1,816 @@ +/*********************************************************************** +* * +* 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 Research + * + * join + */ + +static const char usage[] = +"[-?\n@(#)$Id: join (AT&T Research) 2006-10-31 $\n]" +USAGE_LICENSE +"[+NAME?join - relational database operator]" +"[+DESCRIPTION?\bjoin\b performs an \aequality join\a on the files \afile1\a " + "and \afile2\a and writes the resulting joined files to standard " + "output. By default, a field is delimited by one or more spaces " + "and tabs with leading spaces and/or tabs ignored. The \b-t\b option " + "can be used to change the field delimiter.]" +"[+?The \ajoin field\a is a field in each file on which files are compared. " + "By default \bjoin\b writes one line in the output for each pair " + "of lines in \afiles1\a and \afiles2\a that have identical join " + "fields. The default output line consists of the join field, " + "then the remaining fields from \afile1\a, then the remaining " + "fields from \afile2\a, but this can be changed with the \b-o\b " + "option. The \b-a\b option can be used to add unmatched lines " + "to the output. The \b-v\b option can be used to output only " + "unmatched lines.]" +"[+?The files \afile1\a and \afile2\a must be ordered in the collating " + "sequence of \bsort -b\b on the fields on which they are to be " + "joined otherwise the results are unspecified.]" +"[+?If either \afile1\a or \afile2\a is \b-\b, \bjoin\b " + "uses standard input starting at the current location.]" + +"[e:empty]:[string?Replace empty output fields in the list selected with" +" \b-o\b with \astring\a.]" +"[o:output]:[list?Construct the output line to comprise the fields specified " + "in a blank or comma separated list \alist\a. Each element in " + "\alist\a consists of a file number (either 1 or 2), a period, " + "and a field number or \b0\b representing the join field. " + "As an obsolete feature multiple occurrences of \b-o\b can " + "be specified.]" +"[t:separator|tabs]:[delim?Use \adelim\a as the field separator for both input" +" and output.]" +"[1:j1]#[field?Join on field \afield\a of \afile1\a. Fields start at 1.]" +"[2:j2]#[field?Join on field \afield\a of \afile2\a. Fields start at 1.]" +"[j:join]#[field?Equivalent to \b-1\b \afield\a \b-2\b \afield\a.]" +"[a:unpairable]#[fileno?Write a line for each unpairable line in file" +" \afileno\a, where \afileno\a is either 1 or 2, in addition to the" +" normal output. If \b-a\b options appear for both 1 and 2, then " + "all unpairable lines will be output.]" +"[v:suppress]#[fileno?Write a line for each unpairable line in file" +" \afileno\a, where \afileno\a is either 1 or 2, instead of the normal " + "output. If \b-v\b options appear for both 1 and 2, then " + "all unpairable lines will be output.] ]" +"[i:ignorecase?Ignore case in field comparisons.]" +"[B!:mmap?Enable memory mapped reads instead of buffered.]" + +"[+?The following obsolete option forms are also recognized: \b-j\b \afield\a" +" is equivalent to \b-1\b \afield\a \b-2\b \afield\a, \b-j1\b \afield\a" +" is equivalent to \b-1\b \afield\a, and \b-j2\b \afield\a is" +" equivalent to \b-2\b \afield\a.]" + +"\n" +"\nfile1 file2\n" +"\n" +"[+EXIT STATUS?]{" + "[+0?Both files processed successfully.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\bcut\b(1), \bcomm\b(1), \bpaste\b(1), \bsort\b(1), \buniq\b(1)]" +; + +#include <cmd.h> +#include <sfdisc.h> + +#define C_FILE1 001 +#define C_FILE2 002 +#define C_COMMON 004 +#define C_ALL (C_FILE1|C_FILE2|C_COMMON) + +#define NFIELD 10 +#define JOINFIELD 2 + +#define S_DELIM 1 +#define S_SPACE 2 +#define S_NL 3 + +typedef struct +{ + Sfio_t* iop; + char* name; + char* recptr; + int reclen; + int field; + int fieldlen; + int nfields; + int maxfields; + int spaces; + int hit; + int discard; + char** fieldlist; +} File_t; + +typedef struct +{ + unsigned char state[1<<CHAR_BIT]; + Sfio_t* outfile; + int* outlist; + int outmode; + int ooutmode; + char* nullfield; + int delim; + int buffered; + int ignorecase; + char* same; + int samesize; + File_t file[2]; +} Join_t; + +static void +done(register Join_t* jp) +{ + if (jp->file[0].iop && jp->file[0].iop != sfstdin) + sfclose(jp->file[0].iop); + if (jp->file[1].iop && jp->file[1].iop != sfstdin) + sfclose(jp->file[1].iop); + if (jp->outlist) + free(jp->outlist); + if (jp->file[0].fieldlist) + free(jp->file[0].fieldlist); + if (jp->file[1].fieldlist) + free(jp->file[1].fieldlist); + if (jp->same) + free(jp->same); + free(jp); +} + +static Join_t* +init(void) +{ + register Join_t* jp; + + if (jp = newof(0, Join_t, 1, 0)) + { + jp->state[' '] = jp->state['\t'] = S_SPACE; + jp->delim = -1; + jp->nullfield = 0; + if (!(jp->file[0].fieldlist = newof(0, char*, NFIELD + 1, 0)) || + !(jp->file[1].fieldlist = newof(0, char*, NFIELD + 1, 0))) + { + done(jp); + return 0; + } + jp->file[0].maxfields = NFIELD; + jp->file[1].maxfields = NFIELD; + jp->outmode = C_COMMON; + } + return jp; +} + +static int +getolist(Join_t* jp, const char* first, char** arglist) +{ + register const char* cp = first; + char** argv = arglist; + register int c; + int* outptr; + int* outmax; + int nfield = NFIELD; + char* str; + + outptr = jp->outlist = newof(0, int, NFIELD + 1, 0); + outmax = outptr + NFIELD; + while (c = *cp++) + { + if (c==' ' || c=='\t' || c==',') + continue; + str = (char*)--cp; + if (*cp=='0' && ((c=cp[1])==0 || c==' ' || c=='\t' || c==',')) + { + str++; + c = JOINFIELD; + goto skip; + } + if (cp[1]!='.' || (*cp!='1' && *cp!='2') || (c=strtol(cp+2,&str,10)) <=0) + { + error(2,"%s: invalid field list",first); + break; + } + c--; + c <<=2; + if (*cp=='2') + c |=1; + skip: + if (outptr >= outmax) + { + jp->outlist = newof(jp->outlist, int, 2 * nfield + 1, 0); + outptr = jp->outlist + nfield; + nfield *= 2; + outmax = jp->outlist + nfield; + } + *outptr++ = c; + cp = str; + } + /* need to accept obsolescent command syntax */ + while (1) + { + if (!(cp= *argv) || cp[1]!='.' || (*cp!='1' && *cp!='2')) + { + if (*cp=='0' && cp[1]==0) + { + c = JOINFIELD; + goto skip2; + } + break; + } + str = (char*)cp; + c = strtol(cp+2, &str,10); + if (*str || --c<0) + break; + argv++; + c <<= 2; + if (*cp=='2') + c |=1; + skip2: + if (outptr >= outmax) + { + jp->outlist = newof(jp->outlist, int, 2 * nfield + 1, 0); + outptr = jp->outlist + nfield; + nfield *= 2; + outmax = jp->outlist + nfield; + } + *outptr++ = c; + } + *outptr = -1; + return argv-arglist; +} + +/* + * read in a record from file <index> and split into fields + */ +static unsigned char* +getrec(Join_t* jp, int index, int discard) +{ + register unsigned char* sp = jp->state; + register File_t* fp = &jp->file[index]; + register char** ptr = fp->fieldlist; + register char** ptrmax = ptr + fp->maxfields; + register char* cp; + register int n = 0; + + if (cmdquit()) + return 0; + if (discard && fp->discard) + sfraise(fp->iop, SFSK_DISCARD, NiL); + fp->spaces = 0; + fp->hit = 0; + if (!(cp = sfgetr(fp->iop, '\n', 0))) + { + jp->outmode &= ~(1<<index); + return 0; + } + fp->recptr = cp; + fp->reclen = sfvalue(fp->iop); + if (jp->delim=='\n') /* handle new-line delimiter specially */ + { + *ptr++ = cp; + cp += fp->reclen; + } + else while (n!=S_NL) /* separate into fields */ + { + if (ptr >= ptrmax) + { + n = 2*fp->maxfields; + fp->fieldlist = newof(fp->fieldlist, char*, n + 1, 0); + ptr = fp->fieldlist + fp->maxfields; + fp->maxfields = n; + ptrmax = fp->fieldlist+n; + } + *ptr++ = cp; + if (jp->delim<=0 && sp[*(unsigned char*)cp]==S_SPACE) + { + fp->spaces = 1; + while (sp[*(unsigned char*)cp++]==S_SPACE); + cp--; + } + while ((n=sp[*(unsigned char*)cp++])==0); + } + *ptr = cp; + fp->nfields = ptr - fp->fieldlist; + if ((n=fp->field) < fp->nfields) + { + cp = fp->fieldlist[n]; + /* eliminate leading spaces */ + if (fp->spaces) + { + while (sp[*(unsigned char*)cp++]==S_SPACE); + cp--; + } + fp->fieldlen = (fp->fieldlist[n+1]-cp)-1; + return (unsigned char*)cp; + } + fp->fieldlen = 0; + return (unsigned char*)""; +} + +#if DEBUG_TRACE +static unsigned char* u1,u2,u3; +#define getrec(p,n,d) (u1 = getrec(p, n, d), sfprintf(sfstdout, "[G%d#%d@%I*d:%-.8s]", __LINE__, n, sizeof(Sfoff_t), sftell(p->file[n].iop), u1), u1) +#endif + +/* + * print field <n> from file <index> + */ +static int +outfield(Join_t* jp, int index, register int n, int last) +{ + register File_t* fp = &jp->file[index]; + register char* cp; + register char* cpmax; + register int size; + register Sfio_t* iop = jp->outfile; + + if (n < fp->nfields) + { + cp = fp->fieldlist[n]; + cpmax = fp->fieldlist[n+1]; + } + else + cp = 0; + if ((n=jp->delim)<=0) + { + if (fp->spaces) + { + /*eliminate leading spaces */ + while (jp->state[*(unsigned char*)cp++]==S_SPACE); + cp--; + } + n = ' '; + } + if (last) + n = '\n'; + if (cp) + size = cpmax-cp; + else + size = 0; + if (size==0) + { + if (!jp->nullfield) + sfputc(iop,n); + else if (sfputr(iop,jp->nullfield,n) < 0) + return -1; + } + else + { + last = cp[size-1]; + cp[size-1] = n; + if (sfwrite(iop,cp,size) < 0) + return -1; + cp[size-1] = last; + } + return 0; +} + +#if DEBUG_TRACE +static int i1,i2,i3; +#define outfield(p,i,n,f) (sfprintf(sfstdout, "[F%d#%d:%d,%d]", __LINE__, i1=i, i2=n, i3=f), outfield(p, i1, i2, i3)) +#endif + +static int +outrec(register Join_t* jp, int mode) +{ + register File_t* fp; + register int i; + register int j; + register int k; + register int n; + int* out; + + if (mode < 0 && jp->file[0].hit++) + return 0; + if (mode > 0 && jp->file[1].hit++) + return 0; + if (out = jp->outlist) + { + while ((n = *out++) >= 0) + { + if (n == JOINFIELD) + { + i = mode >= 0; + j = jp->file[i].field; + } + else + { + i = n & 1; + j = (mode<0 && i || mode>0 && !i) ? + jp->file[i].nfields : + n >> 2; + } + if (outfield(jp, i, j, *out < 0) < 0) + return -1; + } + return 0; + } + k = jp->file[0].nfields; + if (mode >= 0) + k += jp->file[1].nfields - 1; + for (i=0; i<2; i++) + { + fp = &jp->file[i]; + if (mode>0 && i==0) + { + k -= (fp->nfields - 1); + continue; + } + n = fp->field; + if (mode||i==0) + { + /* output join field first */ + if (outfield(jp,i,n,!--k) < 0) + return -1; + if (!k) + return 0; + for (j=0; j<n; j++) + { + if (outfield(jp,i,j,!--k) < 0) + return -1; + if (!k) + return 0; + } + j = n + 1; + } + else + j = 0; + for (;j<fp->nfields; j++) + { + if (j!=n && outfield(jp,i,j,!--k) < 0) + return -1; + if (!k) + return 0; + } + } + return 0; +} + +#if DEBUG_TRACE +#define outrec(p,n) (sfprintf(sfstdout, "[R#%d,%d,%lld,%lld:%-.*s{%d}:%-.*s{%d}]", __LINE__, i1=n, lo, hi, jp->file[0].fieldlen, cp1, jp->file[0].hit, jp->file[1].fieldlen, cp2, jp->file[1].hit), outrec(p, i1)) +#endif + +static int +join(Join_t* jp) +{ + register unsigned char* cp1; + register unsigned char* cp2; + register int n1; + register int n2; + register int n; + register int cmp; + register int same; + int o2; + Sfoff_t lo = -1; + Sfoff_t hi = -1; + + if ((cp1 = getrec(jp, 0, 0)) && (cp2 = getrec(jp, 1, 0)) || (cp2 = 0)) + { + n1 = jp->file[0].fieldlen; + n2 = jp->file[1].fieldlen; + same = 0; + for (;;) + { + n = n1 < n2 ? n1 : n2; +#if DEBUG_TRACE + if (!n && !(cmp = n1 < n2 ? -1 : (n1 > n2)) || n && !(cmp = (int)*cp1 - (int)*cp2) && !(cmp = jp->ignorecase ? strncasecmp((char*)cp1, (char*)cp2, n) : memcmp(cp1, cp2, n))) + cmp = n1 - n2; +sfprintf(sfstdout, "[C#%d:%d(%c-%c),%d,%lld,%lld%s]", __LINE__, cmp, *cp1, *cp2, same, lo, hi, (jp->outmode & C_COMMON) ? ",COMMON" : ""); + if (!cmp) +#else + if (!n && !(cmp = n1 < n2 ? -1 : (n1 > n2)) || n && !(cmp = (int)*cp1 - (int)*cp2) && !(cmp = jp->ignorecase ? strncasecmp((char*)cp1, (char*)cp2, n) : memcmp(cp1, cp2, n)) && !(cmp = n1 - n2)) +#endif + { + if (!(jp->outmode & C_COMMON)) + { + if (cp1 = getrec(jp, 0, 1)) + { + n1 = jp->file[0].fieldlen; + same = 1; + continue; + } + if ((jp->ooutmode & (C_FILE1|C_FILE2)) != C_FILE2) + break; + if (sfseek(jp->file[0].iop, (Sfoff_t)-jp->file[0].reclen, SEEK_CUR) < 0 || !(cp1 = getrec(jp, 0, 0))) + { + error(ERROR_SYSTEM|2, "%s: seek error", jp->file[0].name); + return -1; + } + } + else if (outrec(jp, 0) < 0) + return -1; + else if (lo < 0 && (jp->outmode & C_COMMON)) + { + if ((lo = sfseek(jp->file[1].iop, (Sfoff_t)0, SEEK_CUR)) < 0) + { + error(ERROR_SYSTEM|2, "%s: seek error", jp->file[1].name); + return -1; + } + lo -= jp->file[1].reclen; + } + if (cp2 = getrec(jp, 1, lo < 0)) + { + n2 = jp->file[1].fieldlen; + continue; + } +#if DEBUG_TRACE +sfprintf(sfstdout, "[2#%d:0,%lld,%lld]", __LINE__, lo, hi); +#endif + } + else if (cmp > 0) + { + if (same) + { + same = 0; + next: + if (n2 > jp->samesize) + { + jp->samesize = roundof(n2, 16); + if (!(jp->same = newof(jp->same, char, jp->samesize, 0))) + { + error(ERROR_SYSTEM|2, "out of space"); + return -1; + } + } + memcpy(jp->same, cp2, o2 = n2); + if (!(cp2 = getrec(jp, 1, 0))) + break; + n2 = jp->file[1].fieldlen; + if (n2 == o2 && *cp2 == *jp->same && !memcmp(cp2, jp->same, n2)) + goto next; + continue; + } + if (hi >= 0) + { + if (sfseek(jp->file[1].iop, hi, SEEK_SET) != hi) + { + error(ERROR_SYSTEM|2, "%s: seek error", jp->file[1].name); + return -1; + } + hi = -1; + } + else if ((jp->outmode & C_FILE2) && outrec(jp, 1) < 0) + return -1; + lo = -1; + if (cp2 = getrec(jp, 1, 1)) + { + n2 = jp->file[1].fieldlen; + continue; + } +#if DEBUG_TRACE +sfprintf(sfstdout, "[2#%d:0,%lld,%lld]", __LINE__, lo, hi); +#endif + } + else if (same) + { + same = 0; + if (!(cp1 = getrec(jp, 0, 0))) + break; + n1 = jp->file[0].fieldlen; + continue; + } + if (lo >= 0) + { + if ((hi = sfseek(jp->file[1].iop, (Sfoff_t)0, SEEK_CUR)) < 0 || + (hi -= jp->file[1].reclen) < 0 || + sfseek(jp->file[1].iop, lo, SEEK_SET) != lo || + !(cp2 = getrec(jp, 1, 0))) + { + error(ERROR_SYSTEM|2, "%s: seek error", jp->file[1].name); + return -1; + } + n2 = jp->file[1].fieldlen; + lo = -1; + if (jp->file[1].discard) + sfseek(jp->file[1].iop, (Sfoff_t)-1, SEEK_SET); + } + else if (!cp2) + break; + else if ((jp->outmode & C_FILE1) && outrec(jp, -1) < 0) + return -1; + if (!(cp1 = getrec(jp, 0, 1))) + break; + n1 = jp->file[0].fieldlen; + } + } +#if DEBUG_TRACE +sfprintf(sfstdout, "[X#%d:?,%p,%p,%d%,%d,%d%s]", __LINE__, cp1, cp2, cmp, lo, hi, (jp->outmode & C_COMMON) ? ",COMMON" : ""); +#endif + if (cp2) + { + if (hi >= 0 && + sfseek(jp->file[1].iop, (Sfoff_t)0, SEEK_CUR) < hi && + sfseek(jp->file[1].iop, hi, SEEK_SET) != hi) + { + error(ERROR_SYSTEM|2, "%s: seek error", jp->file[1].name); + return -1; + } +#if DEBUG_TRACE +sfprintf(sfstdout, "[O#%d:%02o:%02o]", __LINE__, jp->ooutmode, jp->outmode); +#endif + cp1 = (!cp1 && cmp && hi < 0 && !jp->file[1].hit && ((jp->ooutmode ^ C_ALL) <= 1 || jp->outmode == 2)) ? cp2 : getrec(jp, 1, 0); + cmp = 1; + n = 1; + } + else + { + cmp = -1; + n = 0; + } +#if DEBUG_TRACE +sfprintf(sfstdout, "[X#%d:%d,%p,%p,%d,%02o,%02o%s]", __LINE__, n, cp1, cp2, cmp, jp->ooutmode, jp->outmode, (jp->outmode & C_COMMON) ? ",COMMON" : ""); +#endif + if (!cp1 || !(jp->outmode & (1<<n))) + { + if (cp1 && jp->file[n].iop == sfstdin) + sfseek(sfstdin, (Sfoff_t)0, SEEK_END); + return 0; + } + if (outrec(jp, cmp) < 0) + return -1; + do + { + if (!getrec(jp, n, 1)) + return 0; + } while (outrec(jp, cmp) >= 0); + return -1; +} + +int +b_join(int argc, char** argv, void* context) +{ + register int n; + register char* cp; + register Join_t* jp; + char* e; + +#if !DEBUG_TRACE + cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY); +#endif + if (!(jp = init())) + error(ERROR_system(1),"out of space"); + for (;;) + { + switch (n = optget(argv, usage)) + { + case 0: + break; + case 'j': + /* + * check for obsolete "-j1 field" and "-j2 field" + */ + + if (opt_info.offset == 0) + { + cp = argv[opt_info.index - 1]; + for (n = strlen(cp) - 1; n > 0 && cp[n] != 'j'; n--); + n = cp[n] == 'j'; + } + else + n = 0; + if (n) + { + if (opt_info.num!=1 && opt_info.num!=2) + error(2,"-jfileno field: fileno must be 1 or 2"); + n = '0' + opt_info.num; + if (!(cp = argv[opt_info.index])) + { + argc = 0; + break; + } + opt_info.num = strtol(cp, &e, 10); + if (*e) + { + argc = 0; + break; + } + opt_info.index++; + } + else + { + jp->file[0].field = (int)(opt_info.num-1); + n = '2'; + } + /*FALLTHROUGH*/ + case '1': + case '2': + if (opt_info.num <=0) + error(2,"field number must positive"); + jp->file[n-'1'].field = (int)(opt_info.num-1); + continue; + case 'v': + jp->outmode &= ~C_COMMON; + /*FALLTHROUGH*/ + case 'a': + if (opt_info.num!=1 && opt_info.num!=2) + error(2,"%s: file number must be 1 or 2", opt_info.name); + jp->outmode |= 1<<(opt_info.num-1); + continue; + case 'e': + jp->nullfield = opt_info.arg; + continue; + case 'o': + /* need to accept obsolescent command syntax */ + n = getolist(jp, opt_info.arg, argv+opt_info.index); + opt_info.index += n; + continue; + case 't': + jp->state[' '] = jp->state['\t'] = 0; + n= *(unsigned char*)opt_info.arg; + jp->state[n] = S_DELIM; + jp->delim = n; + continue; + case 'i': + jp->ignorecase = !opt_info.num; + continue; + case 'B': + jp->buffered = !opt_info.num; + continue; + case ':': + error(2, "%s", opt_info.arg); + break; + case '?': + done(jp); + error(ERROR_usage(2), "%s", opt_info.arg); + break; + } + break; + } + argv += opt_info.index; + argc -= opt_info.index; + if (error_info.errors || argc!=2) + { + done(jp); + error(ERROR_usage(2),"%s", optusage(NiL)); + } + jp->ooutmode = jp->outmode; + jp->file[0].name = cp = *argv++; + if (streq(cp,"-")) + { + if (sfseek(sfstdin,(Sfoff_t)0,SEEK_CUR) < 0) + { + if (sfdcseekable(sfstdin)) + error(ERROR_warn(0),"%s: seek may fail",cp); + else + jp->file[0].discard = 1; + } + jp->file[0].iop = sfstdin; + } + else if (!(jp->file[0].iop = sfopen(NiL, cp, "r"))) + { + done(jp); + error(ERROR_system(1),"%s: cannot open",cp); + } + jp->file[1].name = cp = *argv; + if (streq(cp,"-")) + { + if (sfseek(sfstdin,(Sfoff_t)0,SEEK_CUR) < 0) + { + if (sfdcseekable(sfstdin)) + error(ERROR_warn(0),"%s: seek may fail",cp); + else + jp->file[1].discard = 1; + } + jp->file[1].iop = sfstdin; + } + else if (!(jp->file[1].iop = sfopen(NiL, cp, "r"))) + { + done(jp); + error(ERROR_system(1),"%s: cannot open",cp); + } + if (jp->buffered) + { + sfsetbuf(jp->file[0].iop, jp->file[0].iop, SF_UNBOUND); + sfsetbuf(jp->file[1].iop, jp->file[0].iop, SF_UNBOUND); + } + jp->state['\n'] = S_NL; + jp->outfile = sfstdout; + if (!jp->outlist) + jp->nullfield = 0; + if (join(jp) < 0) + { + done(jp); + error(ERROR_system(1),"write error"); + } + else if (jp->file[0].iop==sfstdin || jp->file[1].iop==sfstdin) + sfseek(sfstdin,(Sfoff_t)0,SEEK_END); + done(jp); + return error_info.errors; +} |