View | Details | Raw Unified | Return to bug 195929 | Differences between
and this patch

Collapse All | Expand All

(-)Makefile (-1 / +1 lines)
Lines 6-12 Link Here
6
PROG=	sed
6
PROG=	sed
7
SRCS=	compile.c main.c misc.c process.c
7
SRCS=	compile.c main.c misc.c process.c
8
8
9
WARNS?=	2
9
WARNS?=	5
10
10
11
.if ${MK_TESTS} != "no"
11
.if ${MK_TESTS} != "no"
12
SUBDIR+= tests
12
SUBDIR+= tests
(-)compile.c (-124 / +120 lines)
Lines 64-84 Link Here
64
	int	lh_ref;
64
	int	lh_ref;
65
} *labels[LHSZ];
65
} *labels[LHSZ];
66
66
67
static char	 *compile_addr(char *, struct s_addr *);
67
static const char	 *compile_addr(const char *, struct s_addr *);
68
static char	 *compile_ccl(char **, char *);
68
static       char	 *compile_ccl(const char **, char *);
69
static char	 *compile_delimited(char *, char *, int);
69
static const char	 *compile_delimited(const char *, char *, int);
70
static char	 *compile_flags(char *, struct s_subst *);
70
static const char	 *compile_flags(const char *, struct s_subst *);
71
static regex_t	 *compile_re(char *, int);
71
static const regex_t	 *compile_re(const char *, int);
72
static char	 *compile_subst(char *, struct s_subst *);
72
static const char	 *compile_subst(const char *, struct s_subst *);
73
static char	 *compile_text(void);
73
static       char	 *compile_text(size_t *);
74
static char	 *compile_tr(char *, struct s_tr **);
74
static const char	 *compile_tr(const char *, struct s_tr **);
75
static struct s_command
75
static struct s_command
76
		**compile_stream(struct s_command **);
76
		**compile_stream(struct s_command **);
77
static char	 *duptoeol(char *, const char *);
77
static char	 *duptoeol(const char *, const char *, size_t *);
78
static void	  enterlabel(struct s_command *);
78
static void	  enterlabel(struct s_command *);
79
static struct s_command
79
static struct s_command
80
		 *findlabel(char *);
80
		 *findlabel(const char *);
81
static void	  fixuplabel(struct s_command *, struct s_command *);
81
static void	  fixuplabel(struct s_command *, const struct s_command *);
82
static void	  uselabel(void);
82
static void	  uselabel(void);
83
83
84
/*
84
/*
Lines 144-183 Link Here
144
		err(1, "malloc");
144
		err(1, "malloc");
145
}
145
}
146
146
147
#define EATSPACE() do {							\
147
#define EATSPACE() do {						\
148
	if (p)								\
148
	while (*p && isspace((unsigned char)*p))		\
149
		while (*p && isspace((unsigned char)*p))                \
149
		p++;						\
150
			p++;						\
151
	} while (0)
150
	} while (0)
152
151
152
#define EATSPACEN() do {					\
153
	while (*p && *p != '\n' && isspace((unsigned char)*p))  \
154
		p++;						\
155
	} while (0)
156
153
static struct s_command **
157
static struct s_command **
154
compile_stream(struct s_command **link)
158
compile_stream(struct s_command **link)
155
{
159
{
156
	char *p;
160
	const char *p;
157
	static char lbuf[_POSIX2_LINE_MAX + 1];	/* To save stack */
158
	struct s_command *cmd, *cmd2, *stack;
161
	struct s_command *cmd, *cmd2, *stack;
159
	struct s_format *fp;
162
	struct s_format *fp;
160
	char re[_POSIX2_LINE_MAX + 1];
163
	char re[_POSIX2_LINE_MAX + 1];
161
	int naddr;				/* Number of addresses */
164
	int naddr;				/* Number of addresses */
162
165
163
	stack = 0;
166
	stack = NULL;
164
	for (;;) {
167
	for (;;) {
165
		if ((p = cu_fgets(lbuf, sizeof(lbuf), NULL)) == NULL) {
168
		if ((p = cu_fgets(NULL)) == NULL) {
166
			if (stack != 0)
169
			if (stack != NULL)
167
				errx(1, "%lu: %s: unexpected EOF (pending }'s)",
170
				errx(1, "%lu: %s: unexpected EOF (pending }'s)",
168
							linenum, fname);
171
							linenum, fname);
169
			return (link);
172
			return (link);
170
		}
173
		}
171
174
172
semicolon:	EATSPACE();
175
semicolon:	EATSPACEN();
173
		if (p) {
176
		switch (*p) {
174
			if (*p == '#' || *p == '\0')
177
		case '#': case '\0': case '\n':
175
				continue;
178
			continue;	/* to next command-unit */
176
			else if (*p == ';') {
179
		case ';':
177
				p++;
180
			p++;
178
				goto semicolon;
181
			goto semicolon;
179
			}
180
		}
182
		}
183
181
		if ((*link = cmd = malloc(sizeof(struct s_command))) == NULL)
184
		if ((*link = cmd = malloc(sizeof(struct s_command))) == NULL)
182
			err(1, "malloc");
185
			err(1, "malloc");
183
		link = &cmd->next;
186
		link = &cmd->next;
Lines 208-214 Link Here
208
			cmd->a1 = cmd->a2 = 0;
211
			cmd->a1 = cmd->a2 = 0;
209
212
210
nonsel:		/* Now parse the command */
213
nonsel:		/* Now parse the command */
211
		if (!*p)
214
		if (*p == '\0' || *p == '\n')
212
			errx(1, "%lu: %s: command expected", linenum, fname);
215
			errx(1, "%lu: %s: command expected", linenum, fname);
213
		cmd->code = *p;
216
		cmd->code = *p;
214
		for (fp = cmd_fmts; fp->code; fp++)
217
		for (fp = cmd_fmts; fp->code; fp++)
Lines 215-221 Link Here
215
			if (fp->code == *p)
218
			if (fp->code == *p)
216
				break;
219
				break;
217
		if (!fp->code)
220
		if (!fp->code)
218
			errx(1, "%lu: %s: invalid command code %c", linenum, fname, *p);
221
			errx(1, "%lu: %s: invalid command code %c (%s)", linenum, fname, *p, p);
219
		if (naddr > fp->naddr)
222
		if (naddr > fp->naddr)
220
			errx(1,
223
			errx(1,
221
				"%lu: %s: command %c expects up to %d address(es), found %d",
224
				"%lu: %s: command %c expects up to %d address(es), found %d",
Lines 228-238 Link Here
228
			goto nonsel;
231
			goto nonsel;
229
		case GROUP:			/* { */
232
		case GROUP:			/* { */
230
			p++;
233
			p++;
231
			EATSPACE();
234
			EATSPACEN();
232
			cmd->next = stack;
235
			cmd->next = stack;
233
			stack = cmd;
236
			stack = cmd;
234
			link = &cmd->u.c;
237
			link = &cmd->u.c;
235
			if (*p)
238
			if (*p != '\0' && *p != '\n')
236
				goto semicolon;
239
				goto semicolon;
237
			break;
240
			break;
238
		case ENDGROUP:
241
		case ENDGROUP:
Lines 241-247 Link Here
241
			 * group is really just a noop.
244
			 * group is really just a noop.
242
			 */
245
			 */
243
			cmd->nonsel = 1;
246
			cmd->nonsel = 1;
244
			if (stack == 0)
247
			if (stack == NULL)
245
				errx(1, "%lu: %s: unexpected }", linenum, fname);
248
				errx(1, "%lu: %s: unexpected }", linenum, fname);
246
			cmd2 = stack;
249
			cmd2 = stack;
247
			stack = cmd2->next;
250
			stack = cmd2->next;
Lines 249-261 Link Here
249
			/*FALLTHROUGH*/
252
			/*FALLTHROUGH*/
250
		case EMPTY:		/* d D g G h H l n N p P q x = \0 */
253
		case EMPTY:		/* d D g G h H l n N p P q x = \0 */
251
			p++;
254
			p++;
252
			EATSPACE();
255
			EATSPACEN();
253
			if (*p == ';') {
256
			if (*p == ';') {
254
				p++;
257
				p++;
255
				link = &cmd->next;
258
				link = &cmd->next;
256
				goto semicolon;
259
				goto semicolon;
257
			}
260
			}
258
			if (*p)
261
			if (*p != '\0' && *p != '\n')
259
				errx(1, "%lu: %s: extra characters at the end of %c command",
262
				errx(1, "%lu: %s: extra characters at the end of %c command",
260
						linenum, fname, cmd->code);
263
						linenum, fname, cmd->code);
261
			break;
264
			break;
Lines 266-277 Link Here
266
				errx(1,
269
				errx(1,
267
"%lu: %s: command %c expects \\ followed by text", linenum, fname, cmd->code);
270
"%lu: %s: command %c expects \\ followed by text", linenum, fname, cmd->code);
268
			p++;
271
			p++;
269
			EATSPACE();
272
			EATSPACEN();
270
			if (*p)
273
			if (*p != '\n')
271
				errx(1,
274
				errx(1,
272
				"%lu: %s: extra characters after \\ at the end of %c command",
275
				"%lu: %s: extra characters (%c) after \\ at the end of %c command",
273
				linenum, fname, cmd->code);
276
				linenum, fname, *p, cmd->code);
274
			cmd->t = compile_text();
277
			cmd->t = compile_text(&cmd->tlen);
275
			break;
278
			break;
276
		case COMMENT:			/* \0 # */
279
		case COMMENT:			/* \0 # */
277
			break;
280
			break;
Lines 280-289 Link Here
280
			EATSPACE();
283
			EATSPACE();
281
			if (*p == '\0')
284
			if (*p == '\0')
282
				errx(1, "%lu: %s: filename expected", linenum, fname);
285
				errx(1, "%lu: %s: filename expected", linenum, fname);
283
			cmd->t = duptoeol(p, "w command");
286
			cmd->t = duptoeol(p, "w command", &cmd->tlen);
284
			if (aflag)
287
			if (aflag)
285
				cmd->u.fd = -1;
288
				cmd->u.fd = -1;
286
			else if ((cmd->u.fd = open(p,
289
			else if ((cmd->u.fd = open(cmd->t,
287
			    O_WRONLY|O_APPEND|O_CREAT|O_TRUNC,
290
			    O_WRONLY|O_APPEND|O_CREAT|O_TRUNC,
288
			    DEFFILEMODE)) == -1)
291
			    DEFFILEMODE)) == -1)
289
				err(1, "%s", p);
292
				err(1, "%s", p);
Lines 294-320 Link Here
294
			if (*p == '\0')
297
			if (*p == '\0')
295
				errx(1, "%lu: %s: filename expected", linenum, fname);
298
				errx(1, "%lu: %s: filename expected", linenum, fname);
296
			else
299
			else
297
				cmd->t = duptoeol(p, "read command");
300
				cmd->t = duptoeol(p, "read command", &cmd->tlen);
298
			break;
301
			break;
299
		case BRANCH:			/* b t */
302
		case BRANCH:			/* b t */
300
			p++;
303
			p++;
301
			EATSPACE();
304
			EATSPACEN();
302
			if (*p == '\0')
305
			if (*p == '\0' || *p == '\n')
303
				cmd->t = NULL;
306
				cmd->t = NULL;
304
			else
307
			else
305
				cmd->t = duptoeol(p, "branch");
308
				cmd->t = duptoeol(p, "branch", &cmd->tlen);
306
			break;
309
			break;
307
		case LABEL:			/* : */
310
		case LABEL:			/* : */
308
			p++;
311
			p++;
309
			EATSPACE();
312
			EATSPACE();
310
			cmd->t = duptoeol(p, "label");
313
			cmd->t = duptoeol(p, "label", &cmd->tlen);
311
			if (strlen(p) == 0)
314
			if (cmd->t[0] == '\0')
312
				errx(1, "%lu: %s: empty label", linenum, fname);
315
				errx(1, "%lu: %s: empty label", linenum, fname);
313
			enterlabel(cmd);
316
			enterlabel(cmd);
314
			break;
317
			break;
315
		case SUBST:			/* s */
318
		case SUBST:			/* s */
316
			p++;
319
			p++;
317
			if (*p == '\0' || *p == '\\')
320
			if (*p == '\0' || *p == '\\' || *p == '\n')
318
				errx(1,
321
				errx(1,
319
"%lu: %s: substitute pattern can not be delimited by newline or backslash",
322
"%lu: %s: substitute pattern can not be delimited by newline or backslash",
320
					linenum, fname);
323
					linenum, fname);
Lines 325-345 Link Here
325
				errx(1,
328
				errx(1,
326
				"%lu: %s: unterminated substitute pattern", linenum, fname);
329
				"%lu: %s: unterminated substitute pattern", linenum, fname);
327
330
328
			/* Compile RE with no case sensitivity temporarily */
329
			if (*re == '\0')
330
				cmd->u.s->re = NULL;
331
			else
332
				cmd->u.s->re = compile_re(re, 0);
333
			--p;
331
			--p;
334
			p = compile_subst(p, cmd->u.s);
332
			p = compile_subst(p, cmd->u.s);
335
			p = compile_flags(p, cmd->u.s);
333
			p = compile_flags(p, cmd->u.s);
336
334
337
			/* Recompile RE with case sensitivity from "I" flag if any */
335
			if (*re != '\0')
338
			if (*re == '\0')
339
				cmd->u.s->re = NULL;
340
			else
341
				cmd->u.s->re = compile_re(re, cmd->u.s->icase);
336
				cmd->u.s->re = compile_re(re, cmd->u.s->icase);
337
342
			EATSPACE();
338
			EATSPACE();
339
343
			if (*p == ';') {
340
			if (*p == ';') {
344
				p++;
341
				p++;
345
				link = &cmd->next;
342
				link = &cmd->next;
Lines 372-379 Link Here
372
 * in the case of a non-terminated string.  The character array d is filled
369
 * in the case of a non-terminated string.  The character array d is filled
373
 * with the processed string.
370
 * with the processed string.
374
 */
371
 */
375
static char *
372
static const char *
376
compile_delimited(char *p, char *d, int is_tr)
373
compile_delimited(const char *p, char *d, int is_tr)
377
{
374
{
378
	char c;
375
	char c;
379
376
Lines 416-425 Link Here
416
413
417
/* compile_ccl: expand a POSIX character class */
414
/* compile_ccl: expand a POSIX character class */
418
static char *
415
static char *
419
compile_ccl(char **sp, char *t)
416
compile_ccl(const char **sp, char *t)
420
{
417
{
421
	int c, d;
418
	int c, d;
422
	char *s = *sp;
419
	const char *s = *sp;
423
420
424
	*t++ = *s++;
421
	*t++ = *s++;
425
	if (*s == '^')
422
	if (*s == '^')
Lines 441-448 Link Here
441
 * regular expression.
438
 * regular expression.
442
 * Cflags are passed to regcomp.
439
 * Cflags are passed to regcomp.
443
 */
440
 */
444
static regex_t *
441
static const regex_t *
445
compile_re(char *re, int case_insensitive)
442
compile_re(const char *re, int case_insensitive)
446
{
443
{
447
	regex_t *rep;
444
	regex_t *rep;
448
	int eval, flags;
445
	int eval, flags;
Lines 466-479 Link Here
466
 * point to a saved copy of it.  Nsub is the number of parenthesized regular
463
 * point to a saved copy of it.  Nsub is the number of parenthesized regular
467
 * expressions.
464
 * expressions.
468
 */
465
 */
469
static char *
466
static const char *
470
compile_subst(char *p, struct s_subst *s)
467
compile_subst(const char *p, struct s_subst *s)
471
{
468
{
472
	static char lbuf[_POSIX2_LINE_MAX + 1];
473
	int asize, size;
469
	int asize, size;
474
	u_char ref;
470
	u_char ref;
475
	char c, *text, *op, *sp;
471
	char c, *text, *op, *sp;
476
	int more = 1, sawesc = 0;
472
	int more = 0, sawesc = 0;
477
473
478
	c = *p++;			/* Terminator character */
474
	c = *p++;			/* Terminator character */
479
	if (c == '\0')
475
	if (c == '\0')
Lines 487-493 Link Here
487
	size = 0;
483
	size = 0;
488
	do {
484
	do {
489
		op = sp = text + size;
485
		op = sp = text + size;
490
		for (; *p; p++) {
486
		for (; *p != '\0' && *p != '\n'; p++) {
491
			if (*p == '\\' || sawesc) {
487
			if (*p == '\\' || sawesc) {
492
				/*
488
				/*
493
				 * If this is a continuation from the last
489
				 * If this is a continuation from the last
Lines 509-515 Link Here
509
					 */
505
					 */
510
					sawesc = 1;
506
					sawesc = 1;
511
					p--;
507
					p--;
512
					continue;
508
					break;
509
				} else if (*p == '\n') {
510
					*sp++ = '\n';
511
					break;
513
				} else if (strchr("123456789", *p) != NULL) {
512
				} else if (strchr("123456789", *p) != NULL) {
514
					*sp++ = '\\';
513
					*sp++ = '\\';
515
					ref = *p - '0';
514
					ref = *p - '0';
Lines 523-530 Link Here
523
					*sp++ = '\\';
522
					*sp++ = '\\';
524
			} else if (*p == c) {
523
			} else if (*p == c) {
525
				if (*++p == '\0' && more) {
524
				if (*++p == '\0' && more) {
526
					if (cu_fgets(lbuf, sizeof(lbuf), &more))
525
					const char *nextp;
527
						p = lbuf;
526
527
					nextp = cu_fgets(&more);
528
					if (nextp != NULL)
529
						p = nextp;
528
				}
530
				}
529
				*sp++ = '\0';
531
				*sp++ = '\0';
530
				size += sp - op;
532
				size += sp - op;
Lines 544-550 Link Here
544
			if ((text = realloc(text, asize)) == NULL)
546
			if ((text = realloc(text, asize)) == NULL)
545
				err(1, "realloc");
547
				err(1, "realloc");
546
		}
548
		}
547
	} while (cu_fgets(p = lbuf, sizeof(lbuf), &more));
549
	} while ((p = cu_fgets(&more)));
548
	errx(1, "%lu: %s: unterminated substitute in regular expression",
550
	errx(1, "%lu: %s: unterminated substitute in regular expression",
549
			linenum, fname);
551
			linenum, fname);
550
	/* NOTREACHED */
552
	/* NOTREACHED */
Lines 553-564 Link Here
553
/*
555
/*
554
 * Compile the flags of the s command
556
 * Compile the flags of the s command
555
 */
557
 */
556
static char *
558
static const char *
557
compile_flags(char *p, struct s_subst *s)
559
compile_flags(const char *p, struct s_subst *s)
558
{
560
{
559
	int gn;			/* True if we have seen g or n */
561
	int gn;			/* True if we have seen g or n */
560
	unsigned long nval;
562
	unsigned long nval;
561
	char wfile[_POSIX2_LINE_MAX + 1], *q, *eq;
563
	char *q;
562
564
563
	s->n = 1;				/* Default */
565
	s->n = 1;				/* Default */
564
	s->p = 0;
566
	s->p = 0;
Lines 566-572 Link Here
566
	s->wfd = -1;
568
	s->wfd = -1;
567
	s->icase = 0;
569
	s->icase = 0;
568
	for (gn = 0;;) {
570
	for (gn = 0;;) {
569
		EATSPACE();			/* EXTENSION */
571
		EATSPACEN();			/* EXTENSION */
570
		switch (*p) {
572
		switch (*p) {
571
		case 'g':
573
		case 'g':
572
			if (gn)
574
			if (gn)
Lines 594-606 Link Here
594
"%lu: %s: more than one number or 'g' in substitute flags", linenum, fname);
596
"%lu: %s: more than one number or 'g' in substitute flags", linenum, fname);
595
			gn = 1;
597
			gn = 1;
596
			errno = 0;
598
			errno = 0;
597
			nval = strtol(p, &p, 10);
599
			nval = strtol(p, &q, 10);
598
			if (errno == ERANGE || nval > INT_MAX)
600
			if (errno == ERANGE || nval > INT_MAX)
599
				errx(1,
601
				errx(1,
600
"%lu: %s: overflow in the 'N' substitute flag", linenum, fname);
602
"%lu: %s: overflow in the 'N' substitute flag", linenum, fname);
601
			s->n = nval;
603
			s->n = nval;
602
			p--;
604
			p = q;
603
			break;
605
			continue;
604
		case 'w':
606
		case 'w':
605
			p++;
607
			p++;
606
#ifdef HISTORIC_PRACTICE
608
#ifdef HISTORIC_PRACTICE
Lines 610-636 Link Here
610
			}
612
			}
611
#endif
613
#endif
612
			EATSPACE();
614
			EATSPACE();
613
			q = wfile;
615
			s->wfile = duptoeol(p, "w flag", NULL);
614
			eq = wfile + sizeof(wfile) - 1;
616
			if (!aflag && (s->wfd = open(s->wfile,
615
			while (*p) {
616
				if (*p == '\n')
617
					break;
618
				if (q >= eq)
619
					err(1, "wfile too long");
620
				*q++ = *p++;
621
			}
622
			*q = '\0';
623
			if (q == wfile)
624
				errx(1, "%lu: %s: no wfile specified", linenum, fname);
625
			s->wfile = strdup(wfile);
626
			if (!aflag && (s->wfd = open(wfile,
627
			    O_WRONLY|O_APPEND|O_CREAT|O_TRUNC,
617
			    O_WRONLY|O_APPEND|O_CREAT|O_TRUNC,
628
			    DEFFILEMODE)) == -1)
618
			    DEFFILEMODE)) == -1)
629
				err(1, "%s", wfile);
619
				err(1, "%s", s->wfile);
630
			return (p);
620
			return (p);
631
		default:
621
		default:
632
			errx(1, "%lu: %s: bad flag in substitute command: '%c'",
622
			errx(1, "%lu: %s: bad flag in substitute command: '%c' (%.10s)",
633
					linenum, fname, *p);
623
					linenum, fname, *p, p);
634
			break;
624
			break;
635
		}
625
		}
636
		p++;
626
		p++;
Lines 640-647 Link Here
640
/*
630
/*
641
 * Compile a translation set of strings into a lookup table.
631
 * Compile a translation set of strings into a lookup table.
642
 */
632
 */
643
static char *
633
static const char *
644
compile_tr(char *p, struct s_tr **py)
634
compile_tr(const char *p, struct s_tr **py)
645
{
635
{
646
	struct s_tr *y;
636
	struct s_tr *y;
647
	int i;
637
	int i;
Lines 652-658 Link Here
652
	mbstate_t mbs1, mbs2;
642
	mbstate_t mbs1, mbs2;
653
643
654
	if ((*py = y = malloc(sizeof(*y))) == NULL)
644
	if ((*py = y = malloc(sizeof(*y))) == NULL)
655
		err(1, NULL);
645
		err(1, "malloc");
656
	y->multis = NULL;
646
	y->multis = NULL;
657
	y->nmultis = 0;
647
	y->nmultis = 0;
658
648
Lines 672-682 Link Here
672
	op = old;
662
	op = old;
673
	oldlen = mbsrtowcs(NULL, &op, 0, NULL);
663
	oldlen = mbsrtowcs(NULL, &op, 0, NULL);
674
	if (oldlen == (size_t)-1)
664
	if (oldlen == (size_t)-1)
675
		err(1, NULL);
665
		err(1, "mbsrtowcs");
676
	np = new;
666
	np = new;
677
	newlen = mbsrtowcs(NULL, &np, 0, NULL);
667
	newlen = mbsrtowcs(NULL, &np, 0, NULL);
678
	if (newlen == (size_t)-1)
668
	if (newlen == (size_t)-1)
679
		err(1, NULL);
669
		err(1, "mbsrtowcs");
680
	if (newlen != oldlen)
670
	if (newlen != oldlen)
681
		errx(1, "%lu: %s: transform strings are not the same length",
671
		errx(1, "%lu: %s: transform strings are not the same length",
682
				linenum, fname);
672
				linenum, fname);
Lines 715-721 Link Here
715
				y->multis = realloc(y->multis,
705
				y->multis = realloc(y->multis,
716
				    (y->nmultis + 1) * sizeof(*y->multis));
706
				    (y->nmultis + 1) * sizeof(*y->multis));
717
				if (y->multis == NULL)
707
				if (y->multis == NULL)
718
					err(1, NULL);
708
					err(1, "realloc");
719
				i = y->nmultis++;
709
				i = y->nmultis++;
720
				y->multis[i].fromlen = oclen;
710
				y->multis[i].fromlen = oclen;
721
				memcpy(y->multis[i].from, op, oclen);
711
				memcpy(y->multis[i].from, op, oclen);
Lines 733-756 Link Here
733
 * Compile the text following an a or i command.
723
 * Compile the text following an a or i command.
734
 */
724
 */
735
static char *
725
static char *
736
compile_text(void)
726
compile_text(size_t *ptlen)
737
{
727
{
738
	int asize, esc_nl, size;
728
	int asize, esc_nl, size;
739
	char *text, *p, *op, *s;
729
	char *text, *s;
740
	char lbuf[_POSIX2_LINE_MAX + 1];
730
	const char *p, *op;
741
731
742
	asize = 2 * _POSIX2_LINE_MAX + 1;
732
	asize = 2 * _POSIX2_LINE_MAX + 1;
743
	if ((text = malloc(asize)) == NULL)
733
	if ((text = malloc(asize)) == NULL)
744
		err(1, "malloc");
734
		err(1, "malloc");
745
	size = 0;
735
	size = 0;
746
	while (cu_fgets(lbuf, sizeof(lbuf), NULL)) {
736
	while ((p = cu_fgets(NULL))) {
747
		op = s = text + size;
737
		op = s = text + size;
748
		p = lbuf;
738
		EATSPACEN();
749
		EATSPACE();
750
		for (esc_nl = 0; *p != '\0'; p++) {
739
		for (esc_nl = 0; *p != '\0'; p++) {
751
			if (*p == '\\' && p[1] != '\0' && *++p == '\n')
740
			if (*p == '\\' && p[1] != '\0' && *++p == '\n')
752
				esc_nl = 1;
741
				esc_nl = 1;
753
			*s++ = *p;
742
			*s++ = *p;
743
			if (*p == '\n')
744
				break;
754
		}
745
		}
755
		size += s - op;
746
		size += s - op;
756
		if (!esc_nl) {
747
		if (!esc_nl) {
Lines 764-772 Link Here
764
		}
755
		}
765
	}
756
	}
766
	text[size] = '\0';
757
	text[size] = '\0';
767
	if ((p = realloc(text, size + 1)) == NULL)
758
	if ((text = realloc(text, size + 1)) == NULL)
768
		err(1, "realloc");
759
		err(1, "realloc");
769
	return (p);
760
	*ptlen = size;
761
	return (text);
770
}
762
}
771
763
772
/*
764
/*
Lines 773-780 Link Here
773
 * Get an address and return a pointer to the first character after
765
 * Get an address and return a pointer to the first character after
774
 * it.  Fill the structure pointed to according to the address.
766
 * it.  Fill the structure pointed to according to the address.
775
 */
767
 */
776
static char *
768
static const char *
777
compile_addr(char *p, struct s_addr *a)
769
compile_addr(const char *p, struct s_addr *a)
778
{
770
{
779
	char *end, re[_POSIX2_LINE_MAX + 1];
771
	char *end, re[_POSIX2_LINE_MAX + 1];
780
	int icase;
772
	int icase;
Lines 828-849 Link Here
828
 *	Return a copy of all the characters up to \n or \0.
820
 *	Return a copy of all the characters up to \n or \0.
829
 */
821
 */
830
static char *
822
static char *
831
duptoeol(char *s, const char *ctype)
823
duptoeol(const char *s, const char *ctype, size_t *ptlen)
832
{
824
{
833
	size_t len;
825
	size_t len;
834
	int ws;
826
	int ws;
835
	char *p, *start;
827
	char *p;
828
	const char *start;
836
829
837
	ws = 0;
830
	ws = 0;
838
	for (start = s; *s != '\0' && *s != '\n'; ++s)
831
	for (start = s; *s != '\0' && *s != '\n'; ++s)
839
		ws = isspace((unsigned char)*s);
832
		ws = isspace((unsigned char)*s);
840
	*s = '\0';
841
	if (ws)
833
	if (ws)
842
		warnx("%lu: %s: whitespace after %s", linenum, fname, ctype);
834
		warnx("%lu: %s: whitespace after %s", linenum, fname, ctype);
843
	len = s - start + 1;
835
	len = s - start;
844
	if ((p = malloc(len)) == NULL)
836
	if ((p = malloc(len + 1)) == NULL)
845
		err(1, "malloc");
837
		err(1, "malloc");
846
	return (memmove(p, start, len));
838
	memmove(p, start, len);
839
	p[len] = '\0';
840
	if (ptlen != NULL)
841
		*ptlen = len;
842
	return p;
847
}
843
}
848
844
849
/*
845
/*
Lines 854-860 Link Here
854
 * TODO: Remove } nodes
850
 * TODO: Remove } nodes
855
 */
851
 */
856
static void
852
static void
857
fixuplabel(struct s_command *cp, struct s_command *end)
853
fixuplabel(struct s_command *cp, const struct s_command *end)
858
{
854
{
859
855
860
	for (; cp != end; cp = cp->next)
856
	for (; cp != end; cp = cp->next)
Lines 871-877 Link Here
871
				break;
867
				break;
872
			}
868
			}
873
			if ((cp->u.c = findlabel(cp->t)) == NULL)
869
			if ((cp->u.c = findlabel(cp->t)) == NULL)
874
				errx(1, "%lu: %s: undefined label '%s'", linenum, fname, cp->t);
870
				errx(1, "%lu: %s: %c: undefined label '%s'", linenum, fname, cp->code, cp->t);
875
			free(cp->t);
871
			free(cp->t);
876
			break;
872
			break;
877
		case '{':
873
		case '{':
Lines 911-923 Link Here
911
 * list cp.  L is excluded from the search.  Return NULL if not found.
907
 * list cp.  L is excluded from the search.  Return NULL if not found.
912
 */
908
 */
913
static struct s_command *
909
static struct s_command *
914
findlabel(char *name)
910
findlabel(const char *name)
915
{
911
{
916
	struct labhash *lh;
912
	struct labhash *lh;
917
	u_char *p;
913
	const u_char *p;
918
	u_int h, c;
914
	u_int h, c;
919
915
920
	for (h = 0, p = (u_char *)name; (c = *p) != 0; p++)
916
	for (h = 0, p = (const u_char *)name; (c = *p) != 0; p++)
921
		h = (h << 5) + h + c;
917
		h = (h << 5) + h + c;
922
	for (lh = labels[h & LHMASK]; lh != NULL; lh = lh->lh_next) {
918
	for (lh = labels[h & LHMASK]; lh != NULL; lh = lh->lh_next) {
923
		if (lh->lh_hash == h && strcmp(name, lh->lh_cmd->t) == 0) {
919
		if (lh->lh_hash == h && strcmp(name, lh->lh_cmd->t) == 0) {
(-)defs.h (-2 / +3 lines)
Lines 51-57 Link Here
51
	enum e_atype type;			/* Address type */
51
	enum e_atype type;			/* Address type */
52
	union {
52
	union {
53
		u_long l;			/* Line number */
53
		u_long l;			/* Line number */
54
		regex_t *r;			/* Regular expression */
54
		const regex_t *r;		/* Regular expression */
55
	} u;
55
	} u;
56
};
56
};
57
57
Lines 64-70 Link Here
64
	int icase;				/* True if I flag */
64
	int icase;				/* True if I flag */
65
	char *wfile;				/* NULL if no wfile */
65
	char *wfile;				/* NULL if no wfile */
66
	int wfd;				/* Cached file descriptor */
66
	int wfd;				/* Cached file descriptor */
67
	regex_t *re;				/* Regular expression */
67
	const regex_t *re;			/* Regular expression */
68
	unsigned int maxbref;			/* Largest backreference. */
68
	unsigned int maxbref;			/* Largest backreference. */
69
	u_long linenum;				/* Line number. */
69
	u_long linenum;				/* Line number. */
70
	char *new;				/* Replacement text */
70
	char *new;				/* Replacement text */
Lines 94-99 Link Here
94
	struct s_addr *a1, *a2;			/* Start and end address */
94
	struct s_addr *a1, *a2;			/* Start and end address */
95
	u_long startline;			/* Start line number or zero */
95
	u_long startline;			/* Start line number or zero */
96
	char *t;				/* Text for : a c i r w */
96
	char *t;				/* Text for : a c i r w */
97
	size_t tlen;
97
	union {
98
	union {
98
		struct s_command *c;		/* Command(s) for b t { */
99
		struct s_command *c;		/* Command(s) for b t { */
99
		struct s_subst *s;		/* Substitute command */
100
		struct s_subst *s;		/* Substitute command */
(-)extern.h (-3 / +3 lines)
Lines 45-56 Link Here
45
extern FILE *infile, *outfile;
45
extern FILE *infile, *outfile;
46
extern int rflags;	/* regex flags to use */
46
extern int rflags;	/* regex flags to use */
47
47
48
void	 cfclose(struct s_command *, struct s_command *);
48
void	 cfclose(struct s_command *, const struct s_command *);
49
void	 compile(void);
49
void	 compile(void);
50
void	 cspace(SPACE *, const char *, size_t, enum e_spflag);
50
void	 cspace(SPACE *, const char *, size_t, enum e_spflag);
51
char	*cu_fgets(char *, int, int *);
51
const char *cu_fgets(int *);
52
int	 mf_fgets(SPACE *, enum e_spflag);
52
int	 mf_fgets(SPACE *, enum e_spflag);
53
int	 lastline(void);
53
int	 lastline(void);
54
void	 process(void);
54
void	 process(void);
55
void	 resetstate(void);
55
void	 resetstate(void);
56
char	*strregerror(int, regex_t *);
56
char	*strregerror(int, const regex_t *);
(-)main.c (-45 / +31 lines)
Lines 73-79 Link Here
73
struct s_compunit {
73
struct s_compunit {
74
	struct s_compunit *next;
74
	struct s_compunit *next;
75
	enum e_cut {CU_FILE, CU_STRING} type;
75
	enum e_cut {CU_FILE, CU_STRING} type;
76
	char *s;			/* Pointer to string or fname */
76
	const char *s;			/* Pointer to string or fname */
77
};
77
};
78
78
79
/*
79
/*
Lines 86-92 Link Here
86
 * Linked list of files to be processed
86
 * Linked list of files to be processed
87
 */
87
 */
88
struct s_flist {
88
struct s_flist {
89
	char *fname;
89
	const char *fname;
90
	struct s_flist *next;
90
	struct s_flist *next;
91
};
91
};
92
92
Lines 117-124 Link Here
117
static const char *inplace;	/* Inplace edit file extension. */
117
static const char *inplace;	/* Inplace edit file extension. */
118
u_long linenum;
118
u_long linenum;
119
119
120
static void add_compunit(enum e_cut, char *);
120
static void add_compunit(enum e_cut, const char *);
121
static void add_file(char *);
121
static void add_file(const char *);
122
static void usage(void);
122
static void usage(void);
123
123
124
int
124
int
Lines 125-131 Link Here
125
main(int argc, char *argv[])
125
main(int argc, char *argv[])
126
{
126
{
127
	int c, fflag;
127
	int c, fflag;
128
	char *temp_arg;
129
128
130
	(void) setlocale(LC_ALL, "");
129
	(void) setlocale(LC_ALL, "");
131
130
Lines 147-157 Link Here
147
			break;
146
			break;
148
		case 'e':
147
		case 'e':
149
			eflag = 1;
148
			eflag = 1;
150
			if ((temp_arg = malloc(strlen(optarg) + 2)) == NULL)
149
			add_compunit(CU_STRING, optarg);
151
				err(1, "malloc");
152
			strcpy(temp_arg, optarg);
153
			strcat(temp_arg, "\n");
154
			add_compunit(CU_STRING, temp_arg);
155
			break;
150
			break;
156
		case 'f':
151
		case 'f':
157
			fflag = 1;
152
			fflag = 1;
Lines 214-227 Link Here
214
 * Like fgets, but go through the chain of compilation units chaining them
209
 * Like fgets, but go through the chain of compilation units chaining them
215
 * together.  Empty strings and files are ignored.
210
 * together.  Empty strings and files are ignored.
216
 */
211
 */
217
char *
212
const char *
218
cu_fgets(char *buf, int n, int *more)
213
cu_fgets(int *more)
219
{
214
{
220
	static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
215
	static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
221
	static FILE *f;		/* Current open file */
216
	static FILE *f;		/* Current open file */
222
	static char *s;		/* Current pointer inside string */
217
	static const char *s;	/* Current pointer inside string */
223
	static char string_ident[30];
218
	static char string_ident[30], *lastresult;
219
	static size_t lastsize;
224
	char *p;
220
	char *p;
221
	const char *start;
225
222
226
again:
223
again:
227
	switch (state) {
224
	switch (state) {
Lines 251-264 Link Here
251
			goto again;
248
			goto again;
252
		}
249
		}
253
	case ST_FILE:
250
	case ST_FILE:
254
		if ((p = fgets(buf, n, f)) != NULL) {
251
		p = lastresult;
252
		if (getline(&p, &lastsize, f) != -1) {
255
			linenum++;
253
			linenum++;
256
			if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
254
			if (linenum == 1 && p[0] == '#' && p[1] == 'n')
257
				nflag = 1;
255
				nflag = 1;
258
			if (more != NULL)
256
			if (more != NULL)
259
				*more = !feof(f);
257
				*more = !feof(f);
260
			return (p);
258
			return (lastresult = p);
261
		}
259
		} else if (ferror(f))
260
			err(1, "%s", script->s);
262
		script = script->next;
261
		script = script->next;
263
		(void)fclose(f);
262
		(void)fclose(f);
264
		state = ST_EOF;
263
		state = ST_EOF;
Lines 266-304 Link Here
266
	case ST_STRING:
265
	case ST_STRING:
267
		if (linenum == 0 && s[0] == '#' && s[1] == 'n')
266
		if (linenum == 0 && s[0] == '#' && s[1] == 'n')
268
			nflag = 1;
267
			nflag = 1;
269
		p = buf;
268
		else if (s[0] == '\0') {
269
			state = ST_EOF;
270
			script = script->next;
271
			goto again;
272
		}
273
		start = s;
270
		for (;;) {
274
		for (;;) {
271
			if (n-- <= 1) {
272
				*p = '\0';
273
				linenum++;
274
				if (more != NULL)
275
					*more = 1;
276
				return (buf);
277
			}
278
			switch (*s) {
275
			switch (*s) {
279
			case '\0':
276
			case '\0':
280
				state = ST_EOF;
277
				state = ST_EOF;
281
				if (s == script->s) {
278
				script = script->next;
282
					script = script->next;
279
				/* FALLTHROUGH */
283
					goto again;
284
				} else {
285
					script = script->next;
286
					*p = '\0';
287
					linenum++;
288
					if (more != NULL)
289
						*more = 0;
290
					return (buf);
291
				}
292
			case '\n':
280
			case '\n':
293
				*p++ = '\n';
294
				*p = '\0';
295
				s++;
281
				s++;
296
				linenum++;
282
				linenum++;
297
				if (more != NULL)
283
				if (more != NULL)
298
					*more = 0;
284
					*more = 0;
299
				return (buf);
285
				return (start);
300
			default:
286
			default:
301
				*p++ = *s++;
287
				s++;
302
			}
288
			}
303
		}
289
		}
304
	}
290
	}
Lines 400-412 Link Here
400
				    sizeof(oldfname));
386
				    sizeof(oldfname));
401
				len = strlcat(oldfname, inplace,
387
				len = strlcat(oldfname, inplace,
402
				    sizeof(oldfname));
388
				    sizeof(oldfname));
403
				if (len > sizeof(oldfname))
389
				if ((size_t)len > sizeof(oldfname))
404
					errx(1, "%s: name too long", fname);
390
					errx(1, "%s: name too long", fname);
405
			}
391
			}
406
			len = snprintf(tmpfname, sizeof(tmpfname),
392
			len = snprintf(tmpfname, sizeof(tmpfname),
407
			    "%s/.!%ld!%s", dirname(fname), (long)getpid(),
393
			    "%s/.!%ld!%s", dirname(fname), (long)getpid(),
408
			    basename(fname));
394
			    basename(fname));
409
			if (len >= sizeof(tmpfname))
395
			if ((size_t)len >= sizeof(tmpfname))
410
				errx(1, "%s: name too long", fname);
396
				errx(1, "%s: name too long", fname);
411
			unlink(tmpfname);
397
			unlink(tmpfname);
412
			if (outfile != NULL && outfile != stdout)
398
			if (outfile != NULL && outfile != stdout)
Lines 454-460 Link Here
454
 * Add a compilation unit to the linked list
440
 * Add a compilation unit to the linked list
455
 */
441
 */
456
static void
442
static void
457
add_compunit(enum e_cut type, char *s)
443
add_compunit(enum e_cut type, const char *s)
458
{
444
{
459
	struct s_compunit *cu;
445
	struct s_compunit *cu;
460
446
Lines 471-477 Link Here
471
 * Add a file to the linked list
457
 * Add a file to the linked list
472
 */
458
 */
473
static void
459
static void
474
add_file(char *s)
460
add_file(const char *s)
475
{
461
{
476
	struct s_flist *fp;
462
	struct s_flist *fp;
477
463
(-)misc.c (-5 / +3 lines)
Lines 56-71 Link Here
56
 * the buffer).
56
 * the buffer).
57
 */
57
 */
58
char *
58
char *
59
strregerror(int errcode, regex_t *preg)
59
strregerror(int errcode, const regex_t *preg)
60
{
60
{
61
	static char *oe;
61
	static char *oe;
62
	size_t s;
62
	size_t s;
63
63
64
	if (oe != NULL)
65
		free(oe);
66
	s = regerror(errcode, preg, NULL, 0);
64
	s = regerror(errcode, preg, NULL, 0);
67
	if ((oe = malloc(s)) == NULL)
65
	if ((oe = realloc(oe, s)) == NULL)
68
		err(1, "malloc");
66
		err(1, "realloc");
69
	(void)regerror(errcode, preg, oe, s);
67
	(void)regerror(errcode, preg, oe, s);
70
	return (oe);
68
	return (oe);
71
}
69
}
(-)process.c (-18 / +18 lines)
Lines 66-79 Link Here
66
#define	hs		HS.space
66
#define	hs		HS.space
67
#define	hsl		HS.len
67
#define	hsl		HS.len
68
68
69
static inline int	 applies(struct s_command *);
69
static inline int	applies(struct s_command *);
70
static void		 do_tr(struct s_tr *);
70
static void		do_tr(const struct s_tr *);
71
static void		 flush_appends(void);
71
static void		flush_appends(void);
72
static void		 lputs(char *, size_t);
72
static void		lputs(const char *, size_t);
73
static int		 regexec_e(regex_t *, const char *, int, int, size_t,
73
static int		regexec_e(const regex_t *, const char *, int, int,
74
			     size_t);
74
			    size_t, size_t);
75
static void		 regsub(SPACE *, char *, char *);
75
static void		regsub(SPACE *, const char *, const char *);
76
static int		 substitute(struct s_command *);
76
static int		substitute(const struct s_command *);
77
77
78
struct s_appends *appends;	/* Array of pointers to strings to append. */
78
struct s_appends *appends;	/* Array of pointers to strings to append. */
79
static int appendx;		/* Index into appends array. */
79
static int appendx;		/* Index into appends array. */
Lines 82-88 Link Here
82
static int lastaddr;		/* Set by applies if last address of a range. */
82
static int lastaddr;		/* Set by applies if last address of a range. */
83
static int sdone;		/* If any substitutes since last line input. */
83
static int sdone;		/* If any substitutes since last line input. */
84
				/* Iov structure for 'w' commands. */
84
				/* Iov structure for 'w' commands. */
85
static regex_t *defpreg;
85
static const regex_t *defpreg;
86
size_t maxnsub;
86
size_t maxnsub;
87
regmatch_t *match;
87
regmatch_t *match;
88
88
Lines 366-378 Link Here
366
 *	and then swap them.
366
 *	and then swap them.
367
 */
367
 */
368
static int
368
static int
369
substitute(struct s_command *cp)
369
substitute(const struct s_command *cp)
370
{
370
{
371
	SPACE tspace;
371
	SPACE tspace;
372
	regex_t *re;
372
	const regex_t *re;
373
	regoff_t slen;
373
	regoff_t slen;
374
	int lastempty, n;
374
	int lastempty, n;
375
	size_t le = 0;
375
	regoff_t le = 0;
376
	char *s;
376
	char *s;
377
377
378
	s = ps;
378
	s = ps;
Lines 440-446 Link Here
440
	    regexec_e(re, ps, REG_NOTBOL, 0, le, psl));
440
	    regexec_e(re, ps, REG_NOTBOL, 0, le, psl));
441
441
442
	/* Did not find the requested number of matches. */
442
	/* Did not find the requested number of matches. */
443
	if (n > 1)
443
	if (n > 0)
444
		return (0);
444
		return (0);
445
445
446
	/* Copy the trailing retained string. */
446
	/* Copy the trailing retained string. */
Lines 477-483 Link Here
477
 *	Perform translation ('y' command) in the pattern space.
477
 *	Perform translation ('y' command) in the pattern space.
478
 */
478
 */
479
static void
479
static void
480
do_tr(struct s_tr *y)
480
do_tr(const struct s_tr *y)
481
{
481
{
482
	SPACE tmp;
482
	SPACE tmp;
483
	char c, *p;
483
	char c, *p;
Lines 566-572 Link Here
566
}
566
}
567
567
568
static void
568
static void
569
lputs(char *s, size_t len)
569
lputs(const char *s, size_t len)
570
{
570
{
571
	static const char escapes[] = "\\\a\b\f\r\t\v";
571
	static const char escapes[] = "\\\a\b\f\r\t\v";
572
	int c, col, width;
572
	int c, col, width;
Lines 646-652 Link Here
646
}
646
}
647
647
648
static int
648
static int
649
regexec_e(regex_t *preg, const char *string, int eflags, int nomatch,
649
regexec_e(const regex_t *preg, const char *string, int eflags, int nomatch,
650
	size_t start, size_t stop)
650
	size_t start, size_t stop)
651
{
651
{
652
	int eval;
652
	int eval;
Lines 678-684 Link Here
678
 * Based on a routine by Henry Spencer
678
 * Based on a routine by Henry Spencer
679
 */
679
 */
680
static void
680
static void
681
regsub(SPACE *sp, char *string, char *src)
681
regsub(SPACE *sp, const char *string, const char *src)
682
{
682
{
683
	int len, no;
683
	int len, no;
684
	char c, *dst;
684
	char c, *dst;
Lines 750-756 Link Here
750
 * Close all cached opened files and report any errors
750
 * Close all cached opened files and report any errors
751
 */
751
 */
752
void
752
void
753
cfclose(struct s_command *cp, struct s_command *end)
753
cfclose(struct s_command *cp, const struct s_command *end)
754
{
754
{
755
755
756
	for (; cp != end; cp = cp->next)
756
	for (; cp != end; cp = cp->next)
(-)tests/Makefile (-1 / +4 lines)
Lines 6-12 Link Here
6
TAP_TESTS_SH+=	multi_test
6
TAP_TESTS_SH+=	multi_test
7
TEST_METADATA.multi_test+=	required_files="/usr/share/dict/words"
7
TEST_METADATA.multi_test+=	required_files="/usr/share/dict/words"
8
TAP_TESTS_SH+=	inplace_race_test
8
TAP_TESTS_SH+=	inplace_race_test
9
9
TAP_TESTS_SH=	legacy_test
10
TAP_TESTS_SH+=	multi_test
11
TEST_METADATA.multi_test+=	required_files="/usr/share/dict/words"
12
TAP_TESTS_SH+=	inplace_race_test
10
FILESDIR=	${TESTSDIR}
13
FILESDIR=	${TESTSDIR}
11
FILES=		hanoi.sed
14
FILES=		hanoi.sed
12
FILES+=		math.sed
15
FILES+=		math.sed

Return to bug 195929