157686Sbostic /*- 257686Sbostic * Copyright (c) 1992 The Regents of the University of California. 357686Sbostic * All rights reserved. 457686Sbostic * 557686Sbostic * This code is derived from software contributed to Berkeley by 657686Sbostic * Rodney Ruddock of the University of Guelph. 757686Sbostic * 857686Sbostic * %sccs.include.redist.c% 957686Sbostic */ 1057686Sbostic 1157686Sbostic #ifndef lint 12*57710Sbostic static char sccsid[] = "@(#)g.c 5.2 (Berkeley) 01/23/93"; 1357686Sbostic #endif /* not lint */ 1457686Sbostic 15*57710Sbostic #include <sys/types.h> 16*57710Sbostic 17*57710Sbostic #include <db.h> 18*57710Sbostic #include <regex.h> 19*57710Sbostic #include <setjmp.h> 20*57710Sbostic #include <stdio.h> 21*57710Sbostic #include <stdlib.h> 22*57710Sbostic #include <stdlib.h> 23*57710Sbostic #include <string.h> 24*57710Sbostic #include <unistd.h> 25*57710Sbostic 2657686Sbostic #include "ed.h" 27*57710Sbostic #include "extern.h" 2857686Sbostic 29*57710Sbostic static int find_line __P((LINE *)); 30*57710Sbostic static void w_cmd_l_file __P((FILE *, FILE *, int *)); 31*57710Sbostic 3257686Sbostic /* 3357686Sbostic * Find a line that we noted matched the RE earlier in the current 3457686Sbostic * buffer (it may have disappeared because of the commands in the 3557686Sbostic * command list). 3657686Sbostic */ 3757686Sbostic int 3857686Sbostic find_line(dot) 39*57710Sbostic LINE *dot; 4057686Sbostic { 41*57710Sbostic LINE *l_cl; 4257686Sbostic 43*57710Sbostic l_cl = top; 44*57710Sbostic for (;;) { 45*57710Sbostic if (l_cl == dot) 46*57710Sbostic return (1); 47*57710Sbostic if (l_cl == bottom) 48*57710Sbostic return (0); 49*57710Sbostic l_cl = l_cl->below; 50*57710Sbostic } 51*57710Sbostic } 5257686Sbostic 5357686Sbostic /* 5457686Sbostic * Write the command line to a STDIO tmp file. See g() below. 5557686Sbostic * This allows us to use cmd_loop to run the command list because 5657686Sbostic * we "trick" cmd_loop into reading a STDIO file instead of stdin. 5757686Sbostic */ 5857686Sbostic void 5957686Sbostic w_cmd_l_file(fp, inputt, errnum) 60*57710Sbostic FILE *fp, *inputt; 61*57710Sbostic int *errnum; 6257686Sbostic { 63*57710Sbostic int l_esc = 0, l_cnt = 0; 6457686Sbostic 65*57710Sbostic for (;;) { 66*57710Sbostic ss = getc(inputt); 67*57710Sbostic if (ss == '\\') { 68*57710Sbostic l_esc = 1; 69*57710Sbostic ss = getc(inputt); 70*57710Sbostic } 71*57710Sbostic if (((ss == '\n') && (l_esc == 0)) || (ss == EOF)) { 72*57710Sbostic /* if no command list default command list to 'p' */ 73*57710Sbostic if (l_cnt == 0) 74*57710Sbostic fputc('p', fp); 75*57710Sbostic break; 76*57710Sbostic } 77*57710Sbostic l_esc = 0; 78*57710Sbostic fputc(ss, fp); 79*57710Sbostic l_cnt++; 80*57710Sbostic } 81*57710Sbostic if (ss == EOF) 82*57710Sbostic clearerr(inputt); 83*57710Sbostic } 8457686Sbostic 8557686Sbostic /* 8657686Sbostic * The global function. All global commands (g, G, v, and V) are handled 8757686Sbostic * in here. The lines to be affected by the command list are 1st noted 8857686Sbostic * and then the command list is invoked for each line matching the RE. 8957686Sbostic * Note the trick of how the command list is executed. Saves a lot of 9057686Sbostic * code (and allows for \n's in substitutions). 9157686Sbostic */ 9257686Sbostic void 9357686Sbostic g(inputt, errnum) 94*57710Sbostic FILE *inputt; 95*57710Sbostic int *errnum; 9657686Sbostic { 97*57710Sbostic struct g_list *l_Head, *l_Foot, *l_gut, *l_old; 98*57710Sbostic static char *l_template_g; 99*57710Sbostic char *l_patt; 100*57710Sbostic static int l_template_flag = 0; 101*57710Sbostic int l_re_success, l_flag_v = 0, l_err; 102*57710Sbostic FILE *l_fp; 10357686Sbostic #ifdef POSIX 104*57710Sbostic LINE *l_posix_cur; 10557686Sbostic #endif 10657686Sbostic 107*57710Sbostic if (start_default && End_default) { 108*57710Sbostic start = top; 109*57710Sbostic End = bottom; 110*57710Sbostic } else 111*57710Sbostic if (start_default) 112*57710Sbostic start = End; 113*57710Sbostic if (start == NULL) { 114*57710Sbostic strcpy(help_msg, "bad address"); 115*57710Sbostic *errnum = -1; 116*57710Sbostic return; 117*57710Sbostic } 118*57710Sbostic if (sigint_flag) 119*57710Sbostic SIGINT_ACTION; 12057686Sbostic 121*57710Sbostic if (l_template_flag == 0) { 122*57710Sbostic l_template_flag = 1; 123*57710Sbostic l_template_g = calloc(FILENAME_LEN, sizeof(char)); 124*57710Sbostic if (l_template_g == NULL) { 125*57710Sbostic *errnum = -1; 126*57710Sbostic strcpy(help_msg, "out of memory error"); 127*57710Sbostic return; 128*57710Sbostic } 129*57710Sbostic } 130*57710Sbostic /* set up the STDIO command list file */ 131*57710Sbostic bcopy("/tmp/_4.4bsd_ed_g_XXXXXX\0", l_template_g, 24); 132*57710Sbostic mktemp(l_template_g); 13357686Sbostic 134*57710Sbostic l_Head = l_Foot = l_gut = l_old = NULL; 13557686Sbostic 136*57710Sbostic if ((ss == 'v') || (ss == 'V')) 137*57710Sbostic l_flag_v = 1; 13857686Sbostic 139*57710Sbostic if ((ss == 'G') || (ss == 'V')) { 140*57710Sbostic /* 141*57710Sbostic * If it's an interactive global command we use stdin, not a 142*57710Sbostic * file. 143*57710Sbostic */ 144*57710Sbostic GV_flag = 1; 145*57710Sbostic l_fp = stdin; 146*57710Sbostic } else { 147*57710Sbostic if ((l_fp = fopen(l_template_g, "w+")) == NULL) { 148*57710Sbostic perror("ed: file I/O error"); 149*57710Sbostic exit(1); 150*57710Sbostic } 151*57710Sbostic } 15257686Sbostic 153*57710Sbostic ss = getc(inputt); 15457686Sbostic 155*57710Sbostic /* Get the RE for the global command. */ 156*57710Sbostic l_patt = get_pattern(ss, inputt, errnum, 0); 157*57710Sbostic if (sigint_flag) 158*57710Sbostic SIGINT_ACTION; 159*57710Sbostic /* Instead of: if ((*errnum == -1) && (ss == '\n'))... */ 160*57710Sbostic if (*errnum < -1) 161*57710Sbostic return; 162*57710Sbostic *errnum = 0; 163*57710Sbostic if ((l_patt[1] == '\0') && (RE_flag == 0)) { 164*57710Sbostic *errnum = -1; 165*57710Sbostic ungetc(ss, inputt); 166*57710Sbostic return; 167*57710Sbostic } else 168*57710Sbostic if (l_patt[1] || (RE_patt == NULL)) { 169*57710Sbostic free(RE_patt); 170*57710Sbostic RE_patt = l_patt; 171*57710Sbostic } 172*57710Sbostic RE_sol = (RE_patt[1] == '^') ? 1 : 0; 173*57710Sbostic if ((RE_patt[1]) && 174*57710Sbostic (regfree(&RE_comp), l_err = regcomp(&RE_comp, &RE_patt[1], 0))) { 175*57710Sbostic regerror(l_err, &RE_comp, help_msg, 128); 176*57710Sbostic *errnum = -1; 177*57710Sbostic RE_flag = 0; 178*57710Sbostic ungetc(ss, inputt); 179*57710Sbostic return; 180*57710Sbostic } 181*57710Sbostic RE_flag = 1; 182*57710Sbostic if (sigint_flag) 183*57710Sbostic SIGINT_ACTION; 18457686Sbostic #ifdef POSIX 185*57710Sbostic l_posix_cur = current; 18657686Sbostic #endif 187*57710Sbostic current = start; 18857686Sbostic 189*57710Sbostic for (;;) { 190*57710Sbostic /* 191*57710Sbostic * Find the lines in the buffer that the global command wants 192*57710Sbostic * to work with. 193*57710Sbostic */ 194*57710Sbostic if (sigint_flag) 195*57710Sbostic goto point; 196*57710Sbostic get_line(current->handle, current->len); 197*57710Sbostic l_re_success = 198*57710Sbostic regexec(&RE_comp, text, (size_t) RE_SEC, RE_match, 0); 199*57710Sbostic /* l_re_success=0 => success */ 200*57710Sbostic if ((l_re_success != 0 && l_flag_v == 1) || 201*57710Sbostic (l_re_success == 0 && l_flag_v == 0)) { 202*57710Sbostic if (l_Head == NULL) { 203*57710Sbostic l_gut = malloc(sizeof(struct g_list)); 204*57710Sbostic if (l_gut == NULL) { 205*57710Sbostic *errnum = -1; 206*57710Sbostic strcpy(help_msg, "out of memory error"); 20757686Sbostic #ifdef POSIX 208*57710Sbostic current = l_posix_cur; 20957686Sbostic #endif 210*57710Sbostic return; 211*57710Sbostic } 212*57710Sbostic (l_gut->next) = NULL; 213*57710Sbostic (l_gut->cell) = current; 214*57710Sbostic l_Foot = l_Head = l_gut; 215*57710Sbostic } else { 216*57710Sbostic (l_gut->next) = malloc(sizeof(struct g_list)); 217*57710Sbostic if ((l_gut->next) == NULL) { 218*57710Sbostic *errnum = -1; 219*57710Sbostic strcpy(help_msg, "out of memory error"); 220*57710Sbostic goto clean; 221*57710Sbostic } 222*57710Sbostic l_gut = l_gut->next; 223*57710Sbostic (l_gut->cell) = current; 224*57710Sbostic (l_gut->next) = NULL; 225*57710Sbostic l_Foot = l_gut; 226*57710Sbostic } 227*57710Sbostic } 228*57710Sbostic if (End == current) 229*57710Sbostic break; 230*57710Sbostic current = current->below; 231*57710Sbostic } 23257686Sbostic 233*57710Sbostic if (l_Head == NULL) { 234*57710Sbostic strcpy(help_msg, "no matches found"); 235*57710Sbostic *errnum = -1; 23657686Sbostic #ifdef POSIX 237*57710Sbostic current = l_posix_cur; 23857686Sbostic #endif 239*57710Sbostic return; 240*57710Sbostic } 241*57710Sbostic /* if non-interactive, get the command list */ 242*57710Sbostic if (GV_flag == 0) 243*57710Sbostic w_cmd_l_file(l_fp, inputt, errnum); 244*57710Sbostic l_gut = l_Head; 24557686Sbostic 246*57710Sbostic if (g_flag == 0) 247*57710Sbostic u_clr_stk(); 24857686Sbostic 249*57710Sbostic for (;;) { 250*57710Sbostic /* 251*57710Sbostic * Execute the command list on the lines that still exist that 252*57710Sbostic * we indicated earlier that global wants to work with. 253*57710Sbostic */ 254*57710Sbostic if (sigint_flag) 255*57710Sbostic goto point; 256*57710Sbostic if (GV_flag == 0) 257*57710Sbostic fseek(l_fp, (off_t)0, 0); 258*57710Sbostic if (find_line(l_gut->cell)) { 259*57710Sbostic current = (l_gut->cell); 260*57710Sbostic get_line(current->handle, current->len); 261*57710Sbostic if (GV_flag == 1) 262*57710Sbostic printf("%s\n", text); 263*57710Sbostic g_flag++; 264*57710Sbostic explain_flag--; 265*57710Sbostic cmd_loop(l_fp, errnum); 266*57710Sbostic explain_flag++; 267*57710Sbostic g_flag--; 268*57710Sbostic if ((GV_flag == 1) && (*errnum < 0)) { 269*57710Sbostic ungetc('\n', l_fp); 270*57710Sbostic break; 271*57710Sbostic } 272*57710Sbostic *errnum = 0; 273*57710Sbostic if (l_gut == l_Foot) 274*57710Sbostic break; 275*57710Sbostic l_gut = l_gut->next; 276*57710Sbostic } 277*57710Sbostic } 27857686Sbostic 279*57710Sbostic point: 280*57710Sbostic if (GV_flag == 0) { 281*57710Sbostic fclose(l_fp); 282*57710Sbostic unlink(l_template_g); 283*57710Sbostic } 284*57710Sbostic GV_flag = 0; 28557686Sbostic clean: 286*57710Sbostic /* clean up */ 287*57710Sbostic l_gut = l_Head; 288*57710Sbostic while (1) { 289*57710Sbostic if (l_gut == NULL) 290*57710Sbostic break; 291*57710Sbostic l_old = l_gut; 292*57710Sbostic l_gut = l_gut->next; 293*57710Sbostic free(l_old); 294*57710Sbostic } 29557686Sbostic #ifdef POSIX 296*57710Sbostic current = l_posix_cur; 29757686Sbostic #endif 298*57710Sbostic } 299