blob: 608f868130adefe7d30f0a7d9c714cca95891b7a [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersen6b6b3f61999-10-28 16:06:25 +00002/*
3 * Mini sed implementation for busybox
4 *
5 *
6 * Copyright (C) 1999 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8 *
Erik Andersen1266a131999-12-29 22:19:46 +00009 * Modifications for addresses and append command have been
10 * written by Marco Pantaleoni <panta@prosa.it>, <panta@elasticworld.org>
11 * and are:
12 * Copyright (C) 1999 Marco Pantaleoni.
13 *
Eric Andersen6b6b3f61999-10-28 16:06:25 +000014 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
29
30#include "internal.h"
31#include "regexp.h"
32#include <stdio.h>
33#include <dirent.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <signal.h>
37#include <time.h>
38#include <ctype.h>
39
Erik Andersen1266a131999-12-29 22:19:46 +000040static const char sed_usage[] =
Erik Andersene49d5ec2000-02-08 19:58:47 +000041 "sed [-n] -e script [file...]\n\n"
42 "Allowed sed scripts come in the following form:\n"
43 "\t'ADDR [!] COMMAND'\n\n"
44 "\twhere address ADDR can be:\n"
45 "\t NUMBER Match specified line number\n"
46 "\t $ Match last line\n"
47 "\t /REGEXP/ Match specified regexp\n"
48 "\t (! inverts the meaning of the match)\n\n"
49 "\tand COMMAND can be:\n"
50 "\t s/regexp/replacement/[igp]\n"
51 "\t which attempt to match regexp against the pattern space\n"
52 "\t and if successful replaces the matched portion with replacement.\n\n"
53 "\t aTEXT\n"
54 "\t which appends TEXT after the pattern space\n"
55 "Options:\n"
56 "-e\tadd the script to the commands to be executed\n"
57 "-n\tsuppress automatic printing of pattern space\n\n"
Eric Andersen6b6b3f61999-10-28 16:06:25 +000058#if defined BB_REGEXP
Erik Andersene49d5ec2000-02-08 19:58:47 +000059 "This version of sed matches full regular expresions.\n";
Eric Andersen6b6b3f61999-10-28 16:06:25 +000060#else
Erik Andersene49d5ec2000-02-08 19:58:47 +000061 "This version of sed matches strings (not full regular expresions).\n";
Eric Andersen6b6b3f61999-10-28 16:06:25 +000062#endif
63
Erik Andersen1266a131999-12-29 22:19:46 +000064/* Flags & variables */
65
66typedef enum { f_none, f_replace, f_append } sed_function;
67
68#define NO_LINE -2
69#define LAST_LINE -1
70static int addr_line = NO_LINE;
71static char *addr_pattern = NULL;
72static int negated = 0;
73
74#define SKIPSPACES(p) do { while (isspace(*(p))) (p)++; } while (0)
75
76#define BUFSIZE 1024
77
78static inline int at_last(FILE * fp)
Eric Andersen50d63601999-11-09 01:47:36 +000079{
Erik Andersene49d5ec2000-02-08 19:58:47 +000080 int res = 0;
Eric Andersen6b6b3f61999-10-28 16:06:25 +000081
Erik Andersene49d5ec2000-02-08 19:58:47 +000082 if (feof(fp))
83 return 1;
84 else {
Erik Andersen4d054312000-02-10 07:31:15 +000085 int ch;
Erik Andersene49d5ec2000-02-08 19:58:47 +000086
87 if ((ch = fgetc(fp)) == EOF)
88 res++;
89 ungetc(ch, fp);
90 }
91 return res;
Erik Andersen1266a131999-12-29 22:19:46 +000092}
93
94static void do_sed_repl(FILE * fp, char *needle, char *newNeedle,
Erik Andersene49d5ec2000-02-08 19:58:47 +000095 int ignoreCase, int printFlag, int quietFlag)
Erik Andersen1266a131999-12-29 22:19:46 +000096{
Erik Andersene49d5ec2000-02-08 19:58:47 +000097 int foundOne = FALSE;
98 char haystack[BUFSIZE];
99 int line = 1, doit;
Erik Andersen1266a131999-12-29 22:19:46 +0000100
Erik Andersene49d5ec2000-02-08 19:58:47 +0000101 while (fgets(haystack, BUFSIZE - 1, fp)) {
102 doit = 0;
103 if (addr_pattern) {
104 doit = !find_match(haystack, addr_pattern, FALSE);
105 } else if (addr_line == NO_LINE)
106 doit = 1;
107 else if (addr_line == LAST_LINE) {
108 if (at_last(fp))
109 doit = 1;
110 } else {
111 if (line == addr_line)
112 doit = 1;
113 }
114 if (negated)
115 doit = 1 - doit;
116 if (doit) {
117 foundOne =
118 replace_match(haystack, needle, newNeedle, ignoreCase);
119
120 if (foundOne == TRUE && printFlag == TRUE) {
121 fprintf(stdout, haystack);
122 }
123 }
124
125 if (quietFlag == FALSE) {
126 fprintf(stdout, haystack);
127 }
128
129 line++;
Erik Andersen1266a131999-12-29 22:19:46 +0000130 }
Eric Andersen50d63601999-11-09 01:47:36 +0000131}
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000132
Erik Andersen1266a131999-12-29 22:19:46 +0000133static void do_sed_append(FILE * fp, char *appendline, int quietFlag)
134{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000135 char buffer[BUFSIZE];
136 int line = 1, doit;
Erik Andersen1266a131999-12-29 22:19:46 +0000137
Erik Andersene49d5ec2000-02-08 19:58:47 +0000138 while (fgets(buffer, BUFSIZE - 1, fp)) {
139 doit = 0;
140 if (addr_pattern) {
141 doit = !find_match(buffer, addr_pattern, FALSE);
142 } else if (addr_line == NO_LINE)
143 doit = 1;
144 else if (addr_line == LAST_LINE) {
145 if (at_last(fp))
146 doit = 1;
147 } else {
148 if (line == addr_line)
149 doit = 1;
150 }
151 if (negated)
152 doit = 1 - doit;
153 if (quietFlag == FALSE) {
154 fprintf(stdout, buffer);
155 }
156 if (doit) {
157 fputs(appendline, stdout);
158 fputc('\n', stdout);
159 }
Erik Andersen1266a131999-12-29 22:19:46 +0000160
Erik Andersene49d5ec2000-02-08 19:58:47 +0000161 line++;
162 }
Erik Andersen1266a131999-12-29 22:19:46 +0000163}
164
165extern int sed_main(int argc, char **argv)
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000166{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000167 FILE *fp;
168 char *needle = NULL, *newNeedle = NULL;
169 char *name;
170 char *cp;
171 int ignoreCase = FALSE;
172 int printFlag = FALSE;
173 int quietFlag = FALSE;
174 int stopNow;
175 char *line_s = NULL, saved;
176 char *appendline = NULL;
177 char *pos;
178 sed_function sed_f = f_none;
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000179
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000180 argc--;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000181 argv++;
182 if (argc < 1) {
Eric Andersenc1525e81999-10-29 00:07:31 +0000183 usage(sed_usage);
Eric Andersen50d63601999-11-09 01:47:36 +0000184 }
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000185
Erik Andersen4d054312000-02-10 07:31:15 +0000186 while (argc > 1) {
187 if (**argv == '-') {
188 argc--;
189 cp = *argv++;
190 stopNow = FALSE;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000191
Erik Andersen4d054312000-02-10 07:31:15 +0000192 while (*++cp && stopNow == FALSE) {
193 switch (*cp) {
194 case 'n':
195 quietFlag = TRUE;
196 break;
197 case 'e':
198 if (*(cp + 1) == 0 && --argc < 0) {
199 usage(sed_usage);
200 }
201 if (*++cp != 's')
202 cp = *argv++;
203
204 /* Read address if present */
205 SKIPSPACES(cp);
206 if (*cp == '$') {
207 addr_line = LAST_LINE;
208 cp++;
209 } else {
210 if (isdigit(*cp)) { /* LINE ADDRESS */
211 line_s = cp;
212 while (isdigit(*cp))
213 cp++;
214 if (cp > line_s) {
215 /* numeric line */
216 saved = *cp;
217 *cp = '\0';
218 addr_line = atoi(line_s);
219 *cp = saved;
220 }
221 } else if (*cp == '/') { /* PATTERN ADDRESS */
222 pos = addr_pattern = cp + 1;
223 pos = strchr(pos, '/');
224 if (!pos)
225 usage(sed_usage);
226 *pos = '\0';
227 cp = pos + 1;
228 }
229 }
230
231 SKIPSPACES(cp);
232 if (*cp == '!') {
233 negated++;
234 cp++;
235 }
236
237 /* Read command */
238
239 SKIPSPACES(cp);
240 switch (*cp) {
241 case 's': /* REPLACE */
242 if (strlen(cp) <= 3 || *(cp + 1) != '/')
243 break;
244 sed_f = f_replace;
245
246 pos = needle = cp + 2;
247
248 for (;;) {
249 pos = strchr(pos, '/');
250 if (pos == NULL) {
251 usage(sed_usage);
252 }
253 if (*(pos - 1) == '\\') {
254 pos++;
255 continue;
256 }
257 break;
258 }
259 *pos = 0;
260 newNeedle = ++pos;
261 for (;;) {
262 pos = strchr(pos, '/');
263 if (pos == NULL) {
264 usage(sed_usage);
265 }
266 if (*(pos - 1) == '\\') {
267 pos++;
268 continue;
269 }
270 break;
271 }
272 *pos = 0;
273 if (pos + 2 != 0) {
274 while (*++pos) {
275 switch (*pos) {
276 case 'i':
277 ignoreCase = TRUE;
278 break;
279 case 'p':
280 printFlag = TRUE;
281 break;
282 case 'g':
283 break;
284 default:
285 usage(sed_usage);
286 }
287 }
288 }
289 cp = pos;
290 /* fprintf(stderr, "replace '%s' with '%s'\n", needle, newNeedle); */
291 break;
292
293 case 'a': /* APPEND */
294 if (strlen(cp) < 2)
295 break;
296 sed_f = f_append;
297 appendline = ++cp;
298 /* fprintf(stderr, "append '%s'\n", appendline); */
299 break;
300 }
301
302 stopNow = TRUE;
303 break;
304
305 default:
306 usage(sed_usage);
307 }
308 }
309 }
310 }
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000311
Erik Andersene49d5ec2000-02-08 19:58:47 +0000312 if (argc == 0) {
313 switch (sed_f) {
314 case f_none:
315 break;
316 case f_replace:
317 do_sed_repl(stdin, needle, newNeedle, ignoreCase, printFlag,
318 quietFlag);
319 break;
320 case f_append:
321 do_sed_append(stdin, appendline, quietFlag);
322 break;
323 }
324 } else {
325 while (argc-- > 0) {
326 name = *argv++;
Eric Andersen50d63601999-11-09 01:47:36 +0000327
Erik Andersene49d5ec2000-02-08 19:58:47 +0000328 fp = fopen(name, "r");
329 if (fp == NULL) {
330 perror(name);
331 continue;
332 }
Eric Andersen50d63601999-11-09 01:47:36 +0000333
Erik Andersene49d5ec2000-02-08 19:58:47 +0000334 switch (sed_f) {
335 case f_none:
336 break;
337 case f_replace:
338 do_sed_repl(fp, needle, newNeedle, ignoreCase, printFlag,
339 quietFlag);
340 break;
341 case f_append:
342 do_sed_append(fp, appendline, quietFlag);
343 break;
344 }
Eric Andersen50d63601999-11-09 01:47:36 +0000345
Erik Andersene49d5ec2000-02-08 19:58:47 +0000346 if (ferror(fp))
347 perror(name);
348
349 fclose(fp);
350 }
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000351 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000352 exit(TRUE);
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000353}
354
355
356/* END CODE */