Programmet fungerar som kommandot grep fast med en modifikation som gör att den tänder lysdioden i en sekund för varge rad som grep skriver ut till stdout.
/* $OpenBSD: grepflash.c,v 1.0 2003/05/04 14:02:00 $ */
/*-
* This sourcecode is based on
* $OpenBSD: grep.c,v 1.1 2001/09/21 23:12:00 deraadt Exp $
* and have been modifyed by Xerxes Rånby to turn on the output signal
* on the paralell port for one secound for each row that gets printed.
* This is a fast hack..
*/
/*-
* Copyright (c) 2000 Carson Harding. All rights reserved.
* This code was written and contributed to OpenBSD by Carson Harding.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author, or the names of contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char rcsid[] = "$OpenBSD: grepflash.c,v 1.0 2003/05/04 14:02:00 $";
#endif /* not lint */
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <regex.h>
#include <string.h>
#include <ctype.h>
#include <sys/param.h>
#include <fts.h>
#include <err.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <machine/sysarch.h>
#include <machine/pio.h>
/* ioport(port) permit access to an I/O port.
* port I/O address to enable
*/
void
ioport(int port) {
u_long iomap[32];
struct i386_set_ioperm_args ioperm;
ioperm.iomap = iomap;
syscall(SYS_sysarch, I386_GET_IOPERM, (char *) &ioperm);
iomap[port >> 5] &= ~(1 << (port & 0x1f));
syscall(SYS_sysarch, I386_SET_IOPERM, (char *) &ioperm);
}
void flash(void) {
outb(0x378, 1); /* Set the output register */
sleep(1); /* Sleep a tick */
outb(0x378, 0); /* Set the output register */
}
extern char *__progname;
void usage(void);
void err_regerror(int r, regex_t *rexp);
int grep_files(int regexc, regex_t *regexv, char **files);
int grep_tree(int regexc, regex_t *regexv, char **paths);
int grep_file(int regexc, regex_t *rexp, char *fname);
void arg_patt(char *s);
char *chop_patt(char *s, size_t *len);
void add_patt(char *s, size_t len);
void load_patt(char *fname);
regex_t *regcomp_patt(int pattc, char *pattvp[], int cflags);
int f_bytecount; /* -b prepend byte count */
int f_countonly; /* -c return only count */
int f_nofname; /* -h do not prepend filenames on multiple */
int f_fnameonly; /* -l only print file name with match */
int f_suppress; /* -s suppress error messages; 1/2 -q */
int f_lineno; /* -n prepend with line numbers */
int f_quiet; /* -q no output, only status */
int f_wmatch; /* -w match words */
int f_xmatch; /* -x match line */
int f_zerobyte; /* -z NUL character after filename with -l */
int f_match; /* = REG_MATCH; else = REG_NOMATCH for -v */
int f_multifile; /* multiple files: prepend file names */
int f_matchall; /* empty pattern, matches all input */
int f_error; /* saw error; set exit status */
/* default traversal flags */
int f_ftsflags = FTS_LOGICAL|FTS_NOCHDIR|FTS_NOSTAT;
int f_debug; /* temporary debugging flag */
#define START_PATT_SZ 8 /* start with room for 8 patterns */
char **pattv; /* array of patterns from -e and -f */
int pattc; /* patterns in pattern array */
int pattn; /* patterns we have seen, including nulls */
int
main(int argc, char **argv)
{
int c;
int ch;
int cflags; /* flags to regcomp() */
int sawfile; /* did we see a pattern file? */
regex_t *regexv; /* start of array of compiled patterns */
int (*grepf)(int regexc, regex_t *regexv, char **argv);
ioport(0x378); /* Initialize the paralell port */
sawfile = 0;
cflags = REG_BASIC|REG_NEWLINE;
grepf = grep_files;
if (*__progname == 'e')
cflags |= REG_EXTENDED;
else if (*__progname == 'f')
cflags |= REG_NOSPEC;
while ((ch = getopt(argc, argv, "DEFRHLPXabce:f:hilnqsvwxz")) != -1) {
switch(ch) {
case 'D':
f_debug = 1;
break;
case 'E':
cflags |= REG_EXTENDED;
break;
case 'F':
cflags |= REG_NOSPEC;
break;
case 'H':
f_ftsflags |= FTS_COMFOLLOW;
break;
case 'L':
f_ftsflags |= FTS_LOGICAL;
break;
case 'P':
f_ftsflags |= FTS_PHYSICAL;
break;
case 'R':
grepf = grep_tree;
/*
* If walking the tree we don't know how many files
* we'll actually find. So assume multiple, if
* you don't want names, there's always -h ....
*/
f_multifile = 1;
break;
case 'X':
f_ftsflags |= FTS_XDEV;
break;
case 'a':
/*
* Silently eat -a; we don't use the default
* behaviour it toggles off in gnugrep.
*/
break;
case 'b':
f_bytecount = 1;
break;
case 'c':
f_countonly = 1;
break;
case 'e':
arg_patt(optarg);
break;
case 'f':
load_patt(optarg);
sawfile = 1;
break;
case 'h':
f_nofname = 1;
break;
case 'i':
cflags |= REG_ICASE;
break;
case 'l':
f_fnameonly = 1;
break;
case 'n':
f_lineno = 1;
break;
case 'q':
f_quiet = 1;
break;
case 's':
f_suppress = 1;
break;
case 'v':
f_match = REG_NOMATCH;
break;
case 'w':
f_wmatch = 1;
break;
case 'x':
f_xmatch = 1;
break;
case 'z':
f_zerobyte = 1;
break;
default:
usage();
break;
}
}
if ((cflags & REG_EXTENDED) && (cflags & REG_NOSPEC))
usage();
/*
* If we read one or more pattern files, and still
* didn't end up with any pattern, any pattern file
* we read was empty. This is different than failing
* to provide a pattern as an argument, and we fail
* on this case as if we had searched and found
* no matches. (At least this is what GNU grep and
* Solaris's grep do.)
*/
if (!pattn && !argv[optind]) {
if (sawfile)
exit(1);
else usage();
}
if (!pattn) {
arg_patt(argv[optind]);
optind++;
}
/* why bother ... just do nothing sooner */
if (f_matchall && f_match == REG_NOMATCH)
exit(1);
regexv = regcomp_patt(pattc, pattv, cflags);
if (optind == argc) {
c = grep_file(pattc, regexv, NULL);
} else {
if (argc - optind > 1 && !f_nofname)
f_multifile = 1;
c = (*grepf)(pattc, regexv, &argv[optind]);
}
/* XX ugh */
if (f_error) {
if (c && f_quiet)
exit(0);
else
exit(2);
} else if (c)
exit(0);
else
exit(1);
}
void
usage(void)
{
fprintf(stderr, "usage: %s [-E|-F] [-abchilnqsvwx] [-RXH[-L|-P]]"
" {patt | -e patt | -f patt_file} [files]\n",
__progname);
exit(2);
}
/*
* Patterns as arguments may have embedded newlines.
* When read from file, these are detected by fgetln();
* in arguments we have to find and cut out the segments.
*/
void
arg_patt(char *s)
{
size_t len;
char *sp;
if (f_debug)
fprintf(stderr, "arg_patt(\"%s\")\n", s);
len = strlen(s);
if (!len) { /* got "" on the command-line */
add_patt(s, len);
return;
}
for (sp = chop_patt(s, &len); sp; sp = chop_patt(NULL, &len)) {
if (f_debug) {
fprintf(stderr, "adding pattern \"");
fwrite(sp, len, 1, stderr);
fprintf(stderr, "\", length %lu\n",(unsigned long)len);
if (pattc > 20) {
fprintf(stderr, "too many, exiting ...\n");
exit(2);
}
}
add_patt(sp, len);
}
}
/*
* Kind of like strtok; pass char *, then NULL for rest.
* Call it memtok()... New size gets written into len.
*/
char *
chop_patt(char *s, size_t *len)
{
char *cp;
static char *save_s;
static int save_n;
if (s)
save_n = *len;
else
s = save_s;
if (save_n <= 0) {
s = save_s = NULL;
} else if (s) {
if ((cp = memchr(s, '\n', save_n)) != NULL) {
*len = cp - s; /* returned segment */
save_n -= *len;
save_s = ++cp; /* adjust past newline */
save_n--;
} else {
*len = save_n; /* else return the whole string */
save_n = 0;
}
}
return s;
}
/*
* Start with an array for 8 patterns, and double it
* each time we outgrow it. If pattern is empty (0 length),
* or if f_matchall is already set, set f_matchall and return.
* No use adding a pattern if all input is going to match
* anyhow.
*/
void
add_patt(char *s, size_t len)
{
char *p;
static size_t pattmax = START_PATT_SZ;
static size_t sumlen;
pattn++;
sumlen += len;
if (!len || f_matchall) {
f_matchall = 1;
return;
}
if (!pattv) {
pattv = malloc(START_PATT_SZ * sizeof(char *));
if (!pattv)
err(2, "malloc");
pattc = 0;
} else if (pattc >= pattmax) {
pattmax *= 2;
pattv = realloc(pattv, pattmax * sizeof(char *));
if (!pattv)
err(2, "realloc");
}
p = malloc(len+1);
if (!p) err(2, "malloc");
memmove(p, s, len);
p[len] = '\0';
pattv[pattc++] = p;
}
/*
* Load patterns from file.
*/
void
load_patt(char *fname)
{
char *buf;
size_t len;
FILE *fr;
fr = fopen(fname, "r");
if (!fr)
err(2, fname);
while ((buf = fgetln(fr, &len)) != NULL) {
if (buf[len-1] == '\n')
buf[--len] = '\0';
add_patt(buf, len);
}
fclose(fr);
}
/*
* Compile the collected pattern strings into an array
* of regex_t.
*/
regex_t *
regcomp_patt(int lpattc, char *lpattv[], int cflags)
{
int i;
int r;
regex_t *rxv;
if (f_matchall)
return NULL;
rxv = malloc(sizeof(regex_t) * lpattc);
if (!rxv)
err(2, "malloc");
for (i = 0; i < lpattc; i++) {
if ((r = regcomp(&rxv[i], lpattv[i], cflags)) != 0)
err_regerror(r, &rxv[i]);
}
return rxv;
}
/*
* Print out regcomp error, and exit.
*/
void
err_regerror(int r, regex_t *rexp)
{
size_t n;
char *buf;
n = regerror(r, rexp, NULL, 0);
buf = malloc(n);
if (!buf)
err(2, "malloc");
(void)regerror(r, rexp, buf, n);
errx(2, "%s", buf);
}
/*
* Little wrapper so we can use function pointer above.
*/
int
grep_files(int regexc, regex_t *regexv, char **files)
{
int c;
char **fname;
c = 0;
for (fname = files; *fname; fname++)
c += grep_file(regexc, regexv, *fname);
return c;
}
/*
* Modified from James Howard and Dag-Erling Co?dan Sm?rgrav's grep:
* add FTS_D to FTS_DP (especially since D was the one being used)
* pass in regex_t array, and set fts flags above in main().
*/
int
grep_tree(int regexc, regex_t *regexv, char **paths)
{
int c;
FTS *fts;
FTSENT *p;
c = 0;
if (!(fts = fts_open(paths, f_ftsflags, (int (*) ()) NULL)))
err(2, "fts_open");
while ((p = fts_read(fts)) != NULL) {
switch (p->fts_info) {
case FTS_D:
case FTS_DP:
case FTS_DNR:
break;
case FTS_ERR:
errx(2, "%s: %s", p->fts_path, strerror(p->fts_errno));
break;
default:
if (f_debug)
printf("%s\n", p->fts_path);
c += grep_file(regexc, regexv, p->fts_path);
break;
}
}
return c;
}
/*
* Open and grep the named file. If fname is NULL, read
* from stdin.
*/
#define isword(x) (isalnum(x) || (x) == '_')
int
grep_file(int regexc, regex_t *regexv, char *fname)
{
int i;
int c;
int n;
int r;
int match;
char *buf;
size_t b;
size_t len;
FILE *fr;
regmatch_t pmatch[1];
regoff_t so, eo;
b = 0; /* byte count */
c = 0; /* match count */
n = 0; /* line count */
if (!fname) {
fr = stdin;
fname = "(standard input)";
} else {
fr = fopen(fname, "r");
if (!fr) {
if (!f_suppress)
warn("%s", fname);
f_error = 1;
return 0;
}
}
while ((buf = fgetln(fr, &len)) != NULL) {
n++;
if (f_matchall)
goto printmatch;
match = 0;
for (i = 0; i < regexc; i++) {
pmatch[0].rm_so = 0;
pmatch[0].rm_eo = len-1;
r = regexec(®exv[i], buf, 1, pmatch, REG_STARTEND);
if (r == f_match) {
/*
* XX gnu grep allows both -w and -x;
* XX but seems bizarre. sometimes -w seems
* XX to override, at other times, not.
* XX Need to figure that out.
* XX It seems logical to go with the most
* XX restrictive argument: -x, as -x is
* XX a boundary case of -w anyhow.
*/
if (f_xmatch) {
if (pmatch[0].rm_so != 0 ||
pmatch[0].rm_eo != len-1)
continue;
} else if (f_wmatch) {
so = pmatch[0].rm_so;
eo = pmatch[0].rm_eo;
if (!((so == 0 || !isword(buf[so-1])) &&
(eo == len || !isword(buf[eo]))))
continue;
}
match = 1;
break;
}
/* XX test for regexec() errors ?? */
}
if (match) {
printmatch:
c++;
if (f_fnameonly || f_quiet)
break;
if (f_countonly)
continue;
if (f_multifile && !f_nofname)
printf("%s:", fname);
if (f_lineno)
printf("%d:", n);
if (f_bytecount)
printf("%lu:", (unsigned long)b);
fwrite(buf, len, 1, stdout);
flash();
}
/* save position in stream before next line */
b += len;
}
if (!buf && ferror(fr)) {
warn("%s", fname);
f_error = 1;
/*
* XX or do we spit out what result we did have?
*/
} else if (!f_quiet) {
/*
* XX test -c and -l together: gnu grep
* XX allows (although ugly), do others?
*/
if (f_countonly) {
if (f_multifile)
printf("%s:", fname);
printf("%d\n", c);
}
if (c && f_fnameonly) {
fputs(fname, stdout);
if (f_zerobyte)
fputc('\0', stdout);
else
fputc('\n', stdout);
}
}
if (fr != stdin)
fclose(fr);
return c;
}