summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>1999-10-22 04:30:20 +0000
committerEric Andersen <andersen@codepoet.org>1999-10-22 04:30:20 +0000
commitaa0765e11bdeba5c5abf745369a8430c8311d60c (patch)
tree3593c1a2ff03bfa79982fa12b55c9489f969e057
parentc49960189a04b73e033016bd0f43fbb950f800e1 (diff)
downloadbusybox-w32-aa0765e11bdeba5c5abf745369a8430c8311d60c.tar.gz
busybox-w32-aa0765e11bdeba5c5abf745369a8430c8311d60c.tar.bz2
busybox-w32-aa0765e11bdeba5c5abf745369a8430c8311d60c.zip
Added regexp support, fixed Changelog.
-rw-r--r--Changelog76
-rw-r--r--busybox.def.h5
-rw-r--r--find.c23
-rw-r--r--findutils/find.c23
-rw-r--r--findutils/grep.c46
-rw-r--r--grep.c46
-rw-r--r--internal.h6
-rw-r--r--regexp.c826
-rw-r--r--smtpout2
-rw-r--r--utility.c151
10 files changed, 1006 insertions, 198 deletions
diff --git a/Changelog b/Changelog
index 951aee57f..4d652a5bb 100644
--- a/Changelog
+++ b/Changelog
@@ -1,7 +1,81 @@
10.31
2 * I added a changelog for version 0.30.
3 * adjusted find internals to make it smaller, and removed
4 some redundancy.
5 * Fixed a segfault in ps when /etc/passwd or /etc/group
6 are absent. Now will warn you and carry on.
7 * Added in optional _real_ regular expression support (to be
8 the basis for a future sed utility). When compiled in,
9 adds 3.9k.
10
11
10.30 120.30
2 Major changes -- lots of stuff rewritten. Many thanks to Lineo for 13 Major changes -- lots of stuff rewritten. Many thanks to Lineo for
3 paying me to make these updates. If you have any problems with busybox, 14 paying me to make these updates. If you have any problems with busybox,
4 or notice any bugs -- please let me know so I can fix it. 15 or notice any bugs -- please let me know so I can fix it. These
16 changes include:
17
18 Core Changes:
19 * busybox can now invoke apps in two ways: via symlinks to the
20 busybox binary, and as 'busybox [function] [arguments]...'
21 * When invoked as busybox, the list of currently compiled in
22 functions is printed out (no this is not bloat -- the list
23 has to be there anyway to map invocation name to function).
24 * busybox no longer parses command lines for apps or displays their
25 usage info. Each app gets to handle (or not handle) this for
26 itself.
27 * Eliminated monadic, dyadic, descend, block_device, and
28 postprocess. It was cumbersome to have so many programs
29 cobbled together in this way. Without them, the app is much
30 more granular.
31 * All shared code now lives in utility.c, and is properly
32 ifdef'ed to be only included for those apps requiring it.
33 * Eliminated struct FileInfo (the basis of monadic, dyadic, etc)
34 so now each app has the function prototype of (da-dum):
35 extern int foo_main(int argc, char** argv);
36 which speeds integration of new apps.
37 * Adjusted the Makefile to make it easier to
38 {en|dis}able debugging.
39 * Changed default compiler optimization to -Os
40 (optimize for smaller binaries).
41
42 App Changes:
43 * To cope with the new app function prototype and the removal of
44 monadic, dyadic, etc, the following apps were re-written:
45 * cat - Works same as always.
46 * chgrp, chmod, chown - rewrite. Combined into a single
47 source file. Absorbed patches from Enrique Zanardi <ezanard@debian.org>
48 that removes the dependency on libc6 libnss* libraries.
49 * cp - Can now do 'cp -a' can can copy devices,
50 pipes, symlinks, as well as recursive or non-recursive dir copies.
51 * fdflush - adjusted to remove dependancy on struct FileInfo.
52 * find - Now includes some basic regexp matching
53 which will be the basic of a future mini-sed.
54 * ln - Same functionality.
55 * mkdir - Added -p flag to feature set.
56 * mv - rewrite.
57 * rm - Added -f flag to feature set.
58 * rmdir - Same functionality.
59 * swapon, swapoff - Combined into a single binary. No longer
60 uses /etc/swaps. swap{on|off} -a uses /etc/fstab instead.
61 * touch - Same functionality.
62 * date - adjusted with a patch from Matthew Grant <grantma@anathoth.gen.nz>
63 to accomodate glibc timezone support. I then ripped out GNU getopt.
64 * mkswap -- new version merged from util-linux. Can now make >128Meg swaps.
65 * Replaced the old and star, unstar, and tarcat with the tar
66 implementation from sash. Now tar behaves as god intended
67 it to (i.e. tar -xvf <file> and tar -cf <file> <dir> work).
68 * dd -- rewritten. Can with with files, stdin, stdout.
69 * Added the following new apps:
70 * loadfont -- added from debian boot floppies
71 * chroot -- added based on a patch from Paolo Molaro <lupus@lettere.unipd.it>
72 * grep -- I just wrote it. Only matches simple strings
73 * ps -- I just wrote it. Has _no_ options at all, but works.
74 * fsck_minix, mkfs_minix -- added from util-linux, but I ripped out
75 internationalization and such to make them smaller.
76 * sfdisk -- Added from util-linux (minus internationalization and such).
77 * Probably some other changes that I forgot to document...
78
5 -Erik Andersen 79 -Erik Andersen
6 80
70.28 810.28
diff --git a/busybox.def.h b/busybox.def.h
index 692f24e49..033ccca84 100644
--- a/busybox.def.h
+++ b/busybox.def.h
@@ -40,6 +40,7 @@
40//#define BB_PRINTF 40//#define BB_PRINTF
41#define BB_PS 41#define BB_PS
42#define BB_PWD 42#define BB_PWD
43#define BB_REGEXP
43#define BB_REBOOT 44#define BB_REBOOT
44#define BB_RM 45#define BB_RM
45#define BB_RMDIR 46#define BB_RMDIR
@@ -52,6 +53,8 @@
52//#define BB_TRUE_FALSE // Supplied by ash 53//#define BB_TRUE_FALSE // Supplied by ash
53#define BB_UMOUNT 54#define BB_UMOUNT
54#define BB_UPDATE 55#define BB_UPDATE
55#define BB_UTILITY
56#define BB_ZCAT 56#define BB_ZCAT
57//#define BB_GZIP 57//#define BB_GZIP
58// Don't turn BB_UTILITY off. It contains support code
59// that compiles to 0 if everything else if turned off.
60#define BB_UTILITY
diff --git a/find.c b/find.c
index 1db332297..c154cf4e7 100644
--- a/find.c
+++ b/find.c
@@ -21,14 +21,15 @@
21 * 21 *
22 */ 22 */
23 23
24#include "internal.h"
25#include "regexp.h"
24#include <stdio.h> 26#include <stdio.h>
25#include <unistd.h> 27#include <unistd.h>
26#include <dirent.h> 28#include <dirent.h>
27#include "internal.h"
28 29
29 30
30static char* pattern=NULL; 31static char* pattern=NULL;
31static char* directory=NULL; 32static char* directory=".";
32static int dereferenceFlag=FALSE; 33static int dereferenceFlag=FALSE;
33 34
34static const char find_usage[] = "find [path...] [expression]\n" 35static const char find_usage[] = "find [path...] [expression]\n"
@@ -41,7 +42,7 @@ static int fileAction(const char *fileName, struct stat* statbuf)
41{ 42{
42 if (pattern==NULL) 43 if (pattern==NULL)
43 fprintf(stdout, "%s\n", fileName); 44 fprintf(stdout, "%s\n", fileName);
44 else if (match(fileName, pattern) == TRUE) 45 else if (find_match(fileName, pattern, TRUE) == TRUE)
45 fprintf(stdout, "%s\n", fileName); 46 fprintf(stdout, "%s\n", fileName);
46 return( TRUE); 47 return( TRUE);
47} 48}
@@ -53,7 +54,7 @@ static int dirAction(const char *fileName, struct stat* statbuf)
53 54
54 if (pattern==NULL) 55 if (pattern==NULL)
55 fprintf(stdout, "%s\n", fileName); 56 fprintf(stdout, "%s\n", fileName);
56 else if (match(fileName, pattern) == TRUE) 57 else if (find_match(fileName, pattern, TRUE) == TRUE)
57 fprintf(stdout, "%s\n", fileName); 58 fprintf(stdout, "%s\n", fileName);
58 59
59 dir = opendir( fileName); 60 dir = opendir( fileName);
@@ -71,22 +72,18 @@ static int dirAction(const char *fileName, struct stat* statbuf)
71 72
72int find_main(int argc, char **argv) 73int find_main(int argc, char **argv)
73{ 74{
74 if (argc <= 1) {
75 dirAction( ".", NULL);
76 }
77
78 /* peel off the "find" */ 75 /* peel off the "find" */
79 argc--; 76 argc--;
80 argv++; 77 argv++;
81 78
82 if (**argv != '-') { 79 if ( argc > 0 && **argv != '-') {
83 directory=*argv; 80 directory=*argv;
84 argc--; 81 argc--;
85 argv++; 82 argv++;
86 } 83 }
87 84
88 /* Parse any options */ 85 /* Parse any options */
89 while (**argv == '-') { 86 while (argc > 0 && **argv == '-') {
90 int stopit=FALSE; 87 int stopit=FALSE;
91 while (*++(*argv) && stopit==FALSE) switch (**argv) { 88 while (*++(*argv) && stopit==FALSE) switch (**argv) {
92 case 'f': 89 case 'f':
@@ -120,6 +117,10 @@ int find_main(int argc, char **argv)
120 break; 117 break;
121 } 118 }
122 119
123 dirAction( directory, NULL); 120 if (recursiveAction(directory, TRUE, FALSE, FALSE,
121 fileAction, fileAction) == FALSE) {
122 exit( FALSE);
123 }
124
124 exit(TRUE); 125 exit(TRUE);
125} 126}
diff --git a/findutils/find.c b/findutils/find.c
index 1db332297..c154cf4e7 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -21,14 +21,15 @@
21 * 21 *
22 */ 22 */
23 23
24#include "internal.h"
25#include "regexp.h"
24#include <stdio.h> 26#include <stdio.h>
25#include <unistd.h> 27#include <unistd.h>
26#include <dirent.h> 28#include <dirent.h>
27#include "internal.h"
28 29
29 30
30static char* pattern=NULL; 31static char* pattern=NULL;
31static char* directory=NULL; 32static char* directory=".";
32static int dereferenceFlag=FALSE; 33static int dereferenceFlag=FALSE;
33 34
34static const char find_usage[] = "find [path...] [expression]\n" 35static const char find_usage[] = "find [path...] [expression]\n"
@@ -41,7 +42,7 @@ static int fileAction(const char *fileName, struct stat* statbuf)
41{ 42{
42 if (pattern==NULL) 43 if (pattern==NULL)
43 fprintf(stdout, "%s\n", fileName); 44 fprintf(stdout, "%s\n", fileName);
44 else if (match(fileName, pattern) == TRUE) 45 else if (find_match(fileName, pattern, TRUE) == TRUE)
45 fprintf(stdout, "%s\n", fileName); 46 fprintf(stdout, "%s\n", fileName);
46 return( TRUE); 47 return( TRUE);
47} 48}
@@ -53,7 +54,7 @@ static int dirAction(const char *fileName, struct stat* statbuf)
53 54
54 if (pattern==NULL) 55 if (pattern==NULL)
55 fprintf(stdout, "%s\n", fileName); 56 fprintf(stdout, "%s\n", fileName);
56 else if (match(fileName, pattern) == TRUE) 57 else if (find_match(fileName, pattern, TRUE) == TRUE)
57 fprintf(stdout, "%s\n", fileName); 58 fprintf(stdout, "%s\n", fileName);
58 59
59 dir = opendir( fileName); 60 dir = opendir( fileName);
@@ -71,22 +72,18 @@ static int dirAction(const char *fileName, struct stat* statbuf)
71 72
72int find_main(int argc, char **argv) 73int find_main(int argc, char **argv)
73{ 74{
74 if (argc <= 1) {
75 dirAction( ".", NULL);
76 }
77
78 /* peel off the "find" */ 75 /* peel off the "find" */
79 argc--; 76 argc--;
80 argv++; 77 argv++;
81 78
82 if (**argv != '-') { 79 if ( argc > 0 && **argv != '-') {
83 directory=*argv; 80 directory=*argv;
84 argc--; 81 argc--;
85 argv++; 82 argv++;
86 } 83 }
87 84
88 /* Parse any options */ 85 /* Parse any options */
89 while (**argv == '-') { 86 while (argc > 0 && **argv == '-') {
90 int stopit=FALSE; 87 int stopit=FALSE;
91 while (*++(*argv) && stopit==FALSE) switch (**argv) { 88 while (*++(*argv) && stopit==FALSE) switch (**argv) {
92 case 'f': 89 case 'f':
@@ -120,6 +117,10 @@ int find_main(int argc, char **argv)
120 break; 117 break;
121 } 118 }
122 119
123 dirAction( directory, NULL); 120 if (recursiveAction(directory, TRUE, FALSE, FALSE,
121 fileAction, fileAction) == FALSE) {
122 exit( FALSE);
123 }
124
124 exit(TRUE); 125 exit(TRUE);
125} 126}
diff --git a/findutils/grep.c b/findutils/grep.c
index a495c62ae..44ca02834 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -22,6 +22,7 @@
22 */ 22 */
23 23
24#include "internal.h" 24#include "internal.h"
25#include "regexp.h"
25#include <stdio.h> 26#include <stdio.h>
26#include <dirent.h> 27#include <dirent.h>
27#include <errno.h> 28#include <errno.h>
@@ -30,44 +31,17 @@
30#include <time.h> 31#include <time.h>
31#include <ctype.h> 32#include <ctype.h>
32 33
33
34static const char grep_usage[] = 34static const char grep_usage[] =
35"grep [-ihn]... PATTERN [FILE]...\n" 35"grep [-ihn]... PATTERN [FILE]...\n"
36"Search for PATTERN in each FILE or standard input.\n\n" 36"Search for PATTERN in each FILE or standard input.\n\n"
37"\t-h\tsuppress the prefixing filename on output\n" 37"\t-h\tsuppress the prefixing filename on output\n"
38"\t-i\tignore case distinctions\n" 38"\t-i\tignore case distinctions\n"
39"\t-n\tprint line number with output lines\n\n" 39"\t-n\tprint line number with output lines\n\n"
40#if defined BB_REGEXP
41"This version of grep matches full regexps.\n";
42#else
40"This version of grep matches strings (not full regexps).\n"; 43"This version of grep matches strings (not full regexps).\n";
41 44#endif
42
43/*
44 * See if the specified needle is found in the specified haystack.
45 */
46static int search (const char *haystack, const char *needle, int ignoreCase)
47{
48
49 if (ignoreCase == FALSE) {
50 haystack = strstr (haystack, needle);
51 if (haystack == NULL)
52 return FALSE;
53 return TRUE;
54 } else {
55 int i;
56 char needle1[BUF_SIZE];
57 char haystack1[BUF_SIZE];
58
59 strncpy( haystack1, haystack, sizeof(haystack1));
60 strncpy( needle1, needle, sizeof(needle1));
61 for( i=0; i<sizeof(haystack1) && haystack1[i]; i++)
62 haystack1[i]=tolower( haystack1[i]);
63 for( i=0; i<sizeof(needle1) && needle1[i]; i++)
64 needle1[i]=tolower( needle1[i]);
65 haystack = strstr (haystack1, needle1);
66 if (haystack == NULL)
67 return FALSE;
68 return TRUE;
69 }
70}
71 45
72 46
73extern int grep_main (int argc, char **argv) 47extern int grep_main (int argc, char **argv)
@@ -80,7 +54,7 @@ extern int grep_main (int argc, char **argv)
80 int ignoreCase=FALSE; 54 int ignoreCase=FALSE;
81 int tellLine=FALSE; 55 int tellLine=FALSE;
82 long line; 56 long line;
83 char buf[BUF_SIZE]; 57 char haystack[BUF_SIZE];
84 58
85 ignoreCase = FALSE; 59 ignoreCase = FALSE;
86 tellLine = FALSE; 60 tellLine = FALSE;
@@ -128,21 +102,21 @@ extern int grep_main (int argc, char **argv)
128 102
129 line = 0; 103 line = 0;
130 104
131 while (fgets (buf, sizeof (buf), fp)) { 105 while (fgets (haystack, sizeof (haystack), fp)) {
132 line++; 106 line++;
133 cp = &buf[strlen (buf) - 1]; 107 cp = &haystack[strlen (haystack) - 1];
134 108
135 if (*cp != '\n') 109 if (*cp != '\n')
136 fprintf (stderr, "%s: Line too long\n", name); 110 fprintf (stderr, "%s: Line too long\n", name);
137 111
138 if (search (buf, needle, ignoreCase)==TRUE) { 112 if (find_match(haystack, needle, ignoreCase) == TRUE) {
139 if (tellName==TRUE) 113 if (tellName==TRUE)
140 printf ("%s: ", name); 114 printf ("%s: ", name);
141 115
142 if (tellLine==TRUE) 116 if (tellLine==TRUE)
143 printf ("%ld: ", line); 117 printf ("%ld: ", line);
144 118
145 fputs (buf, stdout); 119 fputs (haystack, stdout);
146 } 120 }
147 } 121 }
148 122
diff --git a/grep.c b/grep.c
index a495c62ae..44ca02834 100644
--- a/grep.c
+++ b/grep.c
@@ -22,6 +22,7 @@
22 */ 22 */
23 23
24#include "internal.h" 24#include "internal.h"
25#include "regexp.h"
25#include <stdio.h> 26#include <stdio.h>
26#include <dirent.h> 27#include <dirent.h>
27#include <errno.h> 28#include <errno.h>
@@ -30,44 +31,17 @@
30#include <time.h> 31#include <time.h>
31#include <ctype.h> 32#include <ctype.h>
32 33
33
34static const char grep_usage[] = 34static const char grep_usage[] =
35"grep [-ihn]... PATTERN [FILE]...\n" 35"grep [-ihn]... PATTERN [FILE]...\n"
36"Search for PATTERN in each FILE or standard input.\n\n" 36"Search for PATTERN in each FILE or standard input.\n\n"
37"\t-h\tsuppress the prefixing filename on output\n" 37"\t-h\tsuppress the prefixing filename on output\n"
38"\t-i\tignore case distinctions\n" 38"\t-i\tignore case distinctions\n"
39"\t-n\tprint line number with output lines\n\n" 39"\t-n\tprint line number with output lines\n\n"
40#if defined BB_REGEXP
41"This version of grep matches full regexps.\n";
42#else
40"This version of grep matches strings (not full regexps).\n"; 43"This version of grep matches strings (not full regexps).\n";
41 44#endif
42
43/*
44 * See if the specified needle is found in the specified haystack.
45 */
46static int search (const char *haystack, const char *needle, int ignoreCase)
47{
48
49 if (ignoreCase == FALSE) {
50 haystack = strstr (haystack, needle);
51 if (haystack == NULL)
52 return FALSE;
53 return TRUE;
54 } else {
55 int i;
56 char needle1[BUF_SIZE];
57 char haystack1[BUF_SIZE];
58
59 strncpy( haystack1, haystack, sizeof(haystack1));
60 strncpy( needle1, needle, sizeof(needle1));
61 for( i=0; i<sizeof(haystack1) && haystack1[i]; i++)
62 haystack1[i]=tolower( haystack1[i]);
63 for( i=0; i<sizeof(needle1) && needle1[i]; i++)
64 needle1[i]=tolower( needle1[i]);
65 haystack = strstr (haystack1, needle1);
66 if (haystack == NULL)
67 return FALSE;
68 return TRUE;
69 }
70}
71 45
72 46
73extern int grep_main (int argc, char **argv) 47extern int grep_main (int argc, char **argv)
@@ -80,7 +54,7 @@ extern int grep_main (int argc, char **argv)
80 int ignoreCase=FALSE; 54 int ignoreCase=FALSE;
81 int tellLine=FALSE; 55 int tellLine=FALSE;
82 long line; 56 long line;
83 char buf[BUF_SIZE]; 57 char haystack[BUF_SIZE];
84 58
85 ignoreCase = FALSE; 59 ignoreCase = FALSE;
86 tellLine = FALSE; 60 tellLine = FALSE;
@@ -128,21 +102,21 @@ extern int grep_main (int argc, char **argv)
128 102
129 line = 0; 103 line = 0;
130 104
131 while (fgets (buf, sizeof (buf), fp)) { 105 while (fgets (haystack, sizeof (haystack), fp)) {
132 line++; 106 line++;
133 cp = &buf[strlen (buf) - 1]; 107 cp = &haystack[strlen (haystack) - 1];
134 108
135 if (*cp != '\n') 109 if (*cp != '\n')
136 fprintf (stderr, "%s: Line too long\n", name); 110 fprintf (stderr, "%s: Line too long\n", name);
137 111
138 if (search (buf, needle, ignoreCase)==TRUE) { 112 if (find_match(haystack, needle, ignoreCase) == TRUE) {
139 if (tellName==TRUE) 113 if (tellName==TRUE)
140 printf ("%s: ", name); 114 printf ("%s: ", name);
141 115
142 if (tellLine==TRUE) 116 if (tellLine==TRUE)
143 printf ("%ld: ", line); 117 printf ("%ld: ", line);
144 118
145 fputs (buf, stdout); 119 fputs (haystack, stdout);
146 } 120 }
147 } 121 }
148 122
diff --git a/internal.h b/internal.h
index d23dca31e..cc7bfca11 100644
--- a/internal.h
+++ b/internal.h
@@ -130,7 +130,6 @@ int fullRead(int fd, char *buf, int len);
130int recursiveAction(const char *fileName, int recurse, int followLinks, int delayDirAction, 130int recursiveAction(const char *fileName, int recurse, int followLinks, int delayDirAction,
131 int (*fileAction) (const char *fileName, struct stat* statbuf), 131 int (*fileAction) (const char *fileName, struct stat* statbuf),
132 int (*dirAction) (const char *fileName, struct stat* statbuf)); 132 int (*dirAction) (const char *fileName, struct stat* statbuf));
133int match(const char* text, const char * pattern);
134const char* timeString(time_t timeVal); 133const char* timeString(time_t timeVal);
135 134
136extern void createPath (const char *name, int mode); 135extern void createPath (const char *name, int mode);
@@ -166,8 +165,9 @@ static inline int clrbit(char * addr,unsigned int nr)
166 return __res != 0; 165 return __res != 0;
167} 166}
168 167
169#endif 168#endif /* inline bitops junk */
170 169
171 170
172#endif 171
172#endif /* _INTERNAL_H_ */
173 173
diff --git a/regexp.c b/regexp.c
new file mode 100644
index 000000000..6017d79b4
--- /dev/null
+++ b/regexp.c
@@ -0,0 +1,826 @@
1/* regexp.c */
2
3#include "internal.h"
4#include "regexp.h"
5#include <setjmp.h>
6#include <stdio.h>
7#include <ctype.h>
8
9
10#if ( defined BB_GREP || defined BB_FIND )
11
12/* This also tries to find a needle in a haystack, but uses
13 * real regular expressions.... The fake regular expression
14 * version of find_match lives in utility.c. Using this version
15 * will add 3.9k to busybox...
16 * -Erik Andersen
17 */
18extern int find_match(char *haystack, char *needle, int ignoreCase)
19{
20 int status;
21 struct regexp* re;
22 re = regcomp( needle);
23 status = regexec(re, haystack, FALSE, ignoreCase);
24 free( re);
25 return( status);
26}
27
28
29/* code swiped from elvis-tiny 1.4 (a clone of vi) and adjusted to
30 * suit the needs of busybox by Erik Andersen.
31 *
32 * From the README:
33 * "Elvis is freely redistributable, in either source form or executable form.
34 * There are no restrictions on how you may use it".
35 * Elvis was written by Steve Kirkendall <kirkenda@cs.pdx.edu>
36 *
37 *
38 * This file contains the code that compiles regular expressions and executes
39 * them. It supports the same syntax and features as vi's regular expression
40 * code. Specifically, the meta characters are:
41 * ^ matches the beginning of a line
42 * $ matches the end of a line
43 * \< matches the beginning of a word
44 * \> matches the end of a word
45 * . matches any single character
46 * [] matches any character in a character class
47 * \( delimits the start of a subexpression
48 * \) delimits the end of a subexpression
49 * * repeats the preceding 0 or more times
50 * NOTE: You cannot follow a \) with a *.
51 *
52 * The physical structure of a compiled RE is as follows:
53 * - First, there is a one-byte value that says how many character classes
54 * are used in this regular expression
55 * - Next, each character class is stored as a bitmap that is 256 bits
56 * (32 bytes) long.
57 * - A mixture of literal characters and compiled meta characters follows.
58 * This begins with M_BEGIN(0) and ends with M_END(0). All meta chars
59 * are stored as a \n followed by a one-byte code, so they take up two
60 * bytes apiece. Literal characters take up one byte apiece. \n can't
61 * be used as a literal character.
62 *
63 */
64
65
66
67static char *previous; /* the previous regexp, used when null regexp is given */
68static char *previous1; /* a copy of the text from the previous substitution for regsub()*/
69
70
71/* These are used to classify or recognize meta-characters */
72#define META '\0'
73#define BASE_META(m) ((m) - 256)
74#define INT_META(c) ((c) + 256)
75#define IS_META(m) ((m) >= 256)
76#define IS_CLASS(m) ((m) >= M_CLASS(0) && (m) <= M_CLASS(9))
77#define IS_START(m) ((m) >= M_START(0) && (m) <= M_START(9))
78#define IS_END(m) ((m) >= M_END(0) && (m) <= M_END(9))
79#define IS_CLOSURE(m) ((m) >= M_SPLAT && (m) <= M_QMARK)
80#define ADD_META(s,m) (*(s)++ = META, *(s)++ = BASE_META(m))
81#define GET_META(s) (*(s) == META ? INT_META(*++(s)) : *s)
82
83/* These are the internal codes used for each type of meta-character */
84#define M_BEGLINE 256 /* internal code for ^ */
85#define M_ENDLINE 257 /* internal code for $ */
86#define M_BEGWORD 258 /* internal code for \< */
87#define M_ENDWORD 259 /* internal code for \> */
88#define M_ANY 260 /* internal code for . */
89#define M_SPLAT 261 /* internal code for * */
90#define M_PLUS 262 /* internal code for \+ */
91#define M_QMARK 263 /* internal code for \? */
92#define M_CLASS(n) (264+(n)) /* internal code for [] */
93#define M_START(n) (274+(n)) /* internal code for \( */
94#define M_END(n) (284+(n)) /* internal code for \) */
95
96/* These are used during compilation */
97static int class_cnt; /* used to assign class IDs */
98static int start_cnt; /* used to assign start IDs */
99static int end_stk[NSUBEXP];/* used to assign end IDs */
100static int end_sp;
101static char *retext; /* points to the text being compiled */
102
103/* error-handling stuff */
104jmp_buf errorhandler;
105#define FAIL(why) fprintf(stderr, why); longjmp(errorhandler, 1)
106
107
108
109
110/* This function builds a bitmap for a particular class */
111/* text -- start of the class */
112/* bmap -- the bitmap */
113static char *makeclass(char* text, char* bmap)
114{
115 int i;
116 int complement = 0;
117
118
119 /* zero the bitmap */
120 for (i = 0; bmap && i < 32; i++)
121 {
122 bmap[i] = 0;
123 }
124
125 /* see if we're going to complement this class */
126 if (*text == '^')
127 {
128 text++;
129 complement = 1;
130 }
131
132 /* add in the characters */
133 while (*text && *text != ']')
134 {
135 /* is this a span of characters? */
136 if (text[1] == '-' && text[2])
137 {
138 /* spans can't be backwards */
139 if (text[0] > text[2])
140 {
141 FAIL("Backwards span in []");
142 }
143
144 /* add each character in the span to the bitmap */
145 for (i = text[0]; bmap && i <= text[2]; i++)
146 {
147 bmap[i >> 3] |= (1 << (i & 7));
148 }
149
150 /* move past this span */
151 text += 3;
152 }
153 else
154 {
155 /* add this single character to the span */
156 i = *text++;
157 if (bmap)
158 {
159 bmap[i >> 3] |= (1 << (i & 7));
160 }
161 }
162 }
163
164 /* make sure the closing ] is missing */
165 if (*text++ != ']')
166 {
167 FAIL("] missing");
168 }
169
170 /* if we're supposed to complement this class, then do so */
171 if (complement && bmap)
172 {
173 for (i = 0; i < 32; i++)
174 {
175 bmap[i] = ~bmap[i];
176 }
177 }
178
179 return text;
180}
181
182
183
184
185/* This function gets the next character or meta character from a string.
186 * The pointer is incremented by 1, or by 2 for \-quoted characters. For [],
187 * a bitmap is generated via makeclass() (if re is given), and the
188 * character-class text is skipped.
189 */
190static int gettoken(sptr, re)
191 char **sptr;
192 regexp *re;
193{
194 int c;
195
196 c = **sptr;
197 ++*sptr;
198 if (c == '\\')
199 {
200 c = **sptr;
201 ++*sptr;
202 switch (c)
203 {
204 case '<':
205 return M_BEGWORD;
206
207 case '>':
208 return M_ENDWORD;
209
210 case '(':
211 if (start_cnt >= NSUBEXP)
212 {
213 FAIL("Too many \\(s");
214 }
215 end_stk[end_sp++] = start_cnt;
216 return M_START(start_cnt++);
217
218 case ')':
219 if (end_sp <= 0)
220 {
221 FAIL("Mismatched \\)");
222 }
223 return M_END(end_stk[--end_sp]);
224
225 case '*':
226 return M_SPLAT;
227
228 case '.':
229 return M_ANY;
230
231 case '+':
232 return M_PLUS;
233
234 case '?':
235 return M_QMARK;
236
237 default:
238 return c;
239 }
240 }
241 else {
242 switch (c)
243 {
244 case '^':
245 if (*sptr == retext + 1)
246 {
247 return M_BEGLINE;
248 }
249 return c;
250
251 case '$':
252 if (!**sptr)
253 {
254 return M_ENDLINE;
255 }
256 return c;
257
258 case '.':
259 return M_ANY;
260
261 case '*':
262 return M_SPLAT;
263
264 case '[':
265 /* make sure we don't have too many classes */
266 if (class_cnt >= 10)
267 {
268 FAIL("Too many []s");
269 }
270
271 /* process the character list for this class */
272 if (re)
273 {
274 /* generate the bitmap for this class */
275 *sptr = makeclass(*sptr, re->program + 1 + 32 * class_cnt);
276 }
277 else
278 {
279 /* skip to end of the class */
280 *sptr = makeclass(*sptr, (char *)0);
281 }
282 return M_CLASS(class_cnt++);
283
284 default:
285 return c;
286 }
287 }
288 /*NOTREACHED*/
289}
290
291
292
293
294/* This function calculates the number of bytes that will be needed for a
295 * compiled RE. Its argument is the uncompiled version. It is not clever
296 * about catching syntax errors; that is done in a later pass.
297 */
298static unsigned calcsize(text)
299 char *text;
300{
301 unsigned size;
302 int token;
303
304 retext = text;
305 class_cnt = 0;
306 start_cnt = 1;
307 end_sp = 0;
308 size = 5;
309 while ((token = gettoken(&text, (regexp *)0)) != 0)
310 {
311 if (IS_CLASS(token))
312 {
313 size += 34;
314 }
315 else if (IS_META(token))
316 {
317 size += 2;
318 }
319 else
320 {
321 size++;
322 }
323 }
324
325 return size;
326}
327
328
329
330/*---------------------------------------------------------------------------*/
331
332
333/* This function checks for a match between a character and a token which is
334 * known to represent a single character. It returns 0 if they match, or
335 * 1 if they don't.
336 */
337static int match1(regexp* re, char ch, int token, int ignoreCase)
338{
339 if (!ch)
340 {
341 /* the end of a line can't match any RE of width 1 */
342 return 1;
343 }
344 if (token == M_ANY)
345 {
346 return 0;
347 }
348 else if (IS_CLASS(token))
349 {
350 if (re->program[1 + 32 * (token - M_CLASS(0)) + (ch >> 3)] & (1 << (ch & 7)))
351 return 0;
352 }
353 else if (ch == token
354 || (ignoreCase==TRUE && isupper(ch) && tolower(ch) == token))
355 {
356 return 0;
357 }
358 return 1;
359}
360
361
362
363/* This function checks characters up to and including the next closure, at
364 * which point it does a recursive call to check the rest of it. This function
365 * returns 0 if everything matches, or 1 if something doesn't match.
366 */
367/* re -- the regular expression */
368/* str -- the string */
369/* prog -- a portion of re->program, an compiled RE */
370/* here -- a portion of str, the string to compare it to */
371static int match(regexp* re, char* str, char* prog, char* here, int ignoreCase)
372{
373 int token;
374 int nmatched;
375 int closure;
376
377 for (token = GET_META(prog); !IS_CLOSURE(token); prog++, token = GET_META(prog))
378 {
379 switch (token)
380 {
381 /*case M_BEGLINE: can't happen; re->bol is used instead */
382 case M_ENDLINE:
383 if (*here)
384 return 1;
385 break;
386
387 case M_BEGWORD:
388 if (here != str &&
389 (here[-1] == '_' ||
390 (isascii(here[-1]) && isalnum(here[-1]))))
391 return 1;
392 break;
393
394 case M_ENDWORD:
395 if ((here[0] == '_' || isascii(here[0])) && isalnum(here[0]))
396 return 1;
397 break;
398
399 case M_START(0):
400 case M_START(1):
401 case M_START(2):
402 case M_START(3):
403 case M_START(4):
404 case M_START(5):
405 case M_START(6):
406 case M_START(7):
407 case M_START(8):
408 case M_START(9):
409 re->startp[token - M_START(0)] = (char *)here;
410 break;
411
412 case M_END(0):
413 case M_END(1):
414 case M_END(2):
415 case M_END(3):
416 case M_END(4):
417 case M_END(5):
418 case M_END(6):
419 case M_END(7):
420 case M_END(8):
421 case M_END(9):
422 re->endp[token - M_END(0)] = (char *)here;
423 if (token == M_END(0))
424 {
425 return 0;
426 }
427 break;
428
429 default: /* literal, M_CLASS(n), or M_ANY */
430 if (match1(re, *here, token, ignoreCase) != 0)
431 return 1;
432 here++;
433 }
434 }
435
436 /* C L O S U R E */
437
438 /* step 1: see what we have to match against, and move "prog" to point
439 * the the remainder of the compiled RE.
440 */
441 closure = token;
442 prog++, token = GET_META(prog);
443 prog++;
444
445 /* step 2: see how many times we can match that token against the string */
446 for (nmatched = 0;
447 (closure != M_QMARK || nmatched < 1) && *here && match1(re, *here, token, ignoreCase) == 0;
448 nmatched++, here++)
449 {
450 }
451
452 /* step 3: try to match the remainder, and back off if it doesn't */
453 while (nmatched >= 0 && match(re, str, prog, here, ignoreCase) != 0)
454 {
455 nmatched--;
456 here--;
457 }
458
459 /* so how did it work out? */
460 if (nmatched >= ((closure == M_PLUS) ? 1 : 0))
461 return 0;
462 return 1;
463}
464
465
466/* This function compiles a regexp. */
467extern regexp *regcomp(char* text)
468{
469 int needfirst;
470 unsigned size;
471 int token;
472 int peek;
473 char *build;
474 regexp *re;
475
476
477 /* prepare for error handling */
478 re = (regexp *)0;
479 if (setjmp(errorhandler))
480 {
481 if (re)
482 {
483 free(re);
484 }
485 return (regexp *)0;
486 }
487
488 /* if an empty regexp string was given, use the previous one */
489 if (*text == 0)
490 {
491 if (!previous)
492 {
493 FAIL("No previous RE");
494 }
495 text = previous;
496 }
497 else /* non-empty regexp given, so remember it */
498 {
499 if (previous)
500 free(previous);
501 previous = (char *)malloc((unsigned)(strlen(text) + 1));
502 if (previous)
503 strcpy(previous, text);
504 }
505
506 /* allocate memory */
507 class_cnt = 0;
508 start_cnt = 1;
509 end_sp = 0;
510 retext = text;
511 size = calcsize(text) + sizeof(regexp);
512 re = (regexp *)malloc((unsigned)size);
513
514 if (!re)
515 {
516 FAIL("Not enough memory for this RE");
517 }
518
519 /* compile it */
520 build = &re->program[1 + 32 * class_cnt];
521 re->program[0] = class_cnt;
522 for (token = 0; token < NSUBEXP; token++)
523 {
524 re->startp[token] = re->endp[token] = (char *)0;
525 }
526 re->first = 0;
527 re->bol = 0;
528 re->minlen = 0;
529 needfirst = 1;
530 class_cnt = 0;
531 start_cnt = 1;
532 end_sp = 0;
533 retext = text;
534 for (token = M_START(0), peek = gettoken(&text, re);
535 token;
536 token = peek, peek = gettoken(&text, re))
537 {
538 /* special processing for the closure operator */
539 if (IS_CLOSURE(peek))
540 {
541 /* detect misuse of closure operator */
542 if (IS_START(token))
543 {
544 FAIL("* or \\+ or \\? follows nothing");
545 }
546 else if (IS_META(token) && token != M_ANY && !IS_CLASS(token))
547 {
548 FAIL("* or \\+ or \\? can only follow a normal character or . or []");
549 }
550
551 /* it is okay -- make it prefix instead of postfix */
552 ADD_META(build, peek);
553
554 /* take care of "needfirst" - is this the first char? */
555 if (needfirst && peek == M_PLUS && !IS_META(token))
556 {
557 re->first = token;
558 }
559 needfirst = 0;
560
561 /* we used "peek" -- need to refill it */
562 peek = gettoken(&text, re);
563 if (IS_CLOSURE(peek))
564 {
565 FAIL("* or \\+ or \\? doubled up");
566 }
567 }
568 else if (!IS_META(token))
569 {
570 /* normal char is NOT argument of closure */
571 if (needfirst)
572 {
573 re->first = token;
574 needfirst = 0;
575 }
576 re->minlen++;
577 }
578 else if (token == M_ANY || IS_CLASS(token))
579 {
580 /* . or [] is NOT argument of closure */
581 needfirst = 0;
582 re->minlen++;
583 }
584
585 /* the "token" character is not closure -- process it normally */
586 if (token == M_BEGLINE)
587 {
588 /* set the BOL flag instead of storing M_BEGLINE */
589 re->bol = 1;
590 }
591 else if (IS_META(token))
592 {
593 ADD_META(build, token);
594 }
595 else
596 {
597 *build++ = token;
598 }
599 }
600
601 /* end it with a \) which MUST MATCH the opening \( */
602 ADD_META(build, M_END(0));
603 if (end_sp > 0)
604 {
605 FAIL("Not enough \\)s");
606 }
607
608 return re;
609}
610
611
612
613
614/* This function searches through a string for text that matches an RE. */
615/* re -- the compiled regexp to search for */
616/* str -- the string to search through */
617/* bol -- does str start at the beginning of a line? (boolean) */
618/* ignoreCase -- ignoreCase or not */
619extern int regexec(struct regexp* re, char* str, int bol, int ignoreCase)
620{
621 char *prog; /* the entry point of re->program */
622 int len; /* length of the string */
623 char *here;
624
625 /* if must start at the beginning of a line, and this isn't, then fail */
626 if (re->bol && bol==TRUE)
627 {
628 return FALSE;
629 }
630
631 len = strlen(str);
632 prog = re->program + 1 + 32 * re->program[0];
633
634 /* search for the RE in the string */
635 if (re->bol)
636 {
637 /* must occur at BOL */
638 if ((re->first
639 && match1(re, *(char *)str, re->first, ignoreCase))/* wrong first letter? */
640 || len < re->minlen /* not long enough? */
641 || match(re, (char *)str, prog, str, ignoreCase)) /* doesn't match? */
642 return FALSE; /* THEN FAIL! */
643 }
644 else if (ignoreCase == FALSE)
645 {
646 /* can occur anywhere in the line, noignorecase */
647 for (here = (char *)str;
648 (re->first && re->first != *here)
649 || match(re, (char *)str, prog, here, ignoreCase);
650 here++, len--)
651 {
652 if (len < re->minlen)
653 return FALSE;
654 }
655 }
656 else
657 {
658 /* can occur anywhere in the line, ignorecase */
659 for (here = (char *)str;
660 (re->first && match1(re, *here, (int)re->first, ignoreCase))
661 || match(re, (char *)str, prog, here, ignoreCase);
662 here++, len--)
663 {
664 if (len < re->minlen)
665 return FALSE;
666 }
667 }
668
669 /* if we didn't fail, then we must have succeeded */
670 return TRUE;
671}
672
673
674
675
676
677/* This performs substitutions after a regexp match has been found. */
678extern void regsub(regexp* re, char* src, char* dst)
679{
680 char *cpy;
681 char *end;
682 char c;
683 char *start;
684 int mod;
685
686 mod = 0;
687
688 start = src;
689 while ((c = *src++) != '\0')
690 {
691 /* recognize any meta characters */
692 if (c == '&')
693 {
694 cpy = re->startp[0];
695 end = re->endp[0];
696 }
697 else if (c == '~')
698 {
699 cpy = previous1;
700 if (cpy)
701 end = cpy + strlen(cpy);
702 }
703 else
704 if (c == '\\')
705 {
706 c = *src++;
707 switch (c)
708 {
709 case '0':
710 case '1':
711 case '2':
712 case '3':
713 case '4':
714 case '5':
715 case '6':
716 case '7':
717 case '8':
718 case '9':
719 /* \0 thru \9 mean "copy subexpression" */
720 c -= '0';
721 cpy = re->startp[(int)c];
722 end = re->endp[(int)c];
723 break;
724 case 'U':
725 case 'u':
726 case 'L':
727 case 'l':
728 /* \U and \L mean "convert to upper/lowercase" */
729 mod = c;
730 continue;
731
732 case 'E':
733 case 'e':
734 /* \E ends the \U or \L */
735 mod = 0;
736 continue;
737 case '&':
738 /* "\&" means "original text" */
739 *dst++ = c;
740 continue;
741
742 case '~':
743 /* "\~" means "previous text, if any" */
744 *dst++ = c;
745 continue;
746 default:
747 /* ordinary char preceded by backslash */
748 *dst++ = c;
749 continue;
750 }
751 }
752 else
753 {
754 /* ordinary character, so just copy it */
755 *dst++ = c;
756 continue;
757 }
758
759 /* Note: to reach this point in the code, we must have evaded
760 * all "continue" statements. To do that, we must have hit
761 * a metacharacter that involves copying.
762 */
763
764 /* if there is nothing to copy, loop */
765 if (!cpy)
766 continue;
767
768 /* copy over a portion of the original */
769 while (cpy < end)
770 {
771 switch (mod)
772 {
773 case 'U':
774 case 'u':
775 /* convert to uppercase */
776 if (isascii(*cpy) && islower(*cpy))
777 {
778 *dst++ = toupper(*cpy);
779 cpy++;
780 }
781 else
782 {
783 *dst++ = *cpy++;
784 }
785 break;
786
787 case 'L':
788 case 'l':
789 /* convert to lowercase */
790 if (isascii(*cpy) && isupper(*cpy))
791 {
792 *dst++ = tolower(*cpy);
793 cpy++;
794 }
795 else
796 {
797 *dst++ = *cpy++;
798 }
799 break;
800
801 default:
802 /* copy without any conversion */
803 *dst++ = *cpy++;
804 }
805
806 /* \u and \l end automatically after the first char */
807 if (mod && (mod == 'u' || mod == 'l'))
808 {
809 mod = 0;
810 }
811 }
812 }
813 *dst = '\0';
814
815 /* remember what text we inserted this time */
816 if (previous1)
817 free(previous1);
818 previous1 = (char *)malloc((unsigned)(strlen(start) + 1));
819 if (previous1)
820 strcpy(previous1, start);
821}
822
823
824#endif /* BB_REGEXP */
825
826
diff --git a/smtpout b/smtpout
deleted file mode 100644
index 635a83c6f..000000000
--- a/smtpout
+++ /dev/null
@@ -1,2 +0,0 @@
1echo '.' >smtpout echo 'QUIT' >smtpout
2kjfjkjd
diff --git a/utility.c b/utility.c
index e188ecdcd..eb24de2e6 100644
--- a/utility.c
+++ b/utility.c
@@ -53,12 +53,17 @@ volatile void usage(const char *usage)
53int 53int
54get_kernel_revision() 54get_kernel_revision()
55{ 55{
56 FILE *f; 56 FILE *file;
57 int major=0, minor=0, patch=0; 57 int major=0, minor=0, patch=0;
58 58 char* filename="/proc/sys/kernel/osrelease";
59 f = fopen("/proc/sys/kernel/osrelease","r"); 59
60 fscanf(f,"%d.%d.%d",&major,&minor,&patch); 60 file = fopen(filename,"r");
61 fclose(f); 61 if (file == NULL) {
62 perror(filename);
63 return( 0);
64 }
65 fscanf(file,"%d.%d.%d",&major,&minor,&patch);
66 fclose(file);
62 return major*65536 + minor*256 + patch; 67 return major*65536 + minor*256 + patch;
63} 68}
64 69
@@ -312,94 +317,6 @@ const char *timeString(time_t timeVal)
312 317
313 318
314/* 319/*
315 * Routine to see if a text string is matched by a wildcard pattern.
316 * Returns TRUE if the text is matched, or FALSE if it is not matched
317 * or if the pattern is invalid.
318 * * matches zero or more characters
319 * ? matches a single character
320 * [abc] matches 'a', 'b' or 'c'
321 * \c quotes character c
322 * Adapted from code written by Ingo Wilken.
323 */
324int match(const char *text, const char *pattern)
325{
326 const char *retryPat;
327 const char *retryText;
328 int ch;
329 int found;
330
331 retryPat = NULL;
332 retryText = NULL;
333
334 while (*text || *pattern) {
335 ch = *pattern++;
336
337 switch (ch) {
338 case '*':
339 retryPat = pattern;
340 retryText = text;
341 break;
342
343 case '[':
344 found = FALSE;
345
346 while ((ch = *pattern++) != ']') {
347 if (ch == '\\')
348 ch = *pattern++;
349
350 if (ch == '\0')
351 return FALSE;
352
353 if (*text == ch)
354 found = TRUE;
355 }
356
357 if (!found) {
358 pattern = retryPat;
359 text = ++retryText;
360 }
361
362 /* fall into next case */
363
364 case '?':
365 if (*text++ == '\0')
366 return FALSE;
367
368 break;
369
370 case '\\':
371 ch = *pattern++;
372
373 if (ch == '\0')
374 return FALSE;
375
376 /* fall into next case */
377
378 default:
379 if (*text == ch) {
380 if (*text)
381 text++;
382 break;
383 }
384
385 if (*text) {
386 pattern = retryPat;
387 text = ++retryText;
388 break;
389 }
390
391 return FALSE;
392 }
393
394 if (pattern == NULL)
395 return FALSE;
396 }
397
398 return TRUE;
399}
400
401
402/*
403 * Write all of the supplied buffer out to a file. 320 * Write all of the supplied buffer out to a file.
404 * This does multiple writes as necessary. 321 * This does multiple writes as necessary.
405 * Returns the amount written, or -1 on an error. 322 * Returns the amount written, or -1 on an error.
@@ -695,13 +612,17 @@ parse_mode( const char* s, mode_t* theMode)
695uid_t 612uid_t
696my_getid(const char *filename, char *name, uid_t id) 613my_getid(const char *filename, char *name, uid_t id)
697{ 614{
698 FILE *stream; 615 FILE *file;
699 char *rname, *start, *end, buf[128]; 616 char *rname, *start, *end, buf[128];
700 uid_t rid; 617 uid_t rid;
701 618
702 stream=fopen(filename,"r"); 619 file=fopen(filename,"r");
620 if (file == NULL) {
621 perror(filename);
622 return (-1);
623 }
703 624
704 while (fgets (buf, 128, stream) != NULL) { 625 while (fgets (buf, 128, file) != NULL) {
705 if (buf[0] == '#') 626 if (buf[0] == '#')
706 continue; 627 continue;
707 628
@@ -731,7 +652,7 @@ my_getid(const char *filename, char *name, uid_t id)
731 return( TRUE); 652 return( TRUE);
732 } 653 }
733 } 654 }
734 fclose(stream); 655 fclose(file);
735 return (-1); 656 return (-1);
736} 657}
737 658
@@ -763,4 +684,40 @@ my_getgrgid(char* group, gid_t gid)
763#endif 684#endif
764 685
765 686
687
688#if !defined BB_REGEXP && (defined BB_GREP || defined BB_FIND )
689/* This tries to find a needle in a haystack, but does so by
690 * only trying to match literal strings (look 'ma, no regexps!)
691 * This is short, sweet, and carries _very_ little baggage,
692 * unlike its beefier cousin a few lines down...
693 * -Erik Andersen
694 */
695extern int find_match(char *haystack, char *needle, int ignoreCase)
696{
697
698 if (ignoreCase == FALSE) {
699 haystack = strstr (haystack, needle);
700 if (haystack == NULL)
701 return FALSE;
702 return TRUE;
703 } else {
704 int i;
705 char needle1[BUF_SIZE];
706 char haystack1[BUF_SIZE];
707
708 strncpy( haystack1, haystack, sizeof(haystack1));
709 strncpy( needle1, needle, sizeof(needle1));
710 for( i=0; i<sizeof(haystack1) && haystack1[i]; i++)
711 haystack1[i]=tolower( haystack1[i]);
712 for( i=0; i<sizeof(needle1) && needle1[i]; i++)
713 needle1[i]=tolower( needle1[i]);
714 haystack = strstr (haystack1, needle1);
715 if (haystack == NULL)
716 return FALSE;
717 return TRUE;
718 }
719}
720#endif
721
766/* END CODE */ 722/* END CODE */
723