blob: 25777243d9994f7a25fde185e7867e5385649d73 [file] [log] [blame]
Eric Andersen6b6b3f61999-10-28 16:06:25 +00001/*
2 * Mini sed implementation for busybox
3 *
4 *
5 * Copyright (C) 1999 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
Erik Andersen1266a131999-12-29 22:19:46 +00008 * Modifications for addresses and append command have been
9 * written by Marco Pantaleoni <panta@prosa.it>, <panta@elasticworld.org>
10 * and are:
11 * Copyright (C) 1999 Marco Pantaleoni.
12 *
Eric Andersen6b6b3f61999-10-28 16:06:25 +000013 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 *
27 */
28
29#include "internal.h"
30#include "regexp.h"
31#include <stdio.h>
32#include <dirent.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <signal.h>
36#include <time.h>
37#include <ctype.h>
38
Erik Andersen1266a131999-12-29 22:19:46 +000039static const char sed_usage[] =
40 "sed [-n] -e script [file...]\n\n"
41 "Allowed sed scripts come in the following form:\n"
42 "\t'ADDR [!] COMMAND'\n\n"
43 "\twhere address ADDR can be:\n"
44 "\t NUMBER Match specified line number\n"
45 "\t $ Match last line\n"
46 "\t /REGEXP/ Match specified regexp\n"
47 "\t (! inverts the meaning of the match)\n\n"
48 "\tand COMMAND can be:\n"
Erik Andersen7dc16072000-01-04 01:10:25 +000049 "\t s/regexp/replacement/[igp]\n"
Erik Andersen1266a131999-12-29 22:19:46 +000050 "\t which attempt to match regexp against the pattern space\n"
51 "\t and if successful replaces the matched portion with replacement.\n\n"
52 "\t aTEXT\n"
53 "\t which appends TEXT after the pattern space\n"
54 "Options:\n"
55 "-e\tadd the script to the commands to be executed\n"
56 "-n\tsuppress automatic printing of pattern space\n\n"
Eric Andersen6b6b3f61999-10-28 16:06:25 +000057#if defined BB_REGEXP
Erik Andersen1266a131999-12-29 22:19:46 +000058 "This version of sed matches full regular expresions.\n";
Eric Andersen6b6b3f61999-10-28 16:06:25 +000059#else
Erik Andersen1266a131999-12-29 22:19:46 +000060 "This version of sed matches strings (not full regular expresions).\n";
Eric Andersen6b6b3f61999-10-28 16:06:25 +000061#endif
62
Erik Andersen1266a131999-12-29 22:19:46 +000063/* Flags & variables */
64
65typedef enum { f_none, f_replace, f_append } sed_function;
66
67#define NO_LINE -2
68#define LAST_LINE -1
69static int addr_line = NO_LINE;
70static char *addr_pattern = NULL;
71static int negated = 0;
72
73#define SKIPSPACES(p) do { while (isspace(*(p))) (p)++; } while (0)
74
75#define BUFSIZE 1024
76
77static inline int at_last(FILE * fp)
Eric Andersen50d63601999-11-09 01:47:36 +000078{
Erik Andersen1266a131999-12-29 22:19:46 +000079 int res = 0;
Eric Andersen6b6b3f61999-10-28 16:06:25 +000080
Erik Andersen1266a131999-12-29 22:19:46 +000081 if (feof(fp))
82 return 1;
83 else {
84 char ch;
85 if ((ch = fgetc(fp)) == EOF)
86 res++;
87 ungetc(ch, fp);
88 }
89 return res;
90}
91
92static void do_sed_repl(FILE * fp, char *needle, char *newNeedle,
93 int ignoreCase, int printFlag, int quietFlag)
94{
95 int foundOne = FALSE;
96 char haystack[BUFSIZE];
97 int line = 1, doit;
98
99 while (fgets(haystack, BUFSIZE - 1, fp)) {
100 doit = 0;
101 if (addr_pattern) {
102 doit = !find_match(haystack, addr_pattern, FALSE);
103 } else if (addr_line == NO_LINE)
104 doit = 1;
105 else if (addr_line == LAST_LINE) {
106 if (at_last(fp))
107 doit = 1;
108 } else {
109 if (line == addr_line)
110 doit = 1;
111 }
112 if (negated)
113 doit = 1 - doit;
114 if (doit) {
115 foundOne =
116 replace_match(haystack, needle, newNeedle, ignoreCase);
117
118 if (foundOne == TRUE && printFlag == TRUE) {
119 fprintf(stdout, haystack);
120 }
121 }
122
123 if (quietFlag == FALSE) {
Eric Andersen50d63601999-11-09 01:47:36 +0000124 fprintf(stdout, haystack);
125 }
Erik Andersen1266a131999-12-29 22:19:46 +0000126
127 line++;
Eric Andersen50d63601999-11-09 01:47:36 +0000128 }
129}
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000130
Erik Andersen1266a131999-12-29 22:19:46 +0000131static void do_sed_append(FILE * fp, char *appendline, int quietFlag)
132{
133 char buffer[BUFSIZE];
134 int line = 1, doit;
135
136 while (fgets(buffer, BUFSIZE - 1, fp)) {
137 doit = 0;
138 if (addr_pattern) {
139 doit = !find_match(buffer, addr_pattern, FALSE);
140 } else if (addr_line == NO_LINE)
141 doit = 1;
142 else if (addr_line == LAST_LINE) {
143 if (at_last(fp))
144 doit = 1;
145 } else {
146 if (line == addr_line)
147 doit = 1;
148 }
149 if (negated)
150 doit = 1 - doit;
151 if (quietFlag == FALSE) {
152 fprintf(stdout, buffer);
153 }
154 if (doit) {
155 fputs(appendline, stdout);
156 fputc('\n', stdout);
157 }
158
159 line++;
160 }
161}
162
163extern int sed_main(int argc, char **argv)
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000164{
165 FILE *fp;
Erik Andersen1266a131999-12-29 22:19:46 +0000166 char *needle = NULL, *newNeedle = NULL;
Eric Andersenc1525e81999-10-29 00:07:31 +0000167 char *name;
168 char *cp;
Erik Andersen1266a131999-12-29 22:19:46 +0000169 int ignoreCase = FALSE;
170 int printFlag = FALSE;
171 int quietFlag = FALSE;
Eric Andersenc1525e81999-10-29 00:07:31 +0000172 int stopNow;
Erik Andersen1266a131999-12-29 22:19:46 +0000173 char *line_s = NULL, saved;
174 char *appendline = NULL;
175 char *pos;
176 sed_function sed_f = f_none;
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000177
178 argc--;
179 argv++;
180 if (argc < 1) {
Eric Andersenc1525e81999-10-29 00:07:31 +0000181 usage(sed_usage);
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000182 }
183
184 if (**argv == '-') {
185 argc--;
186 cp = *argv++;
Erik Andersen1266a131999-12-29 22:19:46 +0000187 stopNow = FALSE;
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000188
Erik Andersen1266a131999-12-29 22:19:46 +0000189 while (*++cp && stopNow == FALSE) {
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000190 switch (*cp) {
191 case 'n':
Eric Andersen7f1acfd1999-10-29 23:09:13 +0000192 quietFlag = TRUE;
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000193 break;
194 case 'e':
Erik Andersen1266a131999-12-29 22:19:46 +0000195 if (*(cp + 1) == 0 && --argc < 0) {
196 usage(sed_usage);
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000197 }
Erik Andersen1266a131999-12-29 22:19:46 +0000198 if (*++cp != 's')
Eric Andersen50d63601999-11-09 01:47:36 +0000199 cp = *argv++;
Erik Andersen1266a131999-12-29 22:19:46 +0000200
201 /* Read address if present */
202 SKIPSPACES(cp);
203 if (*cp == '$') {
204 addr_line = LAST_LINE;
205 cp++;
206 } else {
207 if (isdigit(*cp)) { /* LINE ADDRESS */
208 line_s = cp;
209 while (isdigit(*cp))
210 cp++;
211 if (cp > line_s) {
212 /* numeric line */
213 saved = *cp;
214 *cp = '\0';
215 addr_line = atoi(line_s);
216 *cp = saved;
Eric Andersenc1525e81999-10-29 00:07:31 +0000217 }
Erik Andersen1266a131999-12-29 22:19:46 +0000218 } else if (*cp == '/') { /* PATTERN ADDRESS */
219 pos = addr_pattern = cp + 1;
220 pos = strchr(pos, '/');
221 if (!pos)
222 usage(sed_usage);
223 *pos = '\0';
224 cp = pos + 1;
225 }
226 }
227
228 SKIPSPACES(cp);
229 if (*cp == '!') {
230 negated++;
231 cp++;
232 }
233
234 /* Read command */
235
236 SKIPSPACES(cp);
237 switch (*cp) {
238 case 's': /* REPLACE */
239 if (strlen(cp) <= 3 || *(cp + 1) != '/')
240 break;
241 sed_f = f_replace;
242
243 pos = needle = cp + 2;
244
245 for (;;) {
246 pos = strchr(pos, '/');
247 if (pos == NULL) {
248 usage(sed_usage);
Eric Andersenc1525e81999-10-29 00:07:31 +0000249 }
Erik Andersen1266a131999-12-29 22:19:46 +0000250 if (*(pos - 1) == '\\') {
251 pos++;
252 continue;
253 }
254 break;
255 }
256 *pos = 0;
257 newNeedle = ++pos;
258 for (;;) {
259 pos = strchr(pos, '/');
260 if (pos == NULL) {
261 usage(sed_usage);
262 }
263 if (*(pos - 1) == '\\') {
264 pos++;
265 continue;
266 }
267 break;
268 }
269 *pos = 0;
270 if (pos + 2 != 0) {
271 while (*++pos) {
272 switch (*pos) {
273 case 'i':
274 ignoreCase = TRUE;
275 break;
276 case 'p':
277 printFlag = TRUE;
278 break;
279 case 'g':
280 break;
281 default:
282 usage(sed_usage);
Eric Andersen7f1acfd1999-10-29 23:09:13 +0000283 }
284 }
Eric Andersenc1525e81999-10-29 00:07:31 +0000285 }
Erik Andersen1266a131999-12-29 22:19:46 +0000286 cp = pos;
287 /* fprintf(stderr, "replace '%s' with '%s'\n", needle, newNeedle); */
288 break;
289
290 case 'a': /* APPEND */
291 if (strlen(cp) < 2)
292 break;
293 sed_f = f_append;
294 appendline = ++cp;
295 /* fprintf(stderr, "append '%s'\n", appendline); */
296 break;
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000297 }
Erik Andersen1266a131999-12-29 22:19:46 +0000298
299 stopNow = TRUE;
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000300 break;
301
302 default:
Eric Andersenc1525e81999-10-29 00:07:31 +0000303 usage(sed_usage);
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000304 }
Eric Andersen50d63601999-11-09 01:47:36 +0000305 }
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000306 }
307
Erik Andersen1266a131999-12-29 22:19:46 +0000308 if (argc == 0) {
309 switch (sed_f) {
310 case f_none:
311 break;
312 case f_replace:
313 do_sed_repl(stdin, needle, newNeedle, ignoreCase, printFlag,
314 quietFlag);
315 break;
316 case f_append:
317 do_sed_append(stdin, appendline, quietFlag);
318 break;
319 }
Eric Andersen50d63601999-11-09 01:47:36 +0000320 } else {
321 while (argc-- > 0) {
322 name = *argv++;
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000323
Erik Andersen1266a131999-12-29 22:19:46 +0000324 fp = fopen(name, "r");
Eric Andersen50d63601999-11-09 01:47:36 +0000325 if (fp == NULL) {
Erik Andersen1266a131999-12-29 22:19:46 +0000326 perror(name);
Eric Andersen50d63601999-11-09 01:47:36 +0000327 continue;
328 }
329
Erik Andersen1266a131999-12-29 22:19:46 +0000330 switch (sed_f) {
331 case f_none:
332 break;
333 case f_replace:
334 do_sed_repl(fp, needle, newNeedle, ignoreCase, printFlag,
335 quietFlag);
336 break;
337 case f_append:
338 do_sed_append(fp, appendline, quietFlag);
339 break;
340 }
Eric Andersen50d63601999-11-09 01:47:36 +0000341
Erik Andersen1266a131999-12-29 22:19:46 +0000342 if (ferror(fp))
343 perror(name);
Eric Andersen50d63601999-11-09 01:47:36 +0000344
Erik Andersen1266a131999-12-29 22:19:46 +0000345 fclose(fp);
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000346 }
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000347 }
Erik Andersen1266a131999-12-29 22:19:46 +0000348 exit(TRUE);
Eric Andersen6b6b3f61999-10-28 16:06:25 +0000349}
350
351
352/* END CODE */