1 /* glob.c: This file contains the global command routines for the ed line 2 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 * @(#)glob.c,v 1.1 1994/02/01 00:34:40 alm Exp 29 * $FreeBSD: head/bin/ed/glbl.c 281758 2015-04-20 02:07:57Z eadler $ 30 */ 31 32 #include <sys/types.h> 33 34 #include <sys/ioctl.h> 35 #include <sys/wait.h> 36 37 #include "ed.h" 38 39 40 /* build_active_list: add line matching a pattern to the global-active list */ 41 int 42 build_active_list(int isgcmd) 43 { 44 pattern_t *pat; 45 line_t *lp; 46 long n; 47 char *s; 48 char delimiter; 49 50 if ((delimiter = *ibufp) == ' ' || delimiter == '\n') { 51 errmsg = "invalid pattern delimiter"; 52 return ERR; 53 } else if ((pat = get_compiled_pattern()) == NULL) 54 return ERR; 55 else if (*ibufp == delimiter) 56 ibufp++; 57 clear_active_list(); 58 lp = get_addressed_line_node(first_addr); 59 for (n = first_addr; n <= second_addr; n++, lp = lp->q_forw) { 60 if ((s = get_sbuf_line(lp)) == NULL) 61 return ERR; 62 if (isbinary) 63 NUL_TO_NEWLINE(s, lp->len); 64 if (!(regexec(pat, s, 0, NULL, 0) == isgcmd) && 65 set_active_node(lp) < 0) 66 return ERR; 67 } 68 return 0; 69 } 70 71 72 /* exec_global: apply command list in the command buffer to the active 73 lines in a range; return command status */ 74 long 75 exec_global(int interact, int gflag) 76 { 77 static char *ocmd = NULL; 78 static int ocmdsz = 0; 79 80 line_t *lp = NULL; 81 int status; 82 int n; 83 char *cmd = NULL; 84 85 #ifdef BACKWARDS 86 if (!interact) 87 if (!strcmp(ibufp, "\n")) 88 cmd = "p\n"; /* null cmd-list == `p' */ 89 else if ((cmd = get_extended_line(&n, 0)) == NULL) 90 return ERR; 91 #else 92 if (!interact && (cmd = get_extended_line(&n, 0)) == NULL) 93 return ERR; 94 #endif 95 clear_undo_stack(); 96 while ((lp = next_active_node()) != NULL) { 97 if ((current_addr = get_line_node_addr(lp)) < 0) 98 return ERR; 99 if (interact) { 100 /* print current_addr; get a command in global syntax */ 101 if (display_lines(current_addr, current_addr, gflag) < 0) 102 return ERR; 103 while ((n = get_tty_line()) > 0 && 104 ibuf[n - 1] != '\n') 105 clearerr(stdin); 106 if (n < 0) 107 return ERR; 108 else if (n == 0) { 109 errmsg = "unexpected end-of-file"; 110 return ERR; 111 } else if (n == 1 && !strcmp(ibuf, "\n")) 112 continue; 113 else if (n == 2 && !strcmp(ibuf, "&\n")) { 114 if (cmd == NULL) { 115 errmsg = "no previous command"; 116 return ERR; 117 } else cmd = ocmd; 118 } else if ((cmd = get_extended_line(&n, 0)) == NULL) 119 return ERR; 120 else { 121 REALLOC(ocmd, ocmdsz, n + 1, ERR); 122 memcpy(ocmd, cmd, n + 1); 123 cmd = ocmd; 124 } 125 126 } 127 ibufp = cmd; 128 for (; *ibufp;) 129 if ((status = extract_addr_range()) < 0 || 130 (status = exec_command()) < 0 || 131 (status > 0 && (status = display_lines( 132 current_addr, current_addr, status)) < 0)) 133 return status; 134 } 135 return 0; 136 } 137 138 139 static line_t **active_list; /* list of lines active in a global command */ 140 static long active_last; /* index of last active line in active_list */ 141 static long active_size; /* size of active_list */ 142 static long active_ptr; /* active_list index (non-decreasing) */ 143 static long active_ndx; /* active_list index (modulo active_last) */ 144 145 /* set_active_node: add a line node to the global-active list */ 146 int 147 set_active_node(line_t *lp) 148 { 149 if (active_last + 1 > active_size) { 150 int ti = active_size; 151 line_t **ts; 152 SPL1(); 153 #if defined(sun) || defined(NO_REALLOC_NULL) 154 if (active_list != NULL) { 155 #endif 156 if ((ts = (line_t **) realloc(active_list, 157 (ti += MINBUFSZ) * sizeof(line_t *))) == NULL) { 158 fprintf(stderr, "%s\n", strerror(errno)); 159 errmsg = "out of memory"; 160 SPL0(); 161 return ERR; 162 } 163 #if defined(sun) || defined(NO_REALLOC_NULL) 164 } else { 165 if ((ts = (line_t **) malloc((ti += MINBUFSZ) * 166 sizeof(line_t **))) == NULL) { 167 fprintf(stderr, "%s\n", strerror(errno)); 168 errmsg = "out of memory"; 169 SPL0(); 170 return ERR; 171 } 172 } 173 #endif 174 active_size = ti; 175 active_list = ts; 176 SPL0(); 177 } 178 active_list[active_last++] = lp; 179 return 0; 180 } 181 182 183 /* unset_active_nodes: remove a range of lines from the global-active list */ 184 void 185 unset_active_nodes(line_t *np, line_t *mp) 186 { 187 line_t *lp; 188 long i; 189 190 for (lp = np; lp != mp; lp = lp->q_forw) 191 for (i = 0; i < active_last; i++) 192 if (active_list[active_ndx] == lp) { 193 active_list[active_ndx] = NULL; 194 active_ndx = INC_MOD(active_ndx, active_last - 1); 195 break; 196 } else active_ndx = INC_MOD(active_ndx, active_last - 1); 197 } 198 199 200 /* next_active_node: return the next global-active line node */ 201 line_t * 202 next_active_node(void) 203 { 204 while (active_ptr < active_last && active_list[active_ptr] == NULL) 205 active_ptr++; 206 return (active_ptr < active_last) ? active_list[active_ptr++] : NULL; 207 } 208 209 210 /* clear_active_list: clear the global-active list */ 211 void 212 clear_active_list(void) 213 { 214 SPL1(); 215 active_size = active_last = active_ptr = active_ndx = 0; 216 free(active_list); 217 active_list = NULL; 218 SPL0(); 219 } 220