157686Sbostic /*-
2*60663Sbostic * Copyright (c) 1992, 1993
3*60663Sbostic * The Regents of the University of California. 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*60663Sbostic static char sccsid[] = "@(#)g.c 8.1 (Berkeley) 05/31/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
find_line(dot)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 */
6259475Sbostic
6358315Sbostic static void
w_cmd_l_file(fp,inputt,errnum)6457686Sbostic w_cmd_l_file(fp, inputt, errnum)
6557710Sbostic FILE *fp, *inputt;
6657710Sbostic int *errnum;
6757686Sbostic {
6859475Sbostic int sl=0, jmp_flag, l_cnt=0;
6957686Sbostic
7059475Sbostic if (jmp_flag = setjmp(ctrl_position3))
7159475Sbostic return;
7259475Sbostic
7357710Sbostic for (;;) {
7459475Sbostic sigspecial3 = 1;
7557710Sbostic ss = getc(inputt);
7659475Sbostic sigspecial3 = 0;
7759475Sbostic skip1:
7859475Sbostic if (ss == EOF)
7959475Sbostic goto skip2;
8059475Sbostic else if (ss == '\n') {
8159475Sbostic if (sl != '\\') {
8259475Sbostic skip2:
8359475Sbostic if (l_cnt == 0)
8459475Sbostic fputc('p', fp);
8559475Sbostic else
8659475Sbostic fputc(sl, fp);
8759475Sbostic break;
8859475Sbostic }
8957710Sbostic }
9059475Sbostic else if ((ss == '\\') && (sl == '\\')) {
9159475Sbostic sigspecial3 = 1;
9259475Sbostic sl = getc(inputt);
9359475Sbostic sigspecial3 = 0;
9459475Sbostic if (sl == '\\') {
9559475Sbostic sigspecial3 = 1;
9659475Sbostic sl = getc(inputt);
9759475Sbostic sigspecial3 = 0;
9859475Sbostic if (sl == EOF)
9959475Sbostic goto skip2;
10059475Sbostic if (sl == '\n') {
10159475Sbostic fputc('\\', fp);
10259475Sbostic ss = sl;
10359475Sbostic }
10459475Sbostic else {
10559475Sbostic fputc('\\', fp);
10659475Sbostic fputc('\\', fp);
10759475Sbostic ss = sl;
10859475Sbostic sl = '\\';
10959475Sbostic goto skip1;
11059475Sbostic }
11159475Sbostic }
11259475Sbostic else {
11359475Sbostic fputc('\\', fp);
11459475Sbostic fputc('\\', fp);
11559475Sbostic if ((sl == '\n') || (sl == EOF))
11659475Sbostic goto skip2;
11759475Sbostic else
11859475Sbostic ss = sl;
11959475Sbostic }
12057710Sbostic }
12159475Sbostic else if (l_cnt)
12259475Sbostic fputc(sl, fp);
12359475Sbostic sl = ss;
12457710Sbostic l_cnt++;
12557710Sbostic }
12659558Sbostic
12759558Sbostic fputc('\n', fp);
12857710Sbostic if (ss == EOF)
12957710Sbostic clearerr(inputt);
13057710Sbostic }
13157686Sbostic
13259475Sbostic
13357686Sbostic /*
13457686Sbostic * The global function. All global commands (g, G, v, and V) are handled
13557686Sbostic * in here. The lines to be affected by the command list are 1st noted
13657686Sbostic * and then the command list is invoked for each line matching the RE.
13757686Sbostic * Note the trick of how the command list is executed. Saves a lot of
13857686Sbostic * code (and allows for \n's in substitutions).
13957686Sbostic */
14057686Sbostic void
g(inputt,errnum)14157686Sbostic g(inputt, errnum)
14257710Sbostic FILE *inputt;
14357710Sbostic int *errnum;
14457686Sbostic {
14557710Sbostic static char *l_template_g;
14659915Sbostic char *l_patt;
14757710Sbostic static int l_template_flag = 0;
14859475Sbostic int l_re_success, l_flag_v = 0, l_err, l_num;
14959475Sbostic register l_gut_cnt, a;
15059475Sbostic register LINE **l_gut=gut;
15157710Sbostic FILE *l_fp;
15257686Sbostic #ifdef POSIX
15357710Sbostic LINE *l_posix_cur;
15457686Sbostic #endif
15557686Sbostic
15658564Sralph if (Start_default && End_default) {
15758564Sralph Start = top;
15857710Sbostic End = bottom;
15957710Sbostic } else
16058564Sralph if (Start_default)
16158564Sralph Start = End;
16258564Sralph if (Start == NULL) {
16358315Sbostic strcpy(help_msg, "buffer empty");
16457710Sbostic *errnum = -1;
16557710Sbostic return;
16657710Sbostic }
16757686Sbostic
16857710Sbostic if (l_template_flag == 0) {
16958315Sbostic sigspecial++;
17057710Sbostic l_template_flag = 1;
17157710Sbostic l_template_g = calloc(FILENAME_LEN, sizeof(char));
17258315Sbostic sigspecial--;
17358315Sbostic if (sigint_flag && (!sigspecial))
17458315Sbostic SIGINT_ACTION;
17557710Sbostic if (l_template_g == NULL) {
17657710Sbostic *errnum = -1;
17757710Sbostic strcpy(help_msg, "out of memory error");
17857710Sbostic return;
17957710Sbostic }
18057710Sbostic }
18157710Sbostic /* set up the STDIO command list file */
18259482Sbostic memmove(l_template_g, "/tmp/_4.4bsd_ed_g_XXXXXX\0", 24);
18357710Sbostic mktemp(l_template_g);
18457686Sbostic
18557710Sbostic if ((ss == 'v') || (ss == 'V'))
18657710Sbostic l_flag_v = 1;
18757686Sbostic
18857710Sbostic if ((ss == 'G') || (ss == 'V')) {
18957710Sbostic /*
19057710Sbostic * If it's an interactive global command we use stdin, not a
19157710Sbostic * file.
19257710Sbostic */
19357710Sbostic GV_flag = 1;
19457710Sbostic l_fp = stdin;
19557710Sbostic } else {
19658315Sbostic sigspecial++;
19757710Sbostic if ((l_fp = fopen(l_template_g, "w+")) == NULL) {
19858315Sbostic perror("ed: file I/O error, save buffer in ed.hup");
19958315Sbostic do_hup(); /* does not return */
20058710Sbostic }
20158315Sbostic sigspecial--;
20258315Sbostic if (sigint_flag && (!sigspecial))
20358315Sbostic goto point;
20457710Sbostic }
20557686Sbostic
20657710Sbostic ss = getc(inputt);
20757686Sbostic
20857710Sbostic /* Get the RE for the global command. */
20957710Sbostic l_patt = get_pattern(ss, inputt, errnum, 0);
21058315Sbostic
21157710Sbostic /* Instead of: if ((*errnum == -1) && (ss == '\n'))... */
21257710Sbostic if (*errnum < -1)
21357710Sbostic return;
21457710Sbostic *errnum = 0;
21557710Sbostic if ((l_patt[1] == '\0') && (RE_flag == 0)) {
21657710Sbostic *errnum = -1;
21757710Sbostic ungetc(ss, inputt);
21857710Sbostic return;
21957710Sbostic } else
22057710Sbostic if (l_patt[1] || (RE_patt == NULL)) {
22158315Sbostic sigspecial++;
22257710Sbostic free(RE_patt);
22357710Sbostic RE_patt = l_patt;
22458315Sbostic sigspecial--;
22558315Sbostic if (sigint_flag && (!sigspecial))
22658315Sbostic goto point;
22757710Sbostic }
22857710Sbostic RE_sol = (RE_patt[1] == '^') ? 1 : 0;
22957710Sbostic if ((RE_patt[1]) &&
23057710Sbostic (regfree(&RE_comp), l_err = regcomp(&RE_comp, &RE_patt[1], 0))) {
23157710Sbostic regerror(l_err, &RE_comp, help_msg, 128);
23257710Sbostic *errnum = -1;
23357710Sbostic RE_flag = 0;
23457710Sbostic ungetc(ss, inputt);
23557710Sbostic return;
23657710Sbostic }
23757710Sbostic RE_flag = 1;
23858315Sbostic
23958315Sbostic if (GV_flag)
24058315Sbostic ss = getc(inputt);
24158315Sbostic
24257686Sbostic #ifdef POSIX
24357710Sbostic l_posix_cur = current;
24457686Sbostic #endif
24558564Sralph current = Start;
24657686Sbostic
24758315Sbostic sigspecial++;
24858315Sbostic
24959475Sbostic if ((l_num = line_number(bottom)) > gut_num) {
25059475Sbostic sigspecial++;
25159475Sbostic gut_num = l_num + 512;
25259475Sbostic free(l_gut);
25359558Sbostic gut = l_gut = malloc(sizeof(LINE **) * gut_num);
25459475Sbostic sigspecial--;
25559475Sbostic if (l_gut == NULL) {
25659475Sbostic *errnum = -1;
25759475Sbostic strcpy(help_msg, "out of memory error");
25859475Sbostic #ifdef POSIX
25959475Sbostic current = l_posix_cur;
26059475Sbostic #endif
26159558Sbostic ungetc('\n', inputt);
26259475Sbostic return;
26359475Sbostic }
26459475Sbostic }
26559475Sbostic l_gut_cnt = 0;
26659475Sbostic
26757710Sbostic for (;;) {
26857710Sbostic /*
26957710Sbostic * Find the lines in the buffer that the global command wants
27057710Sbostic * to work with.
27157710Sbostic */
27257710Sbostic get_line(current->handle, current->len);
27358315Sbostic if (sigint_flag && (!sigspecial))
27458315Sbostic goto point;
27557710Sbostic l_re_success =
27657710Sbostic regexec(&RE_comp, text, (size_t) RE_SEC, RE_match, 0);
27757710Sbostic /* l_re_success=0 => success */
27859475Sbostic if ( (l_re_success == 0 && l_flag_v == 0) ||
27959475Sbostic (l_re_success && l_flag_v)) {
28059475Sbostic l_gut[l_gut_cnt++] = current;
28157710Sbostic }
28257710Sbostic if (End == current)
28357710Sbostic break;
28457710Sbostic current = current->below;
28557710Sbostic }
28658315Sbostic sigspecial--;
28758315Sbostic if (sigint_flag && (!sigspecial))
28858315Sbostic goto point;
28957686Sbostic
29059475Sbostic if (l_gut_cnt == 0) {
29157710Sbostic strcpy(help_msg, "no matches found");
29257686Sbostic #ifdef POSIX
29357710Sbostic current = l_posix_cur;
29457686Sbostic #endif
29557710Sbostic return;
29657710Sbostic }
29757710Sbostic /* if non-interactive, get the command list */
29858315Sbostic if (GV_flag == 0) {
29958315Sbostic sigspecial++;
30057710Sbostic w_cmd_l_file(l_fp, inputt, errnum);
30158315Sbostic sigspecial--;
30259475Sbostic if (sigint_flag)
30358315Sbostic goto point;
30458315Sbostic }
30557686Sbostic
30657710Sbostic if (g_flag == 0)
30757710Sbostic u_clr_stk();
30857686Sbostic
30958315Sbostic sigspecial++;
31059475Sbostic for (a=0; a<l_gut_cnt; a++) {
31157710Sbostic /*
31257710Sbostic * Execute the command list on the lines that still exist that
31357710Sbostic * we indicated earlier that global wants to work with.
31457710Sbostic */
31559475Sbostic if (sigint_flag)
31657710Sbostic goto point;
31757710Sbostic if (GV_flag == 0)
31857710Sbostic fseek(l_fp, (off_t)0, 0);
31959475Sbostic if (find_line(l_gut[a])) {
32059475Sbostic current = (l_gut[a]);
32157710Sbostic get_line(current->handle, current->len);
32259475Sbostic if (sigint_flag)
32358315Sbostic goto point;
32457710Sbostic if (GV_flag == 1)
32557710Sbostic printf("%s\n", text);
32657710Sbostic g_flag++;
32757710Sbostic explain_flag--;
32858315Sbostic sigspecial--;
32957710Sbostic cmd_loop(l_fp, errnum);
33058315Sbostic sigspecial++;
33157710Sbostic explain_flag++;
33257710Sbostic g_flag--;
33357710Sbostic if ((GV_flag == 1) && (*errnum < 0)) {
33457710Sbostic ungetc('\n', l_fp);
33557710Sbostic break;
33657710Sbostic }
33757710Sbostic *errnum = 0;
33857710Sbostic }
33957710Sbostic }
34057686Sbostic
34157710Sbostic point:
34257710Sbostic if (GV_flag == 0) {
34357710Sbostic fclose(l_fp);
34457710Sbostic unlink(l_template_g);
34557710Sbostic }
34658316Sbostic else
34758316Sbostic ungetc('\n', inputt);
34858316Sbostic
34957710Sbostic GV_flag = 0;
35059475Sbostic
35157686Sbostic #ifdef POSIX
35257710Sbostic current = l_posix_cur;
35357686Sbostic #endif
35458315Sbostic sigspecial--;
35559475Sbostic if (sigint_flag)
35658315Sbostic SIGINT_ACTION;
35757710Sbostic }
358