628 lines
10 KiB
C
628 lines
10 KiB
C
|
/*
|
||
|
* a small awk clone
|
||
|
*
|
||
|
* (C) 1989 Saeko Hirabauashi & Kouichi Hirabayashi
|
||
|
*
|
||
|
* Absolutely no warranty. Use this software with your own risk.
|
||
|
*
|
||
|
* Permission to use, copy, modify and distribute this software for any
|
||
|
* purpose and without fee is hereby granted, provided that the above
|
||
|
* copyright and disclaimer notice.
|
||
|
*
|
||
|
* This program was written to fit into 64K+64K memory of the Minix 1.2.
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <ctype.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <fcntl.h>
|
||
|
#ifdef DOS
|
||
|
#include <process.h>
|
||
|
#endif
|
||
|
#include "awk.h"
|
||
|
#include "regexp.h"
|
||
|
|
||
|
#define MAXFLD 100
|
||
|
|
||
|
extern char **FS, **RS, **OFS, **ORS, **FILENAME;
|
||
|
extern double *NF, *NR;
|
||
|
extern double *FNR;
|
||
|
extern double *ARGC;
|
||
|
extern SYMBOL *argtab[];
|
||
|
extern CELL *getvar();
|
||
|
|
||
|
char *strsave(), *strcpy(), *getsval(), *jStrchr(), *strchr();
|
||
|
double getfval(), atof();
|
||
|
CELL *mkcell(), *mktmp(), *execute(), *patexec();
|
||
|
FILE *efopen();
|
||
|
|
||
|
extern CELL truecell, falsecell;
|
||
|
|
||
|
extern int pateval;
|
||
|
|
||
|
int infileno = 1;
|
||
|
FILE *ifp;
|
||
|
char record[BUFSIZ];
|
||
|
CELL *field[MAXFLD];
|
||
|
|
||
|
char *fs_str;
|
||
|
regexp *fs_pat;
|
||
|
|
||
|
CELL *
|
||
|
Getline(p) NODE *p;
|
||
|
{
|
||
|
CELL *u;
|
||
|
char *fnam, *s, str[BUFSIZ];
|
||
|
int i;
|
||
|
FILE *fp, *getfp();
|
||
|
|
||
|
if ((int) p->n_arg[0]) /* read into var */
|
||
|
s = str;
|
||
|
else
|
||
|
s = NULL;
|
||
|
if ((int) p->n_arg[1]) { /* file name */
|
||
|
u = execute(p->n_arg[1]);
|
||
|
fnam = getsval(u);
|
||
|
fp = getfp(fnam, (int) p->n_arg[2]);
|
||
|
c_free(u);
|
||
|
i = get1rec(s, fp);
|
||
|
}
|
||
|
else
|
||
|
i = Getrec(s);
|
||
|
if (s == str) {
|
||
|
u = execute(p->n_arg[0]);
|
||
|
setsval(u, str);
|
||
|
}
|
||
|
return mktmp(NUM, NULL, (double) i);
|
||
|
}
|
||
|
|
||
|
static
|
||
|
get1rec(buf, fp) char *buf; FILE *fp;
|
||
|
{
|
||
|
register int c;
|
||
|
register char rs, *s;
|
||
|
int mflg;
|
||
|
|
||
|
if (buf == NULL)
|
||
|
buf = record;
|
||
|
if ((rs = **RS) == '\0') { /* multi line record */
|
||
|
mflg = 1;
|
||
|
rs = '\n';
|
||
|
}
|
||
|
else
|
||
|
mflg = 0;
|
||
|
|
||
|
if (feof(fp) || (c = getc(fp)) == EOF)
|
||
|
return 0;
|
||
|
for (s = buf; ; ) {
|
||
|
for ( ; c != rs && c != EOF; c = getc(fp)) {
|
||
|
if (isKanji(c)) {
|
||
|
*s++ = c; c = getc(fp);
|
||
|
}
|
||
|
*s++ = c;
|
||
|
}
|
||
|
if (mflg) {
|
||
|
if ((c = getc(fp)) == '\n' || c == EOF)
|
||
|
break;
|
||
|
*s++ = '\n';
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
*s = '\0';
|
||
|
#if 1
|
||
|
if (buf == record) {
|
||
|
#else
|
||
|
if (buf == record && c != EOF) {
|
||
|
#endif
|
||
|
mkfld(record, *FS, field);
|
||
|
(*NR)++;
|
||
|
(*FNR)++;
|
||
|
}
|
||
|
return s > buf || c != EOF ? 1 : 0;
|
||
|
}
|
||
|
|
||
|
Getrec(s) char *s;
|
||
|
{
|
||
|
CELL *u;
|
||
|
char *file, str[8];
|
||
|
|
||
|
while (ifp == stdin || infileno < (int)*ARGC) {
|
||
|
if (ifp == NULL) {
|
||
|
*FNR = 0.0;
|
||
|
if (infileno == (int)*ARGC)
|
||
|
break;
|
||
|
sprintf(str, "%d", infileno);
|
||
|
u = getvar(str, argtab);
|
||
|
file = getsval(u);
|
||
|
if (strchr(file, '=') != NULL) {
|
||
|
setvar(file);
|
||
|
infileno++;
|
||
|
continue;
|
||
|
}
|
||
|
else if (strcmp(file, "") == 0) {
|
||
|
/*
|
||
|
if (infileno == (int)*ARGC - 1)
|
||
|
ifp = stdin;
|
||
|
*/
|
||
|
infileno++;
|
||
|
continue;
|
||
|
}
|
||
|
else {
|
||
|
if (strcmp(file, "-") == 0)
|
||
|
ifp = stdin;
|
||
|
else
|
||
|
ifp = efopen(file, "r");
|
||
|
*FILENAME = file;
|
||
|
}
|
||
|
}
|
||
|
if (get1rec(s, ifp))
|
||
|
return 1;
|
||
|
else {
|
||
|
if (ifp != stdin)
|
||
|
fclose(ifp);
|
||
|
ifp = NULL;
|
||
|
infileno++;
|
||
|
}
|
||
|
}
|
||
|
ifp = stdin; /* for further "getline" */
|
||
|
*FILENAME = "-";
|
||
|
return 0; /* EOF */
|
||
|
}
|
||
|
|
||
|
mkfld(rec, sep, fld) char *rec, *sep; CELL *fld[];
|
||
|
{
|
||
|
char *s, *t;
|
||
|
char str[BUFSIZ];
|
||
|
int i, j, n;
|
||
|
int skip = 0;
|
||
|
|
||
|
if (strlen(sep) > 1)
|
||
|
return r_mkfld(rec, sep, fld);
|
||
|
|
||
|
if (*sep == ' ' || *sep == '\0') {
|
||
|
sep = " \t\n"; skip++;
|
||
|
}
|
||
|
for (i = 1, n = (int) *NF; i <= n; i++) {
|
||
|
sfree(fld[i]->c_sval);
|
||
|
sfree(fld[i]);
|
||
|
fld[i] = NULL;
|
||
|
}
|
||
|
for (i = 0, s = rec; ; ) {
|
||
|
t = str;
|
||
|
if (skip) {
|
||
|
while (*s && strchr(" \t\n", *s))
|
||
|
s++;
|
||
|
if (*s == '\0')
|
||
|
break;
|
||
|
}
|
||
|
while (*s && !jStrchr(sep, *s)) {
|
||
|
if (isKanji(*s))
|
||
|
*t++ = *s++;
|
||
|
*t++ = *s++;
|
||
|
}
|
||
|
*t = '\0';
|
||
|
if (isnum(str))
|
||
|
fld[++i] = mkcell(FLD|STR|NUM, str, atof(str));
|
||
|
else
|
||
|
fld[++i] = mkcell(FLD|STR, str, 0.0);
|
||
|
if (*s)
|
||
|
s++;
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
*NF = (double) i;
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
static
|
||
|
r_mkfld(rec, sep, fld) char *rec, *sep; CELL *fld[];
|
||
|
{
|
||
|
char *s, *t;
|
||
|
char str[BUFSIZ];
|
||
|
int i, n;
|
||
|
regexp *mkpat();
|
||
|
extern int r_start, r_length;
|
||
|
|
||
|
if (strcmp(*FS, fs_str) != 0) {
|
||
|
sfree(fs_str); sfree(fs_pat);
|
||
|
fs_str = strsave(*FS);
|
||
|
fs_pat = mkpat(fs_str);
|
||
|
}
|
||
|
for (i = 1, n = (int) *NF; i <= n; i++) {
|
||
|
sfree(fld[i]->c_sval);
|
||
|
sfree(fld[i]);
|
||
|
fld[i] = NULL;
|
||
|
}
|
||
|
for (i = 0, s = rec, t = str; *s; ) {
|
||
|
if (match(fs_pat, s)) {
|
||
|
for (n = r_start; --n > 0; )
|
||
|
*t++ = *s++;
|
||
|
}
|
||
|
else {
|
||
|
while (*s)
|
||
|
*t++ = *s++;
|
||
|
}
|
||
|
*t = '\0';
|
||
|
t = str;
|
||
|
fld[++i] = mkcell(FLD|STR, str, 0.0);
|
||
|
if (*s)
|
||
|
s += r_length;
|
||
|
}
|
||
|
*NF = (double) i;
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
mkrec(u) CELL *u;
|
||
|
{
|
||
|
register char *s, *t;
|
||
|
register int i, j;
|
||
|
|
||
|
for (j = (int)*NF, i = 1; i <= j; i++)
|
||
|
if (field[i] == u)
|
||
|
break;
|
||
|
if (i > j) {
|
||
|
for ( ; i < MAXFLD; i++)
|
||
|
if (field[i] == u)
|
||
|
break;
|
||
|
if (i == MAXFLD)
|
||
|
error("too many field (%d)", i);
|
||
|
*NF = (double)i;
|
||
|
}
|
||
|
for (t = record, i = 1, j = (int) *NF; i <= j; i++) {
|
||
|
if (i > 1)
|
||
|
*t++ = **OFS;
|
||
|
for (s = getsval(field[i]); *s; )
|
||
|
*t++ = *s++;
|
||
|
}
|
||
|
*t++ = '\0';
|
||
|
}
|
||
|
|
||
|
CELL *
|
||
|
Field(p) NODE *p;
|
||
|
{
|
||
|
CELL *u;
|
||
|
int i, j;
|
||
|
|
||
|
u = execute(p->n_arg[0]);
|
||
|
i = (int) getfval(u);
|
||
|
c_free(u);
|
||
|
j = (int)*NF;
|
||
|
if (i > j)
|
||
|
for (++j; j <= i; j++) {
|
||
|
if (field[j] == NULL)
|
||
|
field[j] = mkcell(FLD|STR, "", 0.0);
|
||
|
}
|
||
|
return field[i];
|
||
|
}
|
||
|
|
||
|
CELL *
|
||
|
P1stat(p) NODE *p;
|
||
|
{
|
||
|
CELL *u;
|
||
|
double x;
|
||
|
|
||
|
pateval++;
|
||
|
u = execute(p->n_arg[0]);
|
||
|
pateval = 0;
|
||
|
x = getfval(u);
|
||
|
c_free(u);
|
||
|
if (x != 0.0)
|
||
|
u = execute(p->n_arg[1]);
|
||
|
else
|
||
|
u = &truecell;
|
||
|
return u;
|
||
|
}
|
||
|
|
||
|
CELL *
|
||
|
P2stat(p) NODE *p;
|
||
|
{
|
||
|
static stat = 0;
|
||
|
CELL *u, *v;
|
||
|
double x;
|
||
|
|
||
|
switch (stat) {
|
||
|
case 0:
|
||
|
pateval++;
|
||
|
u = execute(p->n_arg[0]);
|
||
|
pateval = 0;
|
||
|
x = getfval(u);
|
||
|
c_free(u);
|
||
|
if (x == 0.0) {
|
||
|
u = &truecell; break;
|
||
|
}
|
||
|
else
|
||
|
stat++;
|
||
|
/* fall through */
|
||
|
case 1:
|
||
|
u = execute(p->n_arg[2]);
|
||
|
c_free(u);
|
||
|
pateval++;
|
||
|
u = execute(p->n_arg[1]);
|
||
|
pateval = 0;
|
||
|
x = getfval(u);
|
||
|
if (x != 0.0)
|
||
|
stat = 0;
|
||
|
break;
|
||
|
default:
|
||
|
u = &truecell;
|
||
|
break;
|
||
|
}
|
||
|
return u;
|
||
|
}
|
||
|
|
||
|
CELL *
|
||
|
Print0()
|
||
|
{
|
||
|
/*
|
||
|
int i, j;
|
||
|
char *s, str[BUFSIZ];
|
||
|
|
||
|
for (*str = '\0', i = 1, j = (int) *NF; i <= j; i++) {
|
||
|
if (i > 1)
|
||
|
strcat(str, *OFS);
|
||
|
s = getsval(field[i]);
|
||
|
strcat(str, s);
|
||
|
}
|
||
|
strcat(str, *ORS);
|
||
|
fputs(str, stdout);
|
||
|
*/
|
||
|
fprintf(stdout, "%s%s", record, *ORS);
|
||
|
return &truecell;
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
format(t, p) char *t; NODE *p;
|
||
|
{
|
||
|
CELL *u, *v;
|
||
|
char *r, *s, *s0, fmt[BUFSIZ];
|
||
|
double x;
|
||
|
int i;
|
||
|
|
||
|
u = execute(p->n_arg[2]);
|
||
|
s = s0 = getsval(u);
|
||
|
/*
|
||
|
printf("fmt(%s)\n", s);
|
||
|
*/
|
||
|
for (i = 3; *s; s++) {
|
||
|
if (isKanji(*s)) {
|
||
|
*t++ = *s++; *t++ = *s; continue;
|
||
|
}
|
||
|
if (*s != '%') {
|
||
|
*t++ = *s; continue;
|
||
|
}
|
||
|
else if (*(s + 1) == '%') {
|
||
|
*t++ = *s++; continue;
|
||
|
}
|
||
|
for (r = fmt, *r++ = *s++; *r++ = *s; s++) {
|
||
|
if (strchr("%cdefgosux", *s))
|
||
|
break;
|
||
|
}
|
||
|
*r = '\0';
|
||
|
if (p->n_arg[i] == NULL)
|
||
|
error("not enough args in printf(%s)", s0);
|
||
|
v = execute(p->n_arg[i++]);
|
||
|
if (*s == 's')
|
||
|
r = getsval(v);
|
||
|
else
|
||
|
x = getfval(v);
|
||
|
/*
|
||
|
printf("val(%d)(%s)\n", v->c_type, v->c_sval);
|
||
|
*/
|
||
|
switch (*s) {
|
||
|
case 'c':
|
||
|
sprintf(t, fmt, (int) x);
|
||
|
break;
|
||
|
case 'd':
|
||
|
if (*(s - 1) != 'l') {
|
||
|
*--r = 'l'; *++r = 'd'; *++r = '\0';
|
||
|
}
|
||
|
sprintf(t, fmt, (long) x);
|
||
|
break;
|
||
|
case 'e': case 'f': case 'g':
|
||
|
sprintf(t, fmt, x);
|
||
|
break;
|
||
|
case 'o': case 'u': case 'x':
|
||
|
if (*(s - 1) == 'l')
|
||
|
sprintf(t, fmt, (long) x);
|
||
|
else
|
||
|
sprintf(t, fmt, (int) x);
|
||
|
break;
|
||
|
case 's':
|
||
|
/*r = getsval(v);*/
|
||
|
sprintf(t, fmt, r);
|
||
|
break;
|
||
|
default:
|
||
|
strcpy(t, fmt);
|
||
|
break;
|
||
|
}
|
||
|
c_free(v);
|
||
|
t += strlen(t);
|
||
|
}
|
||
|
c_free(u);
|
||
|
*t = '\0';
|
||
|
}
|
||
|
|
||
|
#define MAXFILE 10
|
||
|
struct {
|
||
|
char *f_name; /* file name */
|
||
|
FILE *f_fp;
|
||
|
int f_type;
|
||
|
} filetab[MAXFILE];
|
||
|
|
||
|
FILE *
|
||
|
getfp(file, type) char *file;
|
||
|
{
|
||
|
register int i;
|
||
|
register char *name, *mode;
|
||
|
char *awktmp();
|
||
|
FILE *fp, *efopen(), *epopen();
|
||
|
|
||
|
for (i = 0; i < MAXFILE; i++)
|
||
|
if (filetab[i].f_name && strcmp(filetab[i].f_name, file) == 0)
|
||
|
return filetab[i].f_fp;
|
||
|
for (i = 0; i < MAXFILE; i++)
|
||
|
if (!filetab[i].f_fp)
|
||
|
break;
|
||
|
if (i == MAXFILE)
|
||
|
error("too many files to open");
|
||
|
name = file;
|
||
|
switch (type) {
|
||
|
case R_OUT: mode = "w"; break;
|
||
|
case R_APD: mode = "a"; break;
|
||
|
case R_POUT:
|
||
|
#ifdef DOS
|
||
|
name = awktmp(i); mode = "w"; /* MS-DOS */
|
||
|
#else
|
||
|
fp = epopen(file, "w");
|
||
|
goto g1;
|
||
|
#endif
|
||
|
break;
|
||
|
case R_IN: mode = "r"; break;
|
||
|
case R_PIN:
|
||
|
#ifdef DOS
|
||
|
{
|
||
|
int savefd, fd, result;
|
||
|
|
||
|
name = awktmp(i);
|
||
|
if ((fd = open(name,
|
||
|
O_WRONLY|O_TEXT|O_CREAT|O_TRUNC,S_IREAD|S_IWRITE)) == -1)
|
||
|
error("can't open %s", name);
|
||
|
savefd = dup(1); dup2(fd, 1); close(fd);
|
||
|
if ((result =
|
||
|
system(file)) == -1)
|
||
|
error("can't exec %s", file);
|
||
|
dup2(savefd, 1); close(savefd); close(fd);
|
||
|
mode = "r";
|
||
|
}
|
||
|
#else
|
||
|
fp = epopen(file,"r");
|
||
|
goto g1;
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
fp = efopen(name, mode);
|
||
|
g1:
|
||
|
filetab[i].f_name = strsave(file);
|
||
|
filetab[i].f_type = type;
|
||
|
filetab[i].f_fp = fp;
|
||
|
return fp;
|
||
|
}
|
||
|
|
||
|
closeall()
|
||
|
{
|
||
|
register int i;
|
||
|
|
||
|
for (i = 0; i < MAXFILE; i++)
|
||
|
close1(i);
|
||
|
}
|
||
|
|
||
|
CELL *
|
||
|
Close(s) char *s;
|
||
|
{
|
||
|
register int i;
|
||
|
|
||
|
for (i = 0; i < MAXFILE; i++)
|
||
|
if (strcmp(s, filetab[i].f_name) == 0) {
|
||
|
close1(i);
|
||
|
break;
|
||
|
}
|
||
|
i = (i == MAXFILE) ? 0 : 1;
|
||
|
return mktmp(NUM, NULL, (double) i);
|
||
|
}
|
||
|
|
||
|
static
|
||
|
close1(i)
|
||
|
{
|
||
|
int fd, result, savefd;
|
||
|
char *awktmp();
|
||
|
|
||
|
if (filetab[i].f_fp == NULL)
|
||
|
return;
|
||
|
switch (filetab[i].f_type) {
|
||
|
case R_PIN:
|
||
|
#ifdef DOS
|
||
|
fclose(filetab[i].f_fp);
|
||
|
unlink(awktmp(i));
|
||
|
#else
|
||
|
pclose(filetab[i].f_fp);
|
||
|
#endif
|
||
|
break;
|
||
|
case R_IN: case R_OUT: case R_APD:
|
||
|
fclose(filetab[i].f_fp);
|
||
|
break;
|
||
|
case R_POUT:
|
||
|
#ifdef DOS
|
||
|
fclose(filetab[i].f_fp);
|
||
|
if ((fd = open(awktmp(i), O_RDONLY)) == NULL)
|
||
|
error("can't open %s", awktmp(i));
|
||
|
savefd = dup(0);
|
||
|
dup2(fd, 0);
|
||
|
close(fd);
|
||
|
if ((result =
|
||
|
system(filetab[i].f_name)) == -1)
|
||
|
/*
|
||
|
spawnl(P_WAIT, "/usr/bin/sh", "sh", "-c", filetab[i].f_name, (char *) 0)) == -1)
|
||
|
fprintf(stderr, "can't spawn /bin/sh\n");
|
||
|
*/
|
||
|
error("can't exec %s", filetab[i].f_name);
|
||
|
dup2(savefd, 0);
|
||
|
close(savefd);
|
||
|
unlink(awktmp(i));
|
||
|
#else
|
||
|
pclose(filetab[i].f_fp);
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
sfree(filetab[i].f_name);
|
||
|
filetab[i].f_type = 0;
|
||
|
filetab[i].f_name = NULL;
|
||
|
filetab[i].f_fp = NULL;
|
||
|
}
|
||
|
|
||
|
#ifndef DOS
|
||
|
FILE *
|
||
|
epopen(file, mod) char *file, *mod;
|
||
|
{
|
||
|
FILE *fp, *popen();
|
||
|
|
||
|
if ((fp = popen(file, mod)) == NULL)
|
||
|
error("can't poen %s", file);
|
||
|
return fp;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static char *
|
||
|
awktmp(i)
|
||
|
{
|
||
|
static char str[16];
|
||
|
|
||
|
sprintf(str, "awk000%02d.tmp", i);
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
Index(s, t) char *s, *t;
|
||
|
{
|
||
|
register char *u, *v;
|
||
|
register int i;
|
||
|
|
||
|
for (i = 1; *s; s++, i++) {
|
||
|
for (u = s, v = t; *v; u++, v++) {
|
||
|
if (isKanji(*v)) {
|
||
|
if (*u != *v)
|
||
|
break;
|
||
|
u++; v++;
|
||
|
}
|
||
|
if (*u != *v)
|
||
|
break;
|
||
|
}
|
||
|
if (*v == '\0')
|
||
|
return i;
|
||
|
if (isKanji(*s))
|
||
|
s++;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|