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*58316Sbostic static char sccsid[] = "@(#)g.c 5.4 (Berkeley) 02/28/93"; 1357686Sbostic #endif /* not lint */ 1457686Sbostic 1557710Sbostic #include <sys/types.h> 1657710Sbostic 1758315Sbostic #include <limits.h> 1857710Sbostic #include <regex.h> 1957710Sbostic #include <setjmp.h> 2057710Sbostic #include <stdio.h> 2157710Sbostic #include <stdlib.h> 2257710Sbostic #include <stdlib.h> 2357710Sbostic #include <string.h> 2457710Sbostic #include <unistd.h> 2557710Sbostic 2658315Sbostic #ifdef DBI 2758315Sbostic #include <db.h> 2858315Sbostic #endif 2958315Sbostic 3057686Sbostic #include "ed.h" 3157710Sbostic #include "extern.h" 3257686Sbostic 3357710Sbostic static int find_line __P((LINE *)); 3457710Sbostic static void w_cmd_l_file __P((FILE *, FILE *, int *)); 3557710Sbostic 3657686Sbostic /* 3757686Sbostic * Find a line that we noted matched the RE earlier in the current 3857686Sbostic * buffer (it may have disappeared because of the commands in the 3957686Sbostic * command list). 4057686Sbostic */ 4158315Sbostic static int 4257686Sbostic find_line(dot) 4357710Sbostic LINE *dot; 4457686Sbostic { 4557710Sbostic LINE *l_cl; 4657686Sbostic 4757710Sbostic l_cl = top; 4857710Sbostic for (;;) { 4957710Sbostic if (l_cl == dot) 5057710Sbostic return (1); 5157710Sbostic if (l_cl == bottom) 5257710Sbostic return (0); 5357710Sbostic l_cl = l_cl->below; 5457710Sbostic } 5557710Sbostic } 5657686Sbostic 5757686Sbostic /* 5857686Sbostic * Write the command line to a STDIO tmp file. See g() below. 5957686Sbostic * This allows us to use cmd_loop to run the command list because 6057686Sbostic * we "trick" cmd_loop into reading a STDIO file instead of stdin. 6157686Sbostic */ 6258315Sbostic static void 6357686Sbostic w_cmd_l_file(fp, inputt, errnum) 6457710Sbostic FILE *fp, *inputt; 6557710Sbostic int *errnum; 6657686Sbostic { 6757710Sbostic int l_esc = 0, l_cnt = 0; 6857686Sbostic 6957710Sbostic for (;;) { 7057710Sbostic ss = getc(inputt); 7157710Sbostic if (ss == '\\') { 7257710Sbostic l_esc = 1; 7357710Sbostic ss = getc(inputt); 7457710Sbostic } 7557710Sbostic if (((ss == '\n') && (l_esc == 0)) || (ss == EOF)) { 7657710Sbostic /* if no command list default command list to 'p' */ 7757710Sbostic if (l_cnt == 0) 7857710Sbostic fputc('p', fp); 7957710Sbostic break; 8057710Sbostic } 8157710Sbostic l_esc = 0; 8257710Sbostic fputc(ss, fp); 8357710Sbostic l_cnt++; 8457710Sbostic } 8557710Sbostic if (ss == EOF) 8657710Sbostic clearerr(inputt); 8757710Sbostic } 8857686Sbostic 8957686Sbostic /* 9057686Sbostic * The global function. All global commands (g, G, v, and V) are handled 9157686Sbostic * in here. The lines to be affected by the command list are 1st noted 9257686Sbostic * and then the command list is invoked for each line matching the RE. 9357686Sbostic * Note the trick of how the command list is executed. Saves a lot of 9457686Sbostic * code (and allows for \n's in substitutions). 9557686Sbostic */ 9657686Sbostic void 9757686Sbostic g(inputt, errnum) 9857710Sbostic FILE *inputt; 9957710Sbostic int *errnum; 10057686Sbostic { 10157710Sbostic struct g_list *l_Head, *l_Foot, *l_gut, *l_old; 10257710Sbostic static char *l_template_g; 10357710Sbostic char *l_patt; 10457710Sbostic static int l_template_flag = 0; 10557710Sbostic int l_re_success, l_flag_v = 0, l_err; 10657710Sbostic FILE *l_fp; 10757686Sbostic #ifdef POSIX 10857710Sbostic LINE *l_posix_cur; 10957686Sbostic #endif 11057686Sbostic 11157710Sbostic if (start_default && End_default) { 11257710Sbostic start = top; 11357710Sbostic End = bottom; 11457710Sbostic } else 11557710Sbostic if (start_default) 11657710Sbostic start = End; 11757710Sbostic if (start == NULL) { 11858315Sbostic strcpy(help_msg, "buffer empty"); 11957710Sbostic *errnum = -1; 12057710Sbostic return; 12157710Sbostic } 12257686Sbostic 12357710Sbostic if (l_template_flag == 0) { 12458315Sbostic sigspecial++; 12557710Sbostic l_template_flag = 1; 12657710Sbostic l_template_g = calloc(FILENAME_LEN, sizeof(char)); 12758315Sbostic sigspecial--; 12858315Sbostic if (sigint_flag && (!sigspecial)) 12958315Sbostic SIGINT_ACTION; 13057710Sbostic if (l_template_g == NULL) { 13157710Sbostic *errnum = -1; 13257710Sbostic strcpy(help_msg, "out of memory error"); 13357710Sbostic return; 13457710Sbostic } 13557710Sbostic } 13657710Sbostic /* set up the STDIO command list file */ 13757710Sbostic bcopy("/tmp/_4.4bsd_ed_g_XXXXXX\0", l_template_g, 24); 13857710Sbostic mktemp(l_template_g); 13957686Sbostic 14057710Sbostic l_Head = l_Foot = l_gut = l_old = NULL; 14157686Sbostic 14257710Sbostic if ((ss == 'v') || (ss == 'V')) 14357710Sbostic l_flag_v = 1; 14457686Sbostic 14557710Sbostic if ((ss == 'G') || (ss == 'V')) { 14657710Sbostic /* 14757710Sbostic * If it's an interactive global command we use stdin, not a 14857710Sbostic * file. 14957710Sbostic */ 15057710Sbostic GV_flag = 1; 15157710Sbostic l_fp = stdin; 15257710Sbostic } else { 15358315Sbostic sigspecial++; 15457710Sbostic if ((l_fp = fopen(l_template_g, "w+")) == NULL) { 15558315Sbostic perror("ed: file I/O error, save buffer in ed.hup"); 15658315Sbostic do_hup(); /* does not return */ 15758315Sbostic sigspecial--; 15858315Sbostic if (sigint_flag && (!sigspecial)) 15958315Sbostic goto point; 16057710Sbostic } 16157710Sbostic } 16257686Sbostic 16357710Sbostic ss = getc(inputt); 16457686Sbostic 16557710Sbostic /* Get the RE for the global command. */ 16657710Sbostic l_patt = get_pattern(ss, inputt, errnum, 0); 16758315Sbostic 16857710Sbostic /* Instead of: if ((*errnum == -1) && (ss == '\n'))... */ 16957710Sbostic if (*errnum < -1) 17057710Sbostic return; 17157710Sbostic *errnum = 0; 17257710Sbostic if ((l_patt[1] == '\0') && (RE_flag == 0)) { 17357710Sbostic *errnum = -1; 17457710Sbostic ungetc(ss, inputt); 17557710Sbostic return; 17657710Sbostic } else 17757710Sbostic if (l_patt[1] || (RE_patt == NULL)) { 17858315Sbostic sigspecial++; 17957710Sbostic free(RE_patt); 18057710Sbostic RE_patt = l_patt; 18158315Sbostic sigspecial--; 18258315Sbostic if (sigint_flag && (!sigspecial)) 18358315Sbostic goto point; 18457710Sbostic } 18557710Sbostic RE_sol = (RE_patt[1] == '^') ? 1 : 0; 18657710Sbostic if ((RE_patt[1]) && 18757710Sbostic (regfree(&RE_comp), l_err = regcomp(&RE_comp, &RE_patt[1], 0))) { 18857710Sbostic regerror(l_err, &RE_comp, help_msg, 128); 18957710Sbostic *errnum = -1; 19057710Sbostic RE_flag = 0; 19157710Sbostic ungetc(ss, inputt); 19257710Sbostic return; 19357710Sbostic } 19457710Sbostic RE_flag = 1; 19558315Sbostic 19658315Sbostic if (GV_flag) 19758315Sbostic ss = getc(inputt); 19858315Sbostic 19957686Sbostic #ifdef POSIX 20057710Sbostic l_posix_cur = current; 20157686Sbostic #endif 20257710Sbostic current = start; 20357686Sbostic 20458315Sbostic sigspecial++; 20558315Sbostic 20657710Sbostic for (;;) { 20757710Sbostic /* 20857710Sbostic * Find the lines in the buffer that the global command wants 20957710Sbostic * to work with. 21057710Sbostic */ 21158315Sbostic if (sigint_flag && (!sigspecial)) 21257710Sbostic goto point; 21357710Sbostic get_line(current->handle, current->len); 21458315Sbostic if (sigint_flag && (!sigspecial)) 21558315Sbostic goto point; 21657710Sbostic l_re_success = 21757710Sbostic regexec(&RE_comp, text, (size_t) RE_SEC, RE_match, 0); 21857710Sbostic /* l_re_success=0 => success */ 21957710Sbostic if ((l_re_success != 0 && l_flag_v == 1) || 22057710Sbostic (l_re_success == 0 && l_flag_v == 0)) { 22157710Sbostic if (l_Head == NULL) { 22257710Sbostic l_gut = malloc(sizeof(struct g_list)); 22357710Sbostic if (l_gut == NULL) { 22457710Sbostic *errnum = -1; 22557710Sbostic strcpy(help_msg, "out of memory error"); 22657686Sbostic #ifdef POSIX 22757710Sbostic current = l_posix_cur; 22857686Sbostic #endif 22957710Sbostic return; 23057710Sbostic } 23157710Sbostic (l_gut->next) = NULL; 23257710Sbostic (l_gut->cell) = current; 23357710Sbostic l_Foot = l_Head = l_gut; 23457710Sbostic } else { 23557710Sbostic (l_gut->next) = malloc(sizeof(struct g_list)); 23657710Sbostic if ((l_gut->next) == NULL) { 23757710Sbostic *errnum = -1; 23857710Sbostic strcpy(help_msg, "out of memory error"); 23957710Sbostic goto clean; 24057710Sbostic } 24157710Sbostic l_gut = l_gut->next; 24257710Sbostic (l_gut->cell) = current; 24357710Sbostic (l_gut->next) = NULL; 24457710Sbostic l_Foot = l_gut; 24557710Sbostic } 24657710Sbostic } 24757710Sbostic if (End == current) 24857710Sbostic break; 24957710Sbostic current = current->below; 25057710Sbostic } 25158315Sbostic sigspecial--; 25258315Sbostic if (sigint_flag && (!sigspecial)) 25358315Sbostic goto point; 25457686Sbostic 25557710Sbostic if (l_Head == NULL) { 25657710Sbostic strcpy(help_msg, "no matches found"); 25757710Sbostic *errnum = -1; 25857686Sbostic #ifdef POSIX 25957710Sbostic current = l_posix_cur; 26057686Sbostic #endif 26157710Sbostic return; 26257710Sbostic } 26357710Sbostic /* if non-interactive, get the command list */ 26458315Sbostic if (GV_flag == 0) { 26558315Sbostic sigspecial++; 26657710Sbostic w_cmd_l_file(l_fp, inputt, errnum); 26758315Sbostic sigspecial--; 26858315Sbostic if (sigint_flag && (!sigspecial)) 26958315Sbostic goto point; 27058315Sbostic } 27157710Sbostic l_gut = l_Head; 27257686Sbostic 27357710Sbostic if (g_flag == 0) 27457710Sbostic u_clr_stk(); 27557686Sbostic 27658315Sbostic sigspecial++; 27757710Sbostic for (;;) { 27857710Sbostic /* 27957710Sbostic * Execute the command list on the lines that still exist that 28057710Sbostic * we indicated earlier that global wants to work with. 28157710Sbostic */ 28258315Sbostic if (sigint_flag && (!sigspecial)) 28357710Sbostic goto point; 28457710Sbostic if (GV_flag == 0) 28557710Sbostic fseek(l_fp, (off_t)0, 0); 28657710Sbostic if (find_line(l_gut->cell)) { 28757710Sbostic current = (l_gut->cell); 28857710Sbostic get_line(current->handle, current->len); 28958315Sbostic if (sigint_flag && (!sigspecial)) 29058315Sbostic goto point; 29157710Sbostic if (GV_flag == 1) 29257710Sbostic printf("%s\n", text); 29357710Sbostic g_flag++; 29457710Sbostic explain_flag--; 29558315Sbostic sigspecial--; 29657710Sbostic cmd_loop(l_fp, errnum); 29758315Sbostic sigspecial++; 29857710Sbostic explain_flag++; 29957710Sbostic g_flag--; 30057710Sbostic if ((GV_flag == 1) && (*errnum < 0)) { 30157710Sbostic ungetc('\n', l_fp); 30257710Sbostic break; 30357710Sbostic } 30457710Sbostic *errnum = 0; 30557710Sbostic if (l_gut == l_Foot) 30657710Sbostic break; 30757710Sbostic l_gut = l_gut->next; 30857710Sbostic } 30957710Sbostic } 31057686Sbostic 31157710Sbostic point: 31257710Sbostic if (GV_flag == 0) { 31357710Sbostic fclose(l_fp); 31457710Sbostic unlink(l_template_g); 31557710Sbostic } 316*58316Sbostic else 317*58316Sbostic ungetc('\n', inputt); 318*58316Sbostic 31957710Sbostic GV_flag = 0; 32057686Sbostic clean: 32157710Sbostic /* clean up */ 32257710Sbostic l_gut = l_Head; 32357710Sbostic while (1) { 32457710Sbostic if (l_gut == NULL) 32557710Sbostic break; 32657710Sbostic l_old = l_gut; 32757710Sbostic l_gut = l_gut->next; 32857710Sbostic free(l_old); 32957710Sbostic } 33057686Sbostic #ifdef POSIX 33157710Sbostic current = l_posix_cur; 33257686Sbostic #endif 33358315Sbostic sigspecial--; 33458315Sbostic if (sigint_flag && (!sigspecial)) 33558315Sbostic SIGINT_ACTION; 33657710Sbostic } 337