Added regexp support, fixed Changelog.
authorEric Andersen <andersen@codepoet.org>
Fri, 22 Oct 1999 04:30:20 +0000 (04:30 -0000)
committerEric Andersen <andersen@codepoet.org>
Fri, 22 Oct 1999 04:30:20 +0000 (04:30 -0000)
Changelog
busybox.def.h
find.c
findutils/find.c
findutils/grep.c
grep.c
internal.h
regexp.c [new file with mode: 0644]
smtpout [deleted file]
utility.c

index 951aee57f9c05048ebb2a853bf8789798c6b01de..4d652a5bb75e4ae3dc3e73fb6f2e335c44725e12 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -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
        Major changes -- lots of stuff rewritten. Many thanks to Lineo for
        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
        
 0.28   
index 692f24e496b3b812a4df6d715135b69d6b3f4ff5..033ccca844f04ca5e73b9c8dc6ac5e2b441b89f6 100644 (file)
@@ -40,6 +40,7 @@
 //#define BB_PRINTF
 #define BB_PS
 #define BB_PWD
+#define BB_REGEXP
 #define BB_REBOOT
 #define BB_RM
 #define BB_RMDIR
@@ -52,6 +53,8 @@
 //#define BB_TRUE_FALSE  // Supplied by ash
 #define BB_UMOUNT
 #define BB_UPDATE
-#define BB_UTILITY
 #define BB_ZCAT
 //#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
diff --git a/find.c b/find.c
index 1db332297a4e558c59515a9522a4974b7ebc03c2..c154cf4e784a6923552838e9ba12a313bf94efb1 100644 (file)
--- a/find.c
+++ b/find.c
  *
  */
 
+#include "internal.h"
+#include "regexp.h"
 #include <stdio.h>
 #include <unistd.h>
 #include <dirent.h>
-#include "internal.h"
 
 
 static char* pattern=NULL;
-static char* directory=NULL;
+static char* directory=".";
 static int dereferenceFlag=FALSE;
 
 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)
        fprintf(stdout, "%s\n", fileName);
-    else if (match(fileName, pattern) == TRUE)
+    else if (find_match(fileName, pattern, TRUE) == TRUE)
        fprintf(stdout, "%s\n", fileName);
     return( TRUE);
 }
@@ -53,7 +54,7 @@ static int dirAction(const char *fileName, struct stat* statbuf)
     
     if (pattern==NULL)
        fprintf(stdout, "%s\n", fileName);
-    else if (match(fileName, pattern) == TRUE)
+    else if (find_match(fileName, pattern, TRUE) == TRUE)
        fprintf(stdout, "%s\n", fileName);
 
     dir = opendir( fileName);
@@ -71,22 +72,18 @@ static int dirAction(const char *fileName, struct stat* statbuf)
 
 int find_main(int argc, char **argv)
 {
-    if (argc <= 1) {
-       dirAction( ".", NULL); 
-    }
-
     /* peel off the "find" */
     argc--;
     argv++;
 
-    if (**argv != '-') {
+    if ( argc > 0 && **argv != '-') {
        directory=*argv;
        argc--;
        argv++;
     }
 
     /* Parse any options */
-    while (**argv == '-') {
+    while (argc > 0 && **argv == '-') {
        int stopit=FALSE;
        while (*++(*argv) && stopit==FALSE) switch (**argv) {
            case 'f':
@@ -120,6 +117,10 @@ int find_main(int argc, char **argv)
            break;
     }
 
-    dirAction( directory, NULL); 
+    if (recursiveAction(directory, TRUE, FALSE, FALSE,
+                          fileAction, fileAction) == FALSE) {
+       exit( FALSE);
+    }
+
     exit(TRUE);
 }
index 1db332297a4e558c59515a9522a4974b7ebc03c2..c154cf4e784a6923552838e9ba12a313bf94efb1 100644 (file)
  *
  */
 
+#include "internal.h"
+#include "regexp.h"
 #include <stdio.h>
 #include <unistd.h>
 #include <dirent.h>
-#include "internal.h"
 
 
 static char* pattern=NULL;
-static char* directory=NULL;
+static char* directory=".";
 static int dereferenceFlag=FALSE;
 
 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)
        fprintf(stdout, "%s\n", fileName);
-    else if (match(fileName, pattern) == TRUE)
+    else if (find_match(fileName, pattern, TRUE) == TRUE)
        fprintf(stdout, "%s\n", fileName);
     return( TRUE);
 }
@@ -53,7 +54,7 @@ static int dirAction(const char *fileName, struct stat* statbuf)
     
     if (pattern==NULL)
        fprintf(stdout, "%s\n", fileName);
-    else if (match(fileName, pattern) == TRUE)
+    else if (find_match(fileName, pattern, TRUE) == TRUE)
        fprintf(stdout, "%s\n", fileName);
 
     dir = opendir( fileName);
@@ -71,22 +72,18 @@ static int dirAction(const char *fileName, struct stat* statbuf)
 
 int find_main(int argc, char **argv)
 {
-    if (argc <= 1) {
-       dirAction( ".", NULL); 
-    }
-
     /* peel off the "find" */
     argc--;
     argv++;
 
-    if (**argv != '-') {
+    if ( argc > 0 && **argv != '-') {
        directory=*argv;
        argc--;
        argv++;
     }
 
     /* Parse any options */
-    while (**argv == '-') {
+    while (argc > 0 && **argv == '-') {
        int stopit=FALSE;
        while (*++(*argv) && stopit==FALSE) switch (**argv) {
            case 'f':
@@ -120,6 +117,10 @@ int find_main(int argc, char **argv)
            break;
     }
 
-    dirAction( directory, NULL); 
+    if (recursiveAction(directory, TRUE, FALSE, FALSE,
+                          fileAction, fileAction) == FALSE) {
+       exit( FALSE);
+    }
+
     exit(TRUE);
 }
index a495c62ae9dfdb42cff7d65a6675e9872c91ee00..44ca028345380fb79776de87a9eddbecf7fb7819 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include "internal.h"
+#include "regexp.h"
 #include <stdio.h>
 #include <dirent.h>
 #include <errno.h>
 #include <time.h>
 #include <ctype.h>
 
-
 static const char grep_usage[] =
 "grep [-ihn]... PATTERN [FILE]...\n"
 "Search for PATTERN in each FILE or standard input.\n\n"
 "\t-h\tsuppress the prefixing filename on output\n"
 "\t-i\tignore case distinctions\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";
-
-
-/*
- * 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;
-    }
-}
+#endif
 
 
 extern int grep_main (int argc, char **argv)
@@ -80,7 +54,7 @@ extern int grep_main (int argc, char **argv)
     int ignoreCase=FALSE;
     int tellLine=FALSE;
     long line;
-    char buf[BUF_SIZE];
+    char haystack[BUF_SIZE];
 
     ignoreCase = FALSE;
     tellLine = FALSE;
@@ -128,21 +102,21 @@ extern int grep_main (int argc, char **argv)
 
        line = 0;
 
-       while (fgets (buf, sizeof (buf), fp)) {
+       while (fgets (haystack, sizeof (haystack), fp)) {
            line++;
-           cp = &buf[strlen (buf) - 1];
+           cp = &haystack[strlen (haystack) - 1];
 
            if (*cp != '\n')
                fprintf (stderr, "%s: Line too long\n", name);
 
-           if (search (buf, needle, ignoreCase)==TRUE) {
+           if (find_match(haystack, needle, ignoreCase) == TRUE) {
                if (tellName==TRUE)
                    printf ("%s: ", name);
 
                if (tellLine==TRUE)
                    printf ("%ld: ", line);
 
-               fputs (buf, stdout);
+               fputs (haystack, stdout);
            }
        }
 
diff --git a/grep.c b/grep.c
index a495c62ae9dfdb42cff7d65a6675e9872c91ee00..44ca028345380fb79776de87a9eddbecf7fb7819 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -22,6 +22,7 @@
  */
 
 #include "internal.h"
+#include "regexp.h"
 #include <stdio.h>
 #include <dirent.h>
 #include <errno.h>
 #include <time.h>
 #include <ctype.h>
 
-
 static const char grep_usage[] =
 "grep [-ihn]... PATTERN [FILE]...\n"
 "Search for PATTERN in each FILE or standard input.\n\n"
 "\t-h\tsuppress the prefixing filename on output\n"
 "\t-i\tignore case distinctions\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";
-
-
-/*
- * 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;
-    }
-}
+#endif
 
 
 extern int grep_main (int argc, char **argv)
@@ -80,7 +54,7 @@ extern int grep_main (int argc, char **argv)
     int ignoreCase=FALSE;
     int tellLine=FALSE;
     long line;
-    char buf[BUF_SIZE];
+    char haystack[BUF_SIZE];
 
     ignoreCase = FALSE;
     tellLine = FALSE;
@@ -128,21 +102,21 @@ extern int grep_main (int argc, char **argv)
 
        line = 0;
 
-       while (fgets (buf, sizeof (buf), fp)) {
+       while (fgets (haystack, sizeof (haystack), fp)) {
            line++;
-           cp = &buf[strlen (buf) - 1];
+           cp = &haystack[strlen (haystack) - 1];
 
            if (*cp != '\n')
                fprintf (stderr, "%s: Line too long\n", name);
 
-           if (search (buf, needle, ignoreCase)==TRUE) {
+           if (find_match(haystack, needle, ignoreCase) == TRUE) {
                if (tellName==TRUE)
                    printf ("%s: ", name);
 
                if (tellLine==TRUE)
                    printf ("%ld: ", line);
 
-               fputs (buf, stdout);
+               fputs (haystack, stdout);
            }
        }
 
index d23dca31ecbbb4a4e9a85e37ac0f1915db38f6e9..cc7bfca115148908ef3085da76f4384307e7eda1 100644 (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 (*fileAction) (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);
 
 extern void createPath (const char *name, int mode);
@@ -166,8 +165,9 @@ static inline int clrbit(char * addr,unsigned int nr)
   return __res != 0;
 }
 
-#endif
+#endif /* inline bitops junk */
 
 
-#endif
+
+#endif /* _INTERNAL_H_ */
 
diff --git a/regexp.c b/regexp.c
new file mode 100644 (file)
index 0000000..6017d79
--- /dev/null
+++ b/regexp.c
@@ -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 */
+
+
diff --git a/smtpout b/smtpout
deleted file mode 100644 (file)
index 635a83c..0000000
--- a/smtpout
+++ /dev/null
@@ -1,2 +0,0 @@
-echo '.' >smtpout\recho 'QUIT' >smtpout
-kjfjkjd
index e188ecdcd6f946c98210a4fb3c13773537aeb794..eb24de2e691da08b583eacf2f13ddf786ac12f49 100644 (file)
--- a/utility.c
+++ b/utility.c
@@ -53,12 +53,17 @@ volatile void usage(const char *usage)
 int
 get_kernel_revision()
 {
-  FILE *f;
+  FILE *file;
   int major=0, minor=0, patch=0;
-
-  f = fopen("/proc/sys/kernel/osrelease","r");
-  fscanf(f,"%d.%d.%d",&major,&minor,&patch);
-  fclose(f);
+  char* filename="/proc/sys/kernel/osrelease";
+
+  file = fopen(filename,"r");
+  if (file == NULL) {
+    perror(filename);
+    return( 0);
+  }
+  fscanf(file,"%d.%d.%d",&major,&minor,&patch);
+  fclose(file);
   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.
  * This does multiple writes as necessary.
@@ -695,13 +612,17 @@ parse_mode( const char* s, mode_t* theMode)
 uid_t 
 my_getid(const char *filename, char *name, uid_t id) 
 {
-       FILE *stream;
+       FILE *file;
        char *rname, *start, *end, buf[128];
        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] == '#')
                        continue;
 
@@ -731,7 +652,7 @@ my_getid(const char *filename, char *name, uid_t id)
                    return( TRUE);
                }
        }
-       fclose(stream);
+       fclose(file);
        return (-1);
 }
 
@@ -763,4 +684,40 @@ my_getgrgid(char* group, gid_t gid)
 #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 */
+