Added regexp support, fixed Changelog.

This commit is contained in:
Eric Andersen 1999-10-22 04:30:20 +00:00
parent c49960189a
commit aa0765e11b
10 changed files with 1005 additions and 197 deletions

View File

@ -1,7 +1,81 @@
0.31
* I added a changelog for version 0.30.
* adjusted find internals to make it smaller, and removed
some redundancy.
* Fixed a segfault in ps when /etc/passwd or /etc/group
are absent. Now will warn you and carry on.
* Added in optional _real_ regular expression support (to be
the basis for a future sed utility). When compiled in,
adds 3.9k.
0.30 0.30
Major changes -- lots of stuff rewritten. Many thanks to Lineo for Major changes -- lots of stuff rewritten. Many thanks to Lineo for
paying me to make these updates. If you have any problems with busybox, paying me to make these updates. If you have any problems with busybox,
or notice any bugs -- please let me know so I can fix it. or notice any bugs -- please let me know so I can fix it. These
changes include:
Core Changes:
* busybox can now invoke apps in two ways: via symlinks to the
busybox binary, and as 'busybox [function] [arguments]...'
* When invoked as busybox, the list of currently compiled in
functions is printed out (no this is not bloat -- the list
has to be there anyway to map invocation name to function).
* busybox no longer parses command lines for apps or displays their
usage info. Each app gets to handle (or not handle) this for
itself.
* Eliminated monadic, dyadic, descend, block_device, and
postprocess. It was cumbersome to have so many programs
cobbled together in this way. Without them, the app is much
more granular.
* All shared code now lives in utility.c, and is properly
ifdef'ed to be only included for those apps requiring it.
* Eliminated struct FileInfo (the basis of monadic, dyadic, etc)
so now each app has the function prototype of (da-dum):
extern int foo_main(int argc, char** argv);
which speeds integration of new apps.
* Adjusted the Makefile to make it easier to
{en|dis}able debugging.
* Changed default compiler optimization to -Os
(optimize for smaller binaries).
App Changes:
* To cope with the new app function prototype and the removal of
monadic, dyadic, etc, the following apps were re-written:
* cat - Works same as always.
* chgrp, chmod, chown - rewrite. Combined into a single
source file. Absorbed patches from Enrique Zanardi <ezanard@debian.org>
that removes the dependency on libc6 libnss* libraries.
* cp - Can now do 'cp -a' can can copy devices,
pipes, symlinks, as well as recursive or non-recursive dir copies.
* fdflush - adjusted to remove dependancy on struct FileInfo.
* find - Now includes some basic regexp matching
which will be the basic of a future mini-sed.
* ln - Same functionality.
* mkdir - Added -p flag to feature set.
* mv - rewrite.
* rm - Added -f flag to feature set.
* rmdir - Same functionality.
* swapon, swapoff - Combined into a single binary. No longer
uses /etc/swaps. swap{on|off} -a uses /etc/fstab instead.
* touch - Same functionality.
* date - adjusted with a patch from Matthew Grant <grantma@anathoth.gen.nz>
to accomodate glibc timezone support. I then ripped out GNU getopt.
* mkswap -- new version merged from util-linux. Can now make >128Meg swaps.
* Replaced the old and star, unstar, and tarcat with the tar
implementation from sash. Now tar behaves as god intended
it to (i.e. tar -xvf <file> and tar -cf <file> <dir> work).
* dd -- rewritten. Can with with files, stdin, stdout.
* Added the following new apps:
* loadfont -- added from debian boot floppies
* chroot -- added based on a patch from Paolo Molaro <lupus@lettere.unipd.it>
* grep -- I just wrote it. Only matches simple strings
* ps -- I just wrote it. Has _no_ options at all, but works.
* fsck_minix, mkfs_minix -- added from util-linux, but I ripped out
internationalization and such to make them smaller.
* sfdisk -- Added from util-linux (minus internationalization and such).
* Probably some other changes that I forgot to document...
-Erik Andersen -Erik Andersen
0.28 0.28

View File

@ -40,6 +40,7 @@
//#define BB_PRINTF //#define BB_PRINTF
#define BB_PS #define BB_PS
#define BB_PWD #define BB_PWD
#define BB_REGEXP
#define BB_REBOOT #define BB_REBOOT
#define BB_RM #define BB_RM
#define BB_RMDIR #define BB_RMDIR
@ -52,6 +53,8 @@
//#define BB_TRUE_FALSE // Supplied by ash //#define BB_TRUE_FALSE // Supplied by ash
#define BB_UMOUNT #define BB_UMOUNT
#define BB_UPDATE #define BB_UPDATE
#define BB_UTILITY
#define BB_ZCAT #define BB_ZCAT
//#define BB_GZIP //#define BB_GZIP
// Don't turn BB_UTILITY off. It contains support code
// that compiles to 0 if everything else if turned off.
#define BB_UTILITY

23
find.c
View File

@ -21,14 +21,15 @@
* *
*/ */
#include "internal.h"
#include "regexp.h"
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <dirent.h> #include <dirent.h>
#include "internal.h"
static char* pattern=NULL; static char* pattern=NULL;
static char* directory=NULL; static char* directory=".";
static int dereferenceFlag=FALSE; static int dereferenceFlag=FALSE;
static const char find_usage[] = "find [path...] [expression]\n" static const char find_usage[] = "find [path...] [expression]\n"
@ -41,7 +42,7 @@ static int fileAction(const char *fileName, struct stat* statbuf)
{ {
if (pattern==NULL) if (pattern==NULL)
fprintf(stdout, "%s\n", fileName); fprintf(stdout, "%s\n", fileName);
else if (match(fileName, pattern) == TRUE) else if (find_match(fileName, pattern, TRUE) == TRUE)
fprintf(stdout, "%s\n", fileName); fprintf(stdout, "%s\n", fileName);
return( TRUE); return( TRUE);
} }
@ -53,7 +54,7 @@ static int dirAction(const char *fileName, struct stat* statbuf)
if (pattern==NULL) if (pattern==NULL)
fprintf(stdout, "%s\n", fileName); fprintf(stdout, "%s\n", fileName);
else if (match(fileName, pattern) == TRUE) else if (find_match(fileName, pattern, TRUE) == TRUE)
fprintf(stdout, "%s\n", fileName); fprintf(stdout, "%s\n", fileName);
dir = opendir( fileName); dir = opendir( fileName);
@ -71,22 +72,18 @@ static int dirAction(const char *fileName, struct stat* statbuf)
int find_main(int argc, char **argv) int find_main(int argc, char **argv)
{ {
if (argc <= 1) {
dirAction( ".", NULL);
}
/* peel off the "find" */ /* peel off the "find" */
argc--; argc--;
argv++; argv++;
if (**argv != '-') { if ( argc > 0 && **argv != '-') {
directory=*argv; directory=*argv;
argc--; argc--;
argv++; argv++;
} }
/* Parse any options */ /* Parse any options */
while (**argv == '-') { while (argc > 0 && **argv == '-') {
int stopit=FALSE; int stopit=FALSE;
while (*++(*argv) && stopit==FALSE) switch (**argv) { while (*++(*argv) && stopit==FALSE) switch (**argv) {
case 'f': case 'f':
@ -120,6 +117,10 @@ int find_main(int argc, char **argv)
break; break;
} }
dirAction( directory, NULL); if (recursiveAction(directory, TRUE, FALSE, FALSE,
fileAction, fileAction) == FALSE) {
exit( FALSE);
}
exit(TRUE); exit(TRUE);
} }

View File

@ -21,14 +21,15 @@
* *
*/ */
#include "internal.h"
#include "regexp.h"
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <dirent.h> #include <dirent.h>
#include "internal.h"
static char* pattern=NULL; static char* pattern=NULL;
static char* directory=NULL; static char* directory=".";
static int dereferenceFlag=FALSE; static int dereferenceFlag=FALSE;
static const char find_usage[] = "find [path...] [expression]\n" static const char find_usage[] = "find [path...] [expression]\n"
@ -41,7 +42,7 @@ static int fileAction(const char *fileName, struct stat* statbuf)
{ {
if (pattern==NULL) if (pattern==NULL)
fprintf(stdout, "%s\n", fileName); fprintf(stdout, "%s\n", fileName);
else if (match(fileName, pattern) == TRUE) else if (find_match(fileName, pattern, TRUE) == TRUE)
fprintf(stdout, "%s\n", fileName); fprintf(stdout, "%s\n", fileName);
return( TRUE); return( TRUE);
} }
@ -53,7 +54,7 @@ static int dirAction(const char *fileName, struct stat* statbuf)
if (pattern==NULL) if (pattern==NULL)
fprintf(stdout, "%s\n", fileName); fprintf(stdout, "%s\n", fileName);
else if (match(fileName, pattern) == TRUE) else if (find_match(fileName, pattern, TRUE) == TRUE)
fprintf(stdout, "%s\n", fileName); fprintf(stdout, "%s\n", fileName);
dir = opendir( fileName); dir = opendir( fileName);
@ -71,22 +72,18 @@ static int dirAction(const char *fileName, struct stat* statbuf)
int find_main(int argc, char **argv) int find_main(int argc, char **argv)
{ {
if (argc <= 1) {
dirAction( ".", NULL);
}
/* peel off the "find" */ /* peel off the "find" */
argc--; argc--;
argv++; argv++;
if (**argv != '-') { if ( argc > 0 && **argv != '-') {
directory=*argv; directory=*argv;
argc--; argc--;
argv++; argv++;
} }
/* Parse any options */ /* Parse any options */
while (**argv == '-') { while (argc > 0 && **argv == '-') {
int stopit=FALSE; int stopit=FALSE;
while (*++(*argv) && stopit==FALSE) switch (**argv) { while (*++(*argv) && stopit==FALSE) switch (**argv) {
case 'f': case 'f':
@ -120,6 +117,10 @@ int find_main(int argc, char **argv)
break; break;
} }
dirAction( directory, NULL); if (recursiveAction(directory, TRUE, FALSE, FALSE,
fileAction, fileAction) == FALSE) {
exit( FALSE);
}
exit(TRUE); exit(TRUE);
} }

View File

@ -22,6 +22,7 @@
*/ */
#include "internal.h" #include "internal.h"
#include "regexp.h"
#include <stdio.h> #include <stdio.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
@ -30,44 +31,17 @@
#include <time.h> #include <time.h>
#include <ctype.h> #include <ctype.h>
static const char grep_usage[] = static const char grep_usage[] =
"grep [-ihn]... PATTERN [FILE]...\n" "grep [-ihn]... PATTERN [FILE]...\n"
"Search for PATTERN in each FILE or standard input.\n\n" "Search for PATTERN in each FILE or standard input.\n\n"
"\t-h\tsuppress the prefixing filename on output\n" "\t-h\tsuppress the prefixing filename on output\n"
"\t-i\tignore case distinctions\n" "\t-i\tignore case distinctions\n"
"\t-n\tprint line number with output lines\n\n" "\t-n\tprint line number with output lines\n\n"
#if defined BB_REGEXP
"This version of grep matches full regexps.\n";
#else
"This version of grep matches strings (not full regexps).\n"; "This version of grep matches strings (not full regexps).\n";
#endif
/*
* See if the specified needle is found in the specified haystack.
*/
static int search (const char *haystack, const char *needle, int ignoreCase)
{
if (ignoreCase == FALSE) {
haystack = strstr (haystack, needle);
if (haystack == NULL)
return FALSE;
return TRUE;
} else {
int i;
char needle1[BUF_SIZE];
char haystack1[BUF_SIZE];
strncpy( haystack1, haystack, sizeof(haystack1));
strncpy( needle1, needle, sizeof(needle1));
for( i=0; i<sizeof(haystack1) && haystack1[i]; i++)
haystack1[i]=tolower( haystack1[i]);
for( i=0; i<sizeof(needle1) && needle1[i]; i++)
needle1[i]=tolower( needle1[i]);
haystack = strstr (haystack1, needle1);
if (haystack == NULL)
return FALSE;
return TRUE;
}
}
extern int grep_main (int argc, char **argv) extern int grep_main (int argc, char **argv)
@ -80,7 +54,7 @@ extern int grep_main (int argc, char **argv)
int ignoreCase=FALSE; int ignoreCase=FALSE;
int tellLine=FALSE; int tellLine=FALSE;
long line; long line;
char buf[BUF_SIZE]; char haystack[BUF_SIZE];
ignoreCase = FALSE; ignoreCase = FALSE;
tellLine = FALSE; tellLine = FALSE;
@ -128,21 +102,21 @@ extern int grep_main (int argc, char **argv)
line = 0; line = 0;
while (fgets (buf, sizeof (buf), fp)) { while (fgets (haystack, sizeof (haystack), fp)) {
line++; line++;
cp = &buf[strlen (buf) - 1]; cp = &haystack[strlen (haystack) - 1];
if (*cp != '\n') if (*cp != '\n')
fprintf (stderr, "%s: Line too long\n", name); fprintf (stderr, "%s: Line too long\n", name);
if (search (buf, needle, ignoreCase)==TRUE) { if (find_match(haystack, needle, ignoreCase) == TRUE) {
if (tellName==TRUE) if (tellName==TRUE)
printf ("%s: ", name); printf ("%s: ", name);
if (tellLine==TRUE) if (tellLine==TRUE)
printf ("%ld: ", line); printf ("%ld: ", line);
fputs (buf, stdout); fputs (haystack, stdout);
} }
} }

46
grep.c
View File

@ -22,6 +22,7 @@
*/ */
#include "internal.h" #include "internal.h"
#include "regexp.h"
#include <stdio.h> #include <stdio.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
@ -30,44 +31,17 @@
#include <time.h> #include <time.h>
#include <ctype.h> #include <ctype.h>
static const char grep_usage[] = static const char grep_usage[] =
"grep [-ihn]... PATTERN [FILE]...\n" "grep [-ihn]... PATTERN [FILE]...\n"
"Search for PATTERN in each FILE or standard input.\n\n" "Search for PATTERN in each FILE or standard input.\n\n"
"\t-h\tsuppress the prefixing filename on output\n" "\t-h\tsuppress the prefixing filename on output\n"
"\t-i\tignore case distinctions\n" "\t-i\tignore case distinctions\n"
"\t-n\tprint line number with output lines\n\n" "\t-n\tprint line number with output lines\n\n"
#if defined BB_REGEXP
"This version of grep matches full regexps.\n";
#else
"This version of grep matches strings (not full regexps).\n"; "This version of grep matches strings (not full regexps).\n";
#endif
/*
* See if the specified needle is found in the specified haystack.
*/
static int search (const char *haystack, const char *needle, int ignoreCase)
{
if (ignoreCase == FALSE) {
haystack = strstr (haystack, needle);
if (haystack == NULL)
return FALSE;
return TRUE;
} else {
int i;
char needle1[BUF_SIZE];
char haystack1[BUF_SIZE];
strncpy( haystack1, haystack, sizeof(haystack1));
strncpy( needle1, needle, sizeof(needle1));
for( i=0; i<sizeof(haystack1) && haystack1[i]; i++)
haystack1[i]=tolower( haystack1[i]);
for( i=0; i<sizeof(needle1) && needle1[i]; i++)
needle1[i]=tolower( needle1[i]);
haystack = strstr (haystack1, needle1);
if (haystack == NULL)
return FALSE;
return TRUE;
}
}
extern int grep_main (int argc, char **argv) extern int grep_main (int argc, char **argv)
@ -80,7 +54,7 @@ extern int grep_main (int argc, char **argv)
int ignoreCase=FALSE; int ignoreCase=FALSE;
int tellLine=FALSE; int tellLine=FALSE;
long line; long line;
char buf[BUF_SIZE]; char haystack[BUF_SIZE];
ignoreCase = FALSE; ignoreCase = FALSE;
tellLine = FALSE; tellLine = FALSE;
@ -128,21 +102,21 @@ extern int grep_main (int argc, char **argv)
line = 0; line = 0;
while (fgets (buf, sizeof (buf), fp)) { while (fgets (haystack, sizeof (haystack), fp)) {
line++; line++;
cp = &buf[strlen (buf) - 1]; cp = &haystack[strlen (haystack) - 1];
if (*cp != '\n') if (*cp != '\n')
fprintf (stderr, "%s: Line too long\n", name); fprintf (stderr, "%s: Line too long\n", name);
if (search (buf, needle, ignoreCase)==TRUE) { if (find_match(haystack, needle, ignoreCase) == TRUE) {
if (tellName==TRUE) if (tellName==TRUE)
printf ("%s: ", name); printf ("%s: ", name);
if (tellLine==TRUE) if (tellLine==TRUE)
printf ("%ld: ", line); printf ("%ld: ", line);
fputs (buf, stdout); fputs (haystack, stdout);
} }
} }

View File

@ -130,7 +130,6 @@ int fullRead(int fd, char *buf, int len);
int recursiveAction(const char *fileName, int recurse, int followLinks, int delayDirAction, int recursiveAction(const char *fileName, int recurse, int followLinks, int delayDirAction,
int (*fileAction) (const char *fileName, struct stat* statbuf), int (*fileAction) (const char *fileName, struct stat* statbuf),
int (*dirAction) (const char *fileName, struct stat* statbuf)); int (*dirAction) (const char *fileName, struct stat* statbuf));
int match(const char* text, const char * pattern);
const char* timeString(time_t timeVal); const char* timeString(time_t timeVal);
extern void createPath (const char *name, int mode); extern void createPath (const char *name, int mode);
@ -166,8 +165,9 @@ static inline int clrbit(char * addr,unsigned int nr)
return __res != 0; return __res != 0;
} }
#endif #endif /* inline bitops junk */
#endif
#endif /* _INTERNAL_H_ */

826
regexp.c Normal file
View File

@ -0,0 +1,826 @@
/* regexp.c */
#include "internal.h"
#include "regexp.h"
#include <setjmp.h>
#include <stdio.h>
#include <ctype.h>
#if ( defined BB_GREP || defined BB_FIND )
/* This also tries to find a needle in a haystack, but uses
* real regular expressions.... The fake regular expression
* version of find_match lives in utility.c. Using this version
* will add 3.9k to busybox...
* -Erik Andersen
*/
extern int find_match(char *haystack, char *needle, int ignoreCase)
{
int status;
struct regexp* re;
re = regcomp( needle);
status = regexec(re, haystack, FALSE, ignoreCase);
free( re);
return( status);
}
/* code swiped from elvis-tiny 1.4 (a clone of vi) and adjusted to
* suit the needs of busybox by Erik Andersen.
*
* From the README:
* "Elvis is freely redistributable, in either source form or executable form.
* There are no restrictions on how you may use it".
* Elvis was written by Steve Kirkendall <kirkenda@cs.pdx.edu>
*
*
* This file contains the code that compiles regular expressions and executes
* them. It supports the same syntax and features as vi's regular expression
* code. Specifically, the meta characters are:
* ^ matches the beginning of a line
* $ matches the end of a line
* \< matches the beginning of a word
* \> matches the end of a word
* . matches any single character
* [] matches any character in a character class
* \( delimits the start of a subexpression
* \) delimits the end of a subexpression
* * repeats the preceding 0 or more times
* NOTE: You cannot follow a \) with a *.
*
* The physical structure of a compiled RE is as follows:
* - First, there is a one-byte value that says how many character classes
* are used in this regular expression
* - Next, each character class is stored as a bitmap that is 256 bits
* (32 bytes) long.
* - A mixture of literal characters and compiled meta characters follows.
* This begins with M_BEGIN(0) and ends with M_END(0). All meta chars
* are stored as a \n followed by a one-byte code, so they take up two
* bytes apiece. Literal characters take up one byte apiece. \n can't
* be used as a literal character.
*
*/
static char *previous; /* the previous regexp, used when null regexp is given */
static char *previous1; /* a copy of the text from the previous substitution for regsub()*/
/* These are used to classify or recognize meta-characters */
#define META '\0'
#define BASE_META(m) ((m) - 256)
#define INT_META(c) ((c) + 256)
#define IS_META(m) ((m) >= 256)
#define IS_CLASS(m) ((m) >= M_CLASS(0) && (m) <= M_CLASS(9))
#define IS_START(m) ((m) >= M_START(0) && (m) <= M_START(9))
#define IS_END(m) ((m) >= M_END(0) && (m) <= M_END(9))
#define IS_CLOSURE(m) ((m) >= M_SPLAT && (m) <= M_QMARK)
#define ADD_META(s,m) (*(s)++ = META, *(s)++ = BASE_META(m))
#define GET_META(s) (*(s) == META ? INT_META(*++(s)) : *s)
/* These are the internal codes used for each type of meta-character */
#define M_BEGLINE 256 /* internal code for ^ */
#define M_ENDLINE 257 /* internal code for $ */
#define M_BEGWORD 258 /* internal code for \< */
#define M_ENDWORD 259 /* internal code for \> */
#define M_ANY 260 /* internal code for . */
#define M_SPLAT 261 /* internal code for * */
#define M_PLUS 262 /* internal code for \+ */
#define M_QMARK 263 /* internal code for \? */
#define M_CLASS(n) (264+(n)) /* internal code for [] */
#define M_START(n) (274+(n)) /* internal code for \( */
#define M_END(n) (284+(n)) /* internal code for \) */
/* These are used during compilation */
static int class_cnt; /* used to assign class IDs */
static int start_cnt; /* used to assign start IDs */
static int end_stk[NSUBEXP];/* used to assign end IDs */
static int end_sp;
static char *retext; /* points to the text being compiled */
/* error-handling stuff */
jmp_buf errorhandler;
#define FAIL(why) fprintf(stderr, why); longjmp(errorhandler, 1)
/* This function builds a bitmap for a particular class */
/* text -- start of the class */
/* bmap -- the bitmap */
static char *makeclass(char* text, char* bmap)
{
int i;
int complement = 0;
/* zero the bitmap */
for (i = 0; bmap && i < 32; i++)
{
bmap[i] = 0;
}
/* see if we're going to complement this class */
if (*text == '^')
{
text++;
complement = 1;
}
/* add in the characters */
while (*text && *text != ']')
{
/* is this a span of characters? */
if (text[1] == '-' && text[2])
{
/* spans can't be backwards */
if (text[0] > text[2])
{
FAIL("Backwards span in []");
}
/* add each character in the span to the bitmap */
for (i = text[0]; bmap && i <= text[2]; i++)
{
bmap[i >> 3] |= (1 << (i & 7));
}
/* move past this span */
text += 3;
}
else
{
/* add this single character to the span */
i = *text++;
if (bmap)
{
bmap[i >> 3] |= (1 << (i & 7));
}
}
}
/* make sure the closing ] is missing */
if (*text++ != ']')
{
FAIL("] missing");
}
/* if we're supposed to complement this class, then do so */
if (complement && bmap)
{
for (i = 0; i < 32; i++)
{
bmap[i] = ~bmap[i];
}
}
return text;
}
/* This function gets the next character or meta character from a string.
* The pointer is incremented by 1, or by 2 for \-quoted characters. For [],
* a bitmap is generated via makeclass() (if re is given), and the
* character-class text is skipped.
*/
static int gettoken(sptr, re)
char **sptr;
regexp *re;
{
int c;
c = **sptr;
++*sptr;
if (c == '\\')
{
c = **sptr;
++*sptr;
switch (c)
{
case '<':
return M_BEGWORD;
case '>':
return M_ENDWORD;
case '(':
if (start_cnt >= NSUBEXP)
{
FAIL("Too many \\(s");
}
end_stk[end_sp++] = start_cnt;
return M_START(start_cnt++);
case ')':
if (end_sp <= 0)
{
FAIL("Mismatched \\)");
}
return M_END(end_stk[--end_sp]);
case '*':
return M_SPLAT;
case '.':
return M_ANY;
case '+':
return M_PLUS;
case '?':
return M_QMARK;
default:
return c;
}
}
else {
switch (c)
{
case '^':
if (*sptr == retext + 1)
{
return M_BEGLINE;
}
return c;
case '$':
if (!**sptr)
{
return M_ENDLINE;
}
return c;
case '.':
return M_ANY;
case '*':
return M_SPLAT;
case '[':
/* make sure we don't have too many classes */
if (class_cnt >= 10)
{
FAIL("Too many []s");
}
/* process the character list for this class */
if (re)
{
/* generate the bitmap for this class */
*sptr = makeclass(*sptr, re->program + 1 + 32 * class_cnt);
}
else
{
/* skip to end of the class */
*sptr = makeclass(*sptr, (char *)0);
}
return M_CLASS(class_cnt++);
default:
return c;
}
}
/*NOTREACHED*/
}
/* This function calculates the number of bytes that will be needed for a
* compiled RE. Its argument is the uncompiled version. It is not clever
* about catching syntax errors; that is done in a later pass.
*/
static unsigned calcsize(text)
char *text;
{
unsigned size;
int token;
retext = text;
class_cnt = 0;
start_cnt = 1;
end_sp = 0;
size = 5;
while ((token = gettoken(&text, (regexp *)0)) != 0)
{
if (IS_CLASS(token))
{
size += 34;
}
else if (IS_META(token))
{
size += 2;
}
else
{
size++;
}
}
return size;
}
/*---------------------------------------------------------------------------*/
/* This function checks for a match between a character and a token which is
* known to represent a single character. It returns 0 if they match, or
* 1 if they don't.
*/
static int match1(regexp* re, char ch, int token, int ignoreCase)
{
if (!ch)
{
/* the end of a line can't match any RE of width 1 */
return 1;
}
if (token == M_ANY)
{
return 0;
}
else if (IS_CLASS(token))
{
if (re->program[1 + 32 * (token - M_CLASS(0)) + (ch >> 3)] & (1 << (ch & 7)))
return 0;
}
else if (ch == token
|| (ignoreCase==TRUE && isupper(ch) && tolower(ch) == token))
{
return 0;
}
return 1;
}
/* This function checks characters up to and including the next closure, at
* which point it does a recursive call to check the rest of it. This function
* returns 0 if everything matches, or 1 if something doesn't match.
*/
/* re -- the regular expression */
/* str -- the string */
/* prog -- a portion of re->program, an compiled RE */
/* here -- a portion of str, the string to compare it to */
static int match(regexp* re, char* str, char* prog, char* here, int ignoreCase)
{
int token;
int nmatched;
int closure;
for (token = GET_META(prog); !IS_CLOSURE(token); prog++, token = GET_META(prog))
{
switch (token)
{
/*case M_BEGLINE: can't happen; re->bol is used instead */
case M_ENDLINE:
if (*here)
return 1;
break;
case M_BEGWORD:
if (here != str &&
(here[-1] == '_' ||
(isascii(here[-1]) && isalnum(here[-1]))))
return 1;
break;
case M_ENDWORD:
if ((here[0] == '_' || isascii(here[0])) && isalnum(here[0]))
return 1;
break;
case M_START(0):
case M_START(1):
case M_START(2):
case M_START(3):
case M_START(4):
case M_START(5):
case M_START(6):
case M_START(7):
case M_START(8):
case M_START(9):
re->startp[token - M_START(0)] = (char *)here;
break;
case M_END(0):
case M_END(1):
case M_END(2):
case M_END(3):
case M_END(4):
case M_END(5):
case M_END(6):
case M_END(7):
case M_END(8):
case M_END(9):
re->endp[token - M_END(0)] = (char *)here;
if (token == M_END(0))
{
return 0;
}
break;
default: /* literal, M_CLASS(n), or M_ANY */
if (match1(re, *here, token, ignoreCase) != 0)
return 1;
here++;
}
}
/* C L O S U R E */
/* step 1: see what we have to match against, and move "prog" to point
* the the remainder of the compiled RE.
*/
closure = token;
prog++, token = GET_META(prog);
prog++;
/* step 2: see how many times we can match that token against the string */
for (nmatched = 0;
(closure != M_QMARK || nmatched < 1) && *here && match1(re, *here, token, ignoreCase) == 0;
nmatched++, here++)
{
}
/* step 3: try to match the remainder, and back off if it doesn't */
while (nmatched >= 0 && match(re, str, prog, here, ignoreCase) != 0)
{
nmatched--;
here--;
}
/* so how did it work out? */
if (nmatched >= ((closure == M_PLUS) ? 1 : 0))
return 0;
return 1;
}
/* This function compiles a regexp. */
extern regexp *regcomp(char* text)
{
int needfirst;
unsigned size;
int token;
int peek;
char *build;
regexp *re;
/* prepare for error handling */
re = (regexp *)0;
if (setjmp(errorhandler))
{
if (re)
{
free(re);
}
return (regexp *)0;
}
/* if an empty regexp string was given, use the previous one */
if (*text == 0)
{
if (!previous)
{
FAIL("No previous RE");
}
text = previous;
}
else /* non-empty regexp given, so remember it */
{
if (previous)
free(previous);
previous = (char *)malloc((unsigned)(strlen(text) + 1));
if (previous)
strcpy(previous, text);
}
/* allocate memory */
class_cnt = 0;
start_cnt = 1;
end_sp = 0;
retext = text;
size = calcsize(text) + sizeof(regexp);
re = (regexp *)malloc((unsigned)size);
if (!re)
{
FAIL("Not enough memory for this RE");
}
/* compile it */
build = &re->program[1 + 32 * class_cnt];
re->program[0] = class_cnt;
for (token = 0; token < NSUBEXP; token++)
{
re->startp[token] = re->endp[token] = (char *)0;
}
re->first = 0;
re->bol = 0;
re->minlen = 0;
needfirst = 1;
class_cnt = 0;
start_cnt = 1;
end_sp = 0;
retext = text;
for (token = M_START(0), peek = gettoken(&text, re);
token;
token = peek, peek = gettoken(&text, re))
{
/* special processing for the closure operator */
if (IS_CLOSURE(peek))
{
/* detect misuse of closure operator */
if (IS_START(token))
{
FAIL("* or \\+ or \\? follows nothing");
}
else if (IS_META(token) && token != M_ANY && !IS_CLASS(token))
{
FAIL("* or \\+ or \\? can only follow a normal character or . or []");
}
/* it is okay -- make it prefix instead of postfix */
ADD_META(build, peek);
/* take care of "needfirst" - is this the first char? */
if (needfirst && peek == M_PLUS && !IS_META(token))
{
re->first = token;
}
needfirst = 0;
/* we used "peek" -- need to refill it */
peek = gettoken(&text, re);
if (IS_CLOSURE(peek))
{
FAIL("* or \\+ or \\? doubled up");
}
}
else if (!IS_META(token))
{
/* normal char is NOT argument of closure */
if (needfirst)
{
re->first = token;
needfirst = 0;
}
re->minlen++;
}
else if (token == M_ANY || IS_CLASS(token))
{
/* . or [] is NOT argument of closure */
needfirst = 0;
re->minlen++;
}
/* the "token" character is not closure -- process it normally */
if (token == M_BEGLINE)
{
/* set the BOL flag instead of storing M_BEGLINE */
re->bol = 1;
}
else if (IS_META(token))
{
ADD_META(build, token);
}
else
{
*build++ = token;
}
}
/* end it with a \) which MUST MATCH the opening \( */
ADD_META(build, M_END(0));
if (end_sp > 0)
{
FAIL("Not enough \\)s");
}
return re;
}
/* This function searches through a string for text that matches an RE. */
/* re -- the compiled regexp to search for */
/* str -- the string to search through */
/* bol -- does str start at the beginning of a line? (boolean) */
/* ignoreCase -- ignoreCase or not */
extern int regexec(struct regexp* re, char* str, int bol, int ignoreCase)
{
char *prog; /* the entry point of re->program */
int len; /* length of the string */
char *here;
/* if must start at the beginning of a line, and this isn't, then fail */
if (re->bol && bol==TRUE)
{
return FALSE;
}
len = strlen(str);
prog = re->program + 1 + 32 * re->program[0];
/* search for the RE in the string */
if (re->bol)
{
/* must occur at BOL */
if ((re->first
&& match1(re, *(char *)str, re->first, ignoreCase))/* wrong first letter? */
|| len < re->minlen /* not long enough? */
|| match(re, (char *)str, prog, str, ignoreCase)) /* doesn't match? */
return FALSE; /* THEN FAIL! */
}
else if (ignoreCase == FALSE)
{
/* can occur anywhere in the line, noignorecase */
for (here = (char *)str;
(re->first && re->first != *here)
|| match(re, (char *)str, prog, here, ignoreCase);
here++, len--)
{
if (len < re->minlen)
return FALSE;
}
}
else
{
/* can occur anywhere in the line, ignorecase */
for (here = (char *)str;
(re->first && match1(re, *here, (int)re->first, ignoreCase))
|| match(re, (char *)str, prog, here, ignoreCase);
here++, len--)
{
if (len < re->minlen)
return FALSE;
}
}
/* if we didn't fail, then we must have succeeded */
return TRUE;
}
/* This performs substitutions after a regexp match has been found. */
extern void regsub(regexp* re, char* src, char* dst)
{
char *cpy;
char *end;
char c;
char *start;
int mod;
mod = 0;
start = src;
while ((c = *src++) != '\0')
{
/* recognize any meta characters */
if (c == '&')
{
cpy = re->startp[0];
end = re->endp[0];
}
else if (c == '~')
{
cpy = previous1;
if (cpy)
end = cpy + strlen(cpy);
}
else
if (c == '\\')
{
c = *src++;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/* \0 thru \9 mean "copy subexpression" */
c -= '0';
cpy = re->startp[(int)c];
end = re->endp[(int)c];
break;
case 'U':
case 'u':
case 'L':
case 'l':
/* \U and \L mean "convert to upper/lowercase" */
mod = c;
continue;
case 'E':
case 'e':
/* \E ends the \U or \L */
mod = 0;
continue;
case '&':
/* "\&" means "original text" */
*dst++ = c;
continue;
case '~':
/* "\~" means "previous text, if any" */
*dst++ = c;
continue;
default:
/* ordinary char preceded by backslash */
*dst++ = c;
continue;
}
}
else
{
/* ordinary character, so just copy it */
*dst++ = c;
continue;
}
/* Note: to reach this point in the code, we must have evaded
* all "continue" statements. To do that, we must have hit
* a metacharacter that involves copying.
*/
/* if there is nothing to copy, loop */
if (!cpy)
continue;
/* copy over a portion of the original */
while (cpy < end)
{
switch (mod)
{
case 'U':
case 'u':
/* convert to uppercase */
if (isascii(*cpy) && islower(*cpy))
{
*dst++ = toupper(*cpy);
cpy++;
}
else
{
*dst++ = *cpy++;
}
break;
case 'L':
case 'l':
/* convert to lowercase */
if (isascii(*cpy) && isupper(*cpy))
{
*dst++ = tolower(*cpy);
cpy++;
}
else
{
*dst++ = *cpy++;
}
break;
default:
/* copy without any conversion */
*dst++ = *cpy++;
}
/* \u and \l end automatically after the first char */
if (mod && (mod == 'u' || mod == 'l'))
{
mod = 0;
}
}
}
*dst = '\0';
/* remember what text we inserted this time */
if (previous1)
free(previous1);
previous1 = (char *)malloc((unsigned)(strlen(start) + 1));
if (previous1)
strcpy(previous1, start);
}
#endif /* BB_REGEXP */

View File

@ -1,2 +0,0 @@
echo '.' >smtpout echo 'QUIT' >smtpout
kjfjkjd

149
utility.c
View File

@ -53,12 +53,17 @@ volatile void usage(const char *usage)
int int
get_kernel_revision() get_kernel_revision()
{ {
FILE *f; FILE *file;
int major=0, minor=0, patch=0; int major=0, minor=0, patch=0;
char* filename="/proc/sys/kernel/osrelease";
f = fopen("/proc/sys/kernel/osrelease","r"); file = fopen(filename,"r");
fscanf(f,"%d.%d.%d",&major,&minor,&patch); if (file == NULL) {
fclose(f); perror(filename);
return( 0);
}
fscanf(file,"%d.%d.%d",&major,&minor,&patch);
fclose(file);
return major*65536 + minor*256 + patch; return major*65536 + minor*256 + patch;
} }
@ -311,94 +316,6 @@ const char *timeString(time_t timeVal)
} }
/*
* Routine to see if a text string is matched by a wildcard pattern.
* Returns TRUE if the text is matched, or FALSE if it is not matched
* or if the pattern is invalid.
* * matches zero or more characters
* ? matches a single character
* [abc] matches 'a', 'b' or 'c'
* \c quotes character c
* Adapted from code written by Ingo Wilken.
*/
int match(const char *text, const char *pattern)
{
const char *retryPat;
const char *retryText;
int ch;
int found;
retryPat = NULL;
retryText = NULL;
while (*text || *pattern) {
ch = *pattern++;
switch (ch) {
case '*':
retryPat = pattern;
retryText = text;
break;
case '[':
found = FALSE;
while ((ch = *pattern++) != ']') {
if (ch == '\\')
ch = *pattern++;
if (ch == '\0')
return FALSE;
if (*text == ch)
found = TRUE;
}
if (!found) {
pattern = retryPat;
text = ++retryText;
}
/* fall into next case */
case '?':
if (*text++ == '\0')
return FALSE;
break;
case '\\':
ch = *pattern++;
if (ch == '\0')
return FALSE;
/* fall into next case */
default:
if (*text == ch) {
if (*text)
text++;
break;
}
if (*text) {
pattern = retryPat;
text = ++retryText;
break;
}
return FALSE;
}
if (pattern == NULL)
return FALSE;
}
return TRUE;
}
/* /*
* Write all of the supplied buffer out to a file. * Write all of the supplied buffer out to a file.
* This does multiple writes as necessary. * This does multiple writes as necessary.
@ -695,13 +612,17 @@ parse_mode( const char* s, mode_t* theMode)
uid_t uid_t
my_getid(const char *filename, char *name, uid_t id) my_getid(const char *filename, char *name, uid_t id)
{ {
FILE *stream; FILE *file;
char *rname, *start, *end, buf[128]; char *rname, *start, *end, buf[128];
uid_t rid; uid_t rid;
stream=fopen(filename,"r"); file=fopen(filename,"r");
if (file == NULL) {
perror(filename);
return (-1);
}
while (fgets (buf, 128, stream) != NULL) { while (fgets (buf, 128, file) != NULL) {
if (buf[0] == '#') if (buf[0] == '#')
continue; continue;
@ -731,7 +652,7 @@ my_getid(const char *filename, char *name, uid_t id)
return( TRUE); return( TRUE);
} }
} }
fclose(stream); fclose(file);
return (-1); return (-1);
} }
@ -763,4 +684,40 @@ my_getgrgid(char* group, gid_t gid)
#endif #endif
#if !defined BB_REGEXP && (defined BB_GREP || defined BB_FIND )
/* This tries to find a needle in a haystack, but does so by
* only trying to match literal strings (look 'ma, no regexps!)
* This is short, sweet, and carries _very_ little baggage,
* unlike its beefier cousin a few lines down...
* -Erik Andersen
*/
extern int find_match(char *haystack, char *needle, int ignoreCase)
{
if (ignoreCase == FALSE) {
haystack = strstr (haystack, needle);
if (haystack == NULL)
return FALSE;
return TRUE;
} else {
int i;
char needle1[BUF_SIZE];
char haystack1[BUF_SIZE];
strncpy( haystack1, haystack, sizeof(haystack1));
strncpy( needle1, needle, sizeof(needle1));
for( i=0; i<sizeof(haystack1) && haystack1[i]; i++)
haystack1[i]=tolower( haystack1[i]);
for( i=0; i<sizeof(needle1) && needle1[i]; i++)
needle1[i]=tolower( needle1[i]);
haystack = strstr (haystack1, needle1);
if (haystack == NULL)
return FALSE;
return TRUE;
}
}
#endif
/* END CODE */ /* END CODE */