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