sub.c

     1	/* sub.c: This file contains the substitution routines for the ed
     2	   line editor */
     3	/*-
     4	 * Copyright (c) 1993 Andrew Moore, Talke Studio.
     5	 * All rights reserved.
     6	 *
     7	 * Redistribution and use in source and binary forms, with or without
     8	 * modification, are permitted provided that the following conditions
     9	 * are met:
    10	 * 1. Redistributions of source code must retain the above copyright
    11	 *    notice, this list of conditions and the following disclaimer.
    12	 * 2. Redistributions in binary form must reproduce the above copyright
    13	 *    notice, this list of conditions and the following disclaimer in the
    14	 *    documentation and/or other materials provided with the distribution.
    15	 *
    16	 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    17	 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19	 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    20	 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    21	 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    22	 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    23	 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    24	 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    25	 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    26	 * SUCH DAMAGE.
    27	 */
    28	
    29	#include <sys/cdefs.h>
    30	__FBSDID("$FreeBSD: src/bin/ed/sub.c,v 1.15 2002/06/30 05:13:53 obrien Exp $");
    31	
    32	#include "ed.h"
    33	
    34	
    35	char *rhbuf;			/* rhs substitution buffer */
    36	int rhbufsz;			/* rhs substitution buffer size */
    37	int rhbufi;			/* rhs substitution buffer index */
    38	
    39	/* extract_subst_tail: extract substitution tail from the command buffer */
    40	int
    41	extract_subst_tail(int *flagp, long *np)
    42	{
    43		char delimiter;
    44	
    45		*flagp = *np = 0;
    46		if ((delimiter = *ibufp) == '\n') {
    47			rhbufi = 0;
    48			*flagp = GPR;
    49			return 0;
    50		} else if (extract_subst_template() == NULL)
    51			return  ERR;
    52		else if (*ibufp == '\n') {
    53			*flagp = GPR;
    54			return 0;
    55		} else if (*ibufp == delimiter)
    56			ibufp++;
    57		if ('1' <= *ibufp && *ibufp <= '9') {
    58			STRTOL(*np, ibufp);
    59			return 0;
    60		} else if (*ibufp == 'g') {
    61			ibufp++;
    62			*flagp = GSG;
    63			return 0;
    64		}
    65		return 0;
    66	}
    67	
    68	
    69	/* extract_subst_template: return pointer to copy of substitution template
    70	   in the command buffer */
    71	char *
    72	extract_subst_template(void)
    73	{
    74		int n = 0;
    75		int i = 0;
    76		char c;
    77		char delimiter = *ibufp++;
    78	
    79		if (*ibufp == '%' && *(ibufp + 1) == delimiter) {
    80			ibufp++;
    81			if (!rhbuf)
    82				errmsg = "no previous substitution";
    83			return rhbuf;
    84		}
    85		while (*ibufp != delimiter) {
    86			REALLOC(rhbuf, rhbufsz, i + 2, NULL);
    87			if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') {
    88				i--, ibufp--;
    89				break;
    90			} else if (c != '\\')
    91				;
    92			else if ((rhbuf[i++] = *ibufp++) != '\n')
    93				;
    94			else if (!isglobal) {
    95				while ((n = get_tty_line()) == 0 ||
    96				    (n > 0 && ibuf[n - 1] != '\n'))
    97					clearerr(stdin);
    98				if (n < 0)
    99					return NULL;
   100			}
   101		}
   102		REALLOC(rhbuf, rhbufsz, i + 1, NULL);
   103		rhbuf[rhbufi = i] = '\0';
   104		return  rhbuf;
   105	}
   106	
   107	
   108	char *rbuf;			/* substitute_matching_text buffer */
   109	int rbufsz;			/* substitute_matching_text buffer size */
   110	
   111	/* search_and_replace: for each line in a range, change text matching a pattern
   112	   according to a substitution template; return status  */
   113	int
   114	search_and_replace(pattern_t *pat, int gflag, int kth)
   115	{
   116		undo_t *up;
   117		const char *txt;
   118		const char *eot;
   119		long lc;
   120		long xa = current_addr;
   121		int nsubs = 0;
   122		line_t *lp;
   123		int len;
   124	
   125		current_addr = first_addr - 1;
   126		for (lc = 0; lc <= second_addr - first_addr; lc++) {
   127			lp = get_addressed_line_node(++current_addr);
   128			if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0)
   129				return ERR;
   130			else if (len) {
   131				up = NULL;
   132				if (delete_lines(current_addr, current_addr) < 0)
   133					return ERR;
   134				txt = rbuf;
   135				eot = rbuf + len;
   136				SPL1();
   137				do {
   138					if ((txt = put_sbuf_line(txt)) == NULL) {
   139						SPL0();
   140						return ERR;
   141					} else if (up)
   142						up->t = get_addressed_line_node(current_addr);
   143					else if ((up = push_undo_stack(UADD,
   144					    current_addr, current_addr)) == NULL) {
   145						SPL0();
   146						return ERR;
   147					}
   148				} while (txt != eot);
   149				SPL0();
   150				nsubs++;
   151				/* 3751351 */
   152				replace_marks(lp, get_addressed_line_node(current_addr));
   153				xa = current_addr;
   154			}
   155		}
   156		current_addr = xa;
   157		if  (nsubs == 0 && !(gflag & GLB)) {
   158			errmsg = "no match";
   159			return ERR;
   160		} else if ((gflag & (GPR | GLS | GNP)) &&
   161		    display_lines(current_addr, current_addr, gflag) < 0)
   162			return ERR;
   163		return 0;
   164	}
   165	
   166	
   167	/* substitute_matching_text: replace text matched by a pattern according to
   168	   a substitution template; return pointer to the modified text */
   169	int
   170	substitute_matching_text(pattern_t *pat, line_t *lp, int gflag, int kth)
   171	{
   172		int off = 0;
   173		int changed = 0;
   174		int matchno = 0;
   175		int i = 0;
   176		regmatch_t rm[SE_MAX];
   177		char *txt;
   178		char *eot;
   179	
   180		if ((txt = get_sbuf_line(lp)) == NULL)
   181			return ERR;
   182		if (isbinary)
   183			NUL_TO_NEWLINE(txt, lp->len);
   184		eot = txt + lp->len;
   185		if (!regexec(pat, txt, SE_MAX, rm, 0)) {
   186			do {
   187				if (!kth || kth == ++matchno) {
   188					changed++;
   189					i = rm[0].rm_so;
   190					REALLOC(rbuf, rbufsz, off + i, ERR);
   191					if (isbinary)
   192						NEWLINE_TO_NUL(txt, rm[0].rm_eo);
   193					memcpy(rbuf + off, txt, i);
   194					off += i;
   195					if ((off = apply_subst_template(txt, rm, off,
   196					    pat->re_nsub)) < 0)
   197						return ERR;
   198				} else {
   199					i = rm[0].rm_eo;
   200					REALLOC(rbuf, rbufsz, off + i, ERR);
   201					if (isbinary)
   202						NEWLINE_TO_NUL(txt, i);
   203					memcpy(rbuf + off, txt, i);
   204					off += i;
   205				}
   206				txt += rm[0].rm_eo;
   207			} while (*txt &&
   208	                        (!changed || ((gflag & GSG) && rm[0].rm_eo)) &&
   209			        !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL));
   210			i = eot - txt;
   211			REALLOC(rbuf, rbufsz, off + i + 2, ERR);
   212			if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) {
   213				errmsg = "infinite substitution loop";
   214				return  ERR;
   215			}
   216			if (isbinary)
   217				NEWLINE_TO_NUL(txt, i);
   218			memcpy(rbuf + off, txt, i);
   219			memcpy(rbuf + off + i, "\n", 2);
   220		}
   221		return changed ? off + i + 1 : 0;
   222	}
   223	
   224	
   225	/* apply_subst_template: modify text according to a substitution template;
   226	   return offset to end of modified text */
   227	int
   228	apply_subst_template(const char *boln, regmatch_t *rm, int off, int re_nsub)
   229	{
   230		int j = 0;
   231		int k = 0;
   232		int n;
   233		char *sub = rhbuf;
   234	
   235		for (; sub - rhbuf < rhbufi; sub++)
   236			if (*sub == '&') {
   237				j = rm[0].rm_so;
   238				k = rm[0].rm_eo;
   239				REALLOC(rbuf, rbufsz, off + k - j, ERR);
   240				while (j < k)
   241					rbuf[off++] = boln[j++];
   242			} else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' &&
   243			    (n = *sub - '0') <= re_nsub) {
   244				j = rm[n].rm_so;
   245				k = rm[n].rm_eo;
   246				REALLOC(rbuf, rbufsz, off + k - j, ERR);
   247				while (j < k)
   248					rbuf[off++] = boln[j++];
   249			} else {
   250				REALLOC(rbuf, rbufsz, off + 1, ERR);
   251				rbuf[off++] = *sub;
   252			}
   253		REALLOC(rbuf, rbufsz, off + 1, ERR);
   254		rbuf[off] = '\0';
   255		return off;
   256	}

Generated by GNU Enscript 1.6.6.