1 /*- 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. 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 8.1 (Berkeley) 05/31/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 127 fputc('\n', fp); 128 if (ss == EOF) 129 clearerr(inputt); 130 } 131 132 133 /* 134 * The global function. All global commands (g, G, v, and V) are handled 135 * in here. The lines to be affected by the command list are 1st noted 136 * and then the command list is invoked for each line matching the RE. 137 * Note the trick of how the command list is executed. Saves a lot of 138 * code (and allows for \n's in substitutions). 139 */ 140 void 141 g(inputt, errnum) 142 FILE *inputt; 143 int *errnum; 144 { 145 static char *l_template_g; 146 char *l_patt; 147 static int l_template_flag = 0; 148 int l_re_success, l_flag_v = 0, l_err, l_num; 149 register l_gut_cnt, a; 150 register LINE **l_gut=gut; 151 FILE *l_fp; 152 #ifdef POSIX 153 LINE *l_posix_cur; 154 #endif 155 156 if (Start_default && End_default) { 157 Start = top; 158 End = bottom; 159 } else 160 if (Start_default) 161 Start = End; 162 if (Start == NULL) { 163 strcpy(help_msg, "buffer empty"); 164 *errnum = -1; 165 return; 166 } 167 168 if (l_template_flag == 0) { 169 sigspecial++; 170 l_template_flag = 1; 171 l_template_g = calloc(FILENAME_LEN, sizeof(char)); 172 sigspecial--; 173 if (sigint_flag && (!sigspecial)) 174 SIGINT_ACTION; 175 if (l_template_g == NULL) { 176 *errnum = -1; 177 strcpy(help_msg, "out of memory error"); 178 return; 179 } 180 } 181 /* set up the STDIO command list file */ 182 memmove(l_template_g, "/tmp/_4.4bsd_ed_g_XXXXXX\0", 24); 183 mktemp(l_template_g); 184 185 if ((ss == 'v') || (ss == 'V')) 186 l_flag_v = 1; 187 188 if ((ss == 'G') || (ss == 'V')) { 189 /* 190 * If it's an interactive global command we use stdin, not a 191 * file. 192 */ 193 GV_flag = 1; 194 l_fp = stdin; 195 } else { 196 sigspecial++; 197 if ((l_fp = fopen(l_template_g, "w+")) == NULL) { 198 perror("ed: file I/O error, save buffer in ed.hup"); 199 do_hup(); /* does not return */ 200 } 201 sigspecial--; 202 if (sigint_flag && (!sigspecial)) 203 goto point; 204 } 205 206 ss = getc(inputt); 207 208 /* Get the RE for the global command. */ 209 l_patt = get_pattern(ss, inputt, errnum, 0); 210 211 /* Instead of: if ((*errnum == -1) && (ss == '\n'))... */ 212 if (*errnum < -1) 213 return; 214 *errnum = 0; 215 if ((l_patt[1] == '\0') && (RE_flag == 0)) { 216 *errnum = -1; 217 ungetc(ss, inputt); 218 return; 219 } else 220 if (l_patt[1] || (RE_patt == NULL)) { 221 sigspecial++; 222 free(RE_patt); 223 RE_patt = l_patt; 224 sigspecial--; 225 if (sigint_flag && (!sigspecial)) 226 goto point; 227 } 228 RE_sol = (RE_patt[1] == '^') ? 1 : 0; 229 if ((RE_patt[1]) && 230 (regfree(&RE_comp), l_err = regcomp(&RE_comp, &RE_patt[1], 0))) { 231 regerror(l_err, &RE_comp, help_msg, 128); 232 *errnum = -1; 233 RE_flag = 0; 234 ungetc(ss, inputt); 235 return; 236 } 237 RE_flag = 1; 238 239 if (GV_flag) 240 ss = getc(inputt); 241 242 #ifdef POSIX 243 l_posix_cur = current; 244 #endif 245 current = Start; 246 247 sigspecial++; 248 249 if ((l_num = line_number(bottom)) > gut_num) { 250 sigspecial++; 251 gut_num = l_num + 512; 252 free(l_gut); 253 gut = l_gut = malloc(sizeof(LINE **) * gut_num); 254 sigspecial--; 255 if (l_gut == NULL) { 256 *errnum = -1; 257 strcpy(help_msg, "out of memory error"); 258 #ifdef POSIX 259 current = l_posix_cur; 260 #endif 261 ungetc('\n', inputt); 262 return; 263 } 264 } 265 l_gut_cnt = 0; 266 267 for (;;) { 268 /* 269 * Find the lines in the buffer that the global command wants 270 * to work with. 271 */ 272 get_line(current->handle, current->len); 273 if (sigint_flag && (!sigspecial)) 274 goto point; 275 l_re_success = 276 regexec(&RE_comp, text, (size_t) RE_SEC, RE_match, 0); 277 /* l_re_success=0 => success */ 278 if ( (l_re_success == 0 && l_flag_v == 0) || 279 (l_re_success && l_flag_v)) { 280 l_gut[l_gut_cnt++] = current; 281 } 282 if (End == current) 283 break; 284 current = current->below; 285 } 286 sigspecial--; 287 if (sigint_flag && (!sigspecial)) 288 goto point; 289 290 if (l_gut_cnt == 0) { 291 strcpy(help_msg, "no matches found"); 292 #ifdef POSIX 293 current = l_posix_cur; 294 #endif 295 return; 296 } 297 /* if non-interactive, get the command list */ 298 if (GV_flag == 0) { 299 sigspecial++; 300 w_cmd_l_file(l_fp, inputt, errnum); 301 sigspecial--; 302 if (sigint_flag) 303 goto point; 304 } 305 306 if (g_flag == 0) 307 u_clr_stk(); 308 309 sigspecial++; 310 for (a=0; a<l_gut_cnt; a++) { 311 /* 312 * Execute the command list on the lines that still exist that 313 * we indicated earlier that global wants to work with. 314 */ 315 if (sigint_flag) 316 goto point; 317 if (GV_flag == 0) 318 fseek(l_fp, (off_t)0, 0); 319 if (find_line(l_gut[a])) { 320 current = (l_gut[a]); 321 get_line(current->handle, current->len); 322 if (sigint_flag) 323 goto point; 324 if (GV_flag == 1) 325 printf("%s\n", text); 326 g_flag++; 327 explain_flag--; 328 sigspecial--; 329 cmd_loop(l_fp, errnum); 330 sigspecial++; 331 explain_flag++; 332 g_flag--; 333 if ((GV_flag == 1) && (*errnum < 0)) { 334 ungetc('\n', l_fp); 335 break; 336 } 337 *errnum = 0; 338 } 339 } 340 341 point: 342 if (GV_flag == 0) { 343 fclose(l_fp); 344 unlink(l_template_g); 345 } 346 else 347 ungetc('\n', inputt); 348 349 GV_flag = 0; 350 351 #ifdef POSIX 352 current = l_posix_cur; 353 #endif 354 sigspecial--; 355 if (sigint_flag) 356 SIGINT_ACTION; 357 } 358