/bin/ed/sub.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 254 lines · 199 code · 19 blank · 36 comment · 88 complexity · 5281ffc889b24b58506d611c6bdbece9 MD5 · raw file

  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. #include <sys/cdefs.h>
  29. __FBSDID("$FreeBSD$");
  30. #include "ed.h"
  31. char *rhbuf; /* rhs substitution buffer */
  32. int rhbufsz; /* rhs substitution buffer size */
  33. int rhbufi; /* rhs substitution buffer index */
  34. /* extract_subst_tail: extract substitution tail from the command buffer */
  35. int
  36. extract_subst_tail(int *flagp, long *np)
  37. {
  38. char delimiter;
  39. *flagp = *np = 0;
  40. if ((delimiter = *ibufp) == '\n') {
  41. rhbufi = 0;
  42. *flagp = GPR;
  43. return 0;
  44. } else if (extract_subst_template() == NULL)
  45. return ERR;
  46. else if (*ibufp == '\n') {
  47. *flagp = GPR;
  48. return 0;
  49. } else if (*ibufp == delimiter)
  50. ibufp++;
  51. if ('1' <= *ibufp && *ibufp <= '9') {
  52. STRTOL(*np, ibufp);
  53. return 0;
  54. } else if (*ibufp == 'g') {
  55. ibufp++;
  56. *flagp = GSG;
  57. return 0;
  58. }
  59. return 0;
  60. }
  61. /* extract_subst_template: return pointer to copy of substitution template
  62. in the command buffer */
  63. char *
  64. extract_subst_template(void)
  65. {
  66. int n = 0;
  67. int i = 0;
  68. char c;
  69. char delimiter = *ibufp++;
  70. if (*ibufp == '%' && *(ibufp + 1) == delimiter) {
  71. ibufp++;
  72. if (!rhbuf)
  73. errmsg = "no previous substitution";
  74. return rhbuf;
  75. }
  76. while (*ibufp != delimiter) {
  77. REALLOC(rhbuf, rhbufsz, i + 2, NULL);
  78. if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') {
  79. i--, ibufp--;
  80. break;
  81. } else if (c != '\\')
  82. ;
  83. else if ((rhbuf[i++] = *ibufp++) != '\n')
  84. ;
  85. else if (!isglobal) {
  86. while ((n = get_tty_line()) == 0 ||
  87. (n > 0 && ibuf[n - 1] != '\n'))
  88. clearerr(stdin);
  89. if (n < 0)
  90. return NULL;
  91. }
  92. }
  93. REALLOC(rhbuf, rhbufsz, i + 1, NULL);
  94. rhbuf[rhbufi = i] = '\0';
  95. return rhbuf;
  96. }
  97. char *rbuf; /* substitute_matching_text buffer */
  98. int rbufsz; /* substitute_matching_text buffer size */
  99. /* search_and_replace: for each line in a range, change text matching a pattern
  100. according to a substitution template; return status */
  101. int
  102. search_and_replace(pattern_t *pat, int gflag, int kth)
  103. {
  104. undo_t *up;
  105. const char *txt;
  106. const char *eot;
  107. long lc;
  108. long xa = current_addr;
  109. int nsubs = 0;
  110. line_t *lp;
  111. int len;
  112. current_addr = first_addr - 1;
  113. for (lc = 0; lc <= second_addr - first_addr; lc++) {
  114. lp = get_addressed_line_node(++current_addr);
  115. if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0)
  116. return ERR;
  117. else if (len) {
  118. up = NULL;
  119. if (delete_lines(current_addr, current_addr) < 0)
  120. return ERR;
  121. txt = rbuf;
  122. eot = rbuf + len;
  123. SPL1();
  124. do {
  125. if ((txt = put_sbuf_line(txt)) == NULL) {
  126. SPL0();
  127. return ERR;
  128. } else if (up)
  129. up->t = get_addressed_line_node(current_addr);
  130. else if ((up = push_undo_stack(UADD,
  131. current_addr, current_addr)) == NULL) {
  132. SPL0();
  133. return ERR;
  134. }
  135. } while (txt != eot);
  136. SPL0();
  137. nsubs++;
  138. xa = current_addr;
  139. }
  140. }
  141. current_addr = xa;
  142. if (nsubs == 0 && !(gflag & GLB)) {
  143. errmsg = "no match";
  144. return ERR;
  145. } else if ((gflag & (GPR | GLS | GNP)) &&
  146. display_lines(current_addr, current_addr, gflag) < 0)
  147. return ERR;
  148. return 0;
  149. }
  150. /* substitute_matching_text: replace text matched by a pattern according to
  151. a substitution template; return pointer to the modified text */
  152. int
  153. substitute_matching_text(pattern_t *pat, line_t *lp, int gflag, int kth)
  154. {
  155. int off = 0;
  156. int changed = 0;
  157. int matchno = 0;
  158. int i = 0;
  159. regmatch_t rm[SE_MAX];
  160. char *txt;
  161. char *eot;
  162. if ((txt = get_sbuf_line(lp)) == NULL)
  163. return ERR;
  164. if (isbinary)
  165. NUL_TO_NEWLINE(txt, lp->len);
  166. eot = txt + lp->len;
  167. if (!regexec(pat, txt, SE_MAX, rm, 0)) {
  168. do {
  169. if (!kth || kth == ++matchno) {
  170. changed++;
  171. i = rm[0].rm_so;
  172. REALLOC(rbuf, rbufsz, off + i, ERR);
  173. if (isbinary)
  174. NEWLINE_TO_NUL(txt, rm[0].rm_eo);
  175. memcpy(rbuf + off, txt, i);
  176. off += i;
  177. if ((off = apply_subst_template(txt, rm, off,
  178. pat->re_nsub)) < 0)
  179. return ERR;
  180. } else {
  181. i = rm[0].rm_eo;
  182. REALLOC(rbuf, rbufsz, off + i, ERR);
  183. if (isbinary)
  184. NEWLINE_TO_NUL(txt, i);
  185. memcpy(rbuf + off, txt, i);
  186. off += i;
  187. }
  188. txt += rm[0].rm_eo;
  189. } while (*txt &&
  190. (!changed || ((gflag & GSG) && rm[0].rm_eo)) &&
  191. !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL));
  192. i = eot - txt;
  193. REALLOC(rbuf, rbufsz, off + i + 2, ERR);
  194. if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) {
  195. errmsg = "infinite substitution loop";
  196. return ERR;
  197. }
  198. if (isbinary)
  199. NEWLINE_TO_NUL(txt, i);
  200. memcpy(rbuf + off, txt, i);
  201. memcpy(rbuf + off + i, "\n", 2);
  202. }
  203. return changed ? off + i + 1 : 0;
  204. }
  205. /* apply_subst_template: modify text according to a substitution template;
  206. return offset to end of modified text */
  207. int
  208. apply_subst_template(const char *boln, regmatch_t *rm, int off, int re_nsub)
  209. {
  210. int j = 0;
  211. int k = 0;
  212. int n;
  213. char *sub = rhbuf;
  214. for (; sub - rhbuf < rhbufi; sub++)
  215. if (*sub == '&') {
  216. j = rm[0].rm_so;
  217. k = rm[0].rm_eo;
  218. REALLOC(rbuf, rbufsz, off + k - j, ERR);
  219. while (j < k)
  220. rbuf[off++] = boln[j++];
  221. } else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' &&
  222. (n = *sub - '0') <= re_nsub) {
  223. j = rm[n].rm_so;
  224. k = rm[n].rm_eo;
  225. REALLOC(rbuf, rbufsz, off + k - j, ERR);
  226. while (j < k)
  227. rbuf[off++] = boln[j++];
  228. } else {
  229. REALLOC(rbuf, rbufsz, off + 1, ERR);
  230. rbuf[off++] = *sub;
  231. }
  232. REALLOC(rbuf, rbufsz, off + 1, ERR);
  233. rbuf[off] = '\0';
  234. return off;
  235. }