1 /*- 2 * Copyright (c) 1992 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rodney Ruddock of the University of Guelph. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char sccsid[] = "@(#)g.c 5.8 (Berkeley) 04/28/93"; 13 #endif /* not lint */ 14 15 #include <sys/types.h> 16 17 #include <limits.h> 18 #include <regex.h> 19 #include <setjmp.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 #ifdef DBI 27 #include <db.h> 28 #endif 29 30 #include "ed.h" 31 #include "extern.h" 32 33 static int find_line __P((LINE *)); 34 static void w_cmd_l_file __P((FILE *, FILE *, int *)); 35 36 /* 37 * Find a line that we noted matched the RE earlier in the current 38 * buffer (it may have disappeared because of the commands in the 39 * command list). 40 */ 41 static int 42 find_line(dot) 43 LINE *dot; 44 { 45 LINE *l_cl; 46 47 l_cl = top; 48 for (;;) { 49 if (l_cl == dot) 50 return (1); 51 if (l_cl == bottom) 52 return (0); 53 l_cl = l_cl->below; 54 } 55 } 56 57 /* 58 * Write the command line to a STDIO tmp file. See g() below. 59 * This allows us to use cmd_loop to run the command list because 60 * we "trick" cmd_loop into reading a STDIO file instead of stdin. 61 */ 62 63 static void 64 w_cmd_l_file(fp, inputt, errnum) 65 FILE *fp, *inputt; 66 int *errnum; 67 { 68 int sl=0, jmp_flag, l_cnt=0; 69 70 if (jmp_flag = setjmp(ctrl_position3)) 71 return; 72 73 for (;;) { 74 sigspecial3 = 1; 75 ss = getc(inputt); 76 sigspecial3 = 0; 77 skip1: 78 if (ss == EOF) 79 goto skip2; 80 else if (ss == '\n') { 81 if (sl != '\\') { 82 skip2: 83 if (l_cnt == 0) 84 fputc('p', fp); 85 else 86 fputc(sl, fp); 87 break; 88 } 89 } 90 else if ((ss == '\\') && (sl == '\\')) { 91 sigspecial3 = 1; 92 sl = getc(inputt); 93 sigspecial3 = 0; 94 if (sl == '\\') { 95 sigspecial3 = 1; 96 sl = getc(inputt); 97 sigspecial3 = 0; 98 if (sl == EOF) 99 goto skip2; 100 if (sl == '\n') { 101 fputc('\\', fp); 102 ss = sl; 103 } 104 else { 105 fputc('\\', fp); 106 fputc('\\', fp); 107 ss = sl; 108 sl = '\\'; 109 goto skip1; 110 } 111 } 112 else { 113 fputc('\\', fp); 114 fputc('\\', fp); 115 if ((sl == '\n') || (sl == EOF)) 116 goto skip2; 117 else 118 ss = sl; 119 } 120 } 121 else if (l_cnt) 122 fputc(sl, fp); 123 sl = ss; 124 l_cnt++; 125 } 126 if (ss == EOF) 127 clearerr(inputt); 128 } 129 130 131 /* 132 * The global function. All global commands (g, G, v, and V) are handled 133 * in here. The lines to be affected by the command list are 1st noted 134 * and then the command list is invoked for each line matching the RE. 135 * Note the trick of how the command list is executed. Saves a lot of 136 * code (and allows for \n's in substitutions). 137 */ 138 void 139 g(inputt, errnum) 140 FILE *inputt; 141 int *errnum; 142 { 143 static char *l_template_g; 144 char *l_patt; 145 static int l_template_flag = 0; 146 int l_re_success, l_flag_v = 0, l_err, l_num; 147 register l_gut_cnt, a; 148 register LINE **l_gut=gut; 149 FILE *l_fp; 150 #ifdef POSIX 151 LINE *l_posix_cur; 152 #endif 153 154 if (Start_default && End_default) { 155 Start = top; 156 End = bottom; 157 } else 158 if (Start_default) 159 Start = End; 160 if (Start == NULL) { 161 strcpy(help_msg, "buffer empty"); 162 *errnum = -1; 163 return; 164 } 165 166 if (l_template_flag == 0) { 167 sigspecial++; 168 l_template_flag = 1; 169 l_template_g = calloc(FILENAME_LEN, sizeof(char)); 170 sigspecial--; 171 if (sigint_flag && (!sigspecial)) 172 SIGINT_ACTION; 173 if (l_template_g == NULL) { 174 *errnum = -1; 175 strcpy(help_msg, "out of memory error"); 176 return; 177 } 178 } 179 /* set up the STDIO command list file */ 180 memmove(l_template_g, "/tmp/_4.4bsd_ed_g_XXXXXX\0", 24); 181 mktemp(l_template_g); 182 183 if ((ss == 'v') || (ss == 'V')) 184 l_flag_v = 1; 185 186 if ((ss == 'G') || (ss == 'V')) { 187 /* 188 * If it's an interactive global command we use stdin, not a 189 * file. 190 */ 191 GV_flag = 1; 192 l_fp = stdin; 193 } else { 194 sigspecial++; 195 if ((l_fp = fopen(l_template_g, "w+")) == NULL) { 196 perror("ed: file I/O error, save buffer in ed.hup"); 197 do_hup(); /* does not return */ 198 } 199 sigspecial--; 200 if (sigint_flag && (!sigspecial)) 201 goto point; 202 } 203 204 ss = getc(inputt); 205 206 /* Get the RE for the global command. */ 207 l_patt = get_pattern(ss, inputt, errnum, 0); 208 209 /* Instead of: if ((*errnum == -1) && (ss == '\n'))... */ 210 if (*errnum < -1) 211 return; 212 *errnum = 0; 213 if ((l_patt[1] == '\0') && (RE_flag == 0)) { 214 *errnum = -1; 215 ungetc(ss, inputt); 216 return; 217 } else 218 if (l_patt[1] || (RE_patt == NULL)) { 219 sigspecial++; 220 free(RE_patt); 221 RE_patt = l_patt; 222 sigspecial--; 223 if (sigint_flag && (!sigspecial)) 224 goto point; 225 } 226 RE_sol = (RE_patt[1] == '^') ? 1 : 0; 227 if ((RE_patt[1]) && 228 (regfree(&RE_comp), l_err = regcomp(&RE_comp, &RE_patt[1], 0))) { 229 regerror(l_err, &RE_comp, help_msg, 128); 230 *errnum = -1; 231 RE_flag = 0; 232 ungetc(ss, inputt); 233 return; 234 } 235 RE_flag = 1; 236 237 if (GV_flag) 238 ss = getc(inputt); 239 240 #ifdef POSIX 241 l_posix_cur = current; 242 #endif 243 current = Start; 244 245 sigspecial++; 246 247 if ((l_num = line_number(bottom)) > gut_num) { 248 sigspecial++; 249 gut_num = l_num + 512; 250 free(l_gut); 251 l_gut = malloc(sizeof(LINE **) * gut_num); 252 sigspecial--; 253 if (l_gut == NULL) { 254 *errnum = -1; 255 strcpy(help_msg, "out of memory error"); 256 #ifdef POSIX 257 current = l_posix_cur; 258 #endif 259 return; 260 } 261 } 262 l_gut_cnt = 0; 263 264 for (;;) { 265 /* 266 * Find the lines in the buffer that the global command wants 267 * to work with. 268 */ 269 get_line(current->handle, current->len); 270 if (sigint_flag && (!sigspecial)) 271 goto point; 272 l_re_success = 273 regexec(&RE_comp, text, (size_t) RE_SEC, RE_match, 0); 274 /* l_re_success=0 => success */ 275 if ( (l_re_success == 0 && l_flag_v == 0) || 276 (l_re_success && l_flag_v)) { 277 l_gut[l_gut_cnt++] = current; 278 } 279 if (End == current) 280 break; 281 current = current->below; 282 } 283 sigspecial--; 284 if (sigint_flag && (!sigspecial)) 285 goto point; 286 287 if (l_gut_cnt == 0) { 288 strcpy(help_msg, "no matches found"); 289 #ifdef POSIX 290 current = l_posix_cur; 291 #endif 292 return; 293 } 294 /* if non-interactive, get the command list */ 295 if (GV_flag == 0) { 296 sigspecial++; 297 w_cmd_l_file(l_fp, inputt, errnum); 298 sigspecial--; 299 if (sigint_flag) 300 goto point; 301 } 302 303 if (g_flag == 0) 304 u_clr_stk(); 305 306 sigspecial++; 307 for (a=0; a<l_gut_cnt; a++) { 308 /* 309 * Execute the command list on the lines that still exist that 310 * we indicated earlier that global wants to work with. 311 */ 312 if (sigint_flag) 313 goto point; 314 if (GV_flag == 0) 315 fseek(l_fp, (off_t)0, 0); 316 if (find_line(l_gut[a])) { 317 current = (l_gut[a]); 318 get_line(current->handle, current->len); 319 if (sigint_flag) 320 goto point; 321 if (GV_flag == 1) 322 printf("%s\n", text); 323 g_flag++; 324 explain_flag--; 325 sigspecial--; 326 cmd_loop(l_fp, errnum); 327 sigspecial++; 328 explain_flag++; 329 g_flag--; 330 if ((GV_flag == 1) && (*errnum < 0)) { 331 ungetc('\n', l_fp); 332 break; 333 } 334 *errnum = 0; 335 } 336 } 337 338 point: 339 if (GV_flag == 0) { 340 fclose(l_fp); 341 unlink(l_template_g); 342 } 343 else 344 ungetc('\n', inputt); 345 346 GV_flag = 0; 347 348 #ifdef POSIX 349 current = l_posix_cur; 350 #endif 351 sigspecial--; 352 if (sigint_flag) 353 SIGINT_ACTION; 354 } 355