xref: /csrg-svn/contrib/ed/sub.c (revision 57705)
1*57705Sbostic /*-
2*57705Sbostic  * Copyright (c) 1992 The Regents of the University of California.
3*57705Sbostic  * All rights reserved.
4*57705Sbostic  *
5*57705Sbostic  * This code is derived from software contributed to Berkeley by
6*57705Sbostic  * Rodney Ruddock of the University of Guelph.
7*57705Sbostic  *
8*57705Sbostic  * %sccs.include.redist.c%
9*57705Sbostic  */
10*57705Sbostic 
11*57705Sbostic #ifndef lint
12*57705Sbostic static char sccsid[] = "@(#)sub.c	5.1 (Berkeley) 01/23/93";
13*57705Sbostic #endif /* not lint */
14*57705Sbostic 
15*57705Sbostic #include "ed.h"
16*57705Sbostic 
17*57705Sbostic /*
18*57705Sbostic  * The substitute command. It's big because of the backward compatability.
19*57705Sbostic  */
20*57705Sbostic 
21*57705Sbostic void
22*57705Sbostic s(inputt, errnum)
23*57705Sbostic 
24*57705Sbostic FILE *inputt;
25*57705Sbostic int *errnum;
26*57705Sbostic 
27*57705Sbostic {
28*57705Sbostic   static int l_count2=1, l_global=0, l_print=0, l_first_pass_flag=0;
29*57705Sbostic   static char *l_match=NULL, *l_repl=NULL;
30*57705Sbostic   int l_s_flag, l_count, l_matched, l_nflag, l_cnt, yy, l_sr_flag=0, l_err, l_sl;
31*57705Sbostic   char *l_match2=NULL, *l_local=NULL, *l_local_temp=NULL;
32*57705Sbostic   LINE *l_s_ret, *l_temp_line, *l_temp_line2, *l_kval, *l_last;
33*57705Sbostic #ifndef REG_STARTEND
34*57705Sbostic   size_t l_offset=0;
35*57705Sbostic #endif
36*57705Sbostic 
37*57705Sbostic   if (start_default && End_default)
38*57705Sbostic     start = End = current;
39*57705Sbostic   else if (start_default)
40*57705Sbostic     start = End;
41*57705Sbostic   if (start == NULL)
42*57705Sbostic     {
43*57705Sbostic       *errnum = -1;
44*57705Sbostic       return;
45*57705Sbostic     }
46*57705Sbostic   start_default = End_default = 0;
47*57705Sbostic 
48*57705Sbostic   l_sl = ss = getc(inputt);
49*57705Sbostic    if (l_first_pass_flag == 0)
50*57705Sbostic     l_match = l_repl = NULL;
51*57705Sbostic   l_match2 = get_pattern(l_sl, inputt, errnum, 0);
52*57705Sbostic   if (sigint_flag)
53*57705Sbostic     SIGINT_ACTION;
54*57705Sbostic   if (*errnum < 0)
55*57705Sbostic     {
56*57705Sbostic       if ((*errnum == -2) && (l_sl != '\n'))
57*57705Sbostic         return;
58*57705Sbostic       if ((l_match2 == NULL) || (strlen(l_match2) > 4) || (l_first_pass_flag == 0))
59*57705Sbostic         return;
60*57705Sbostic       *errnum = 0;
61*57705Sbostic       l_sr_flag = -1;
62*57705Sbostic       for (yy=0; yy<(strlen(l_match2)); yy++)
63*57705Sbostic          {
64*57705Sbostic            switch (l_match2[yy])
65*57705Sbostic                  {
66*57705Sbostic                    case '\n': ss = getc(inputt);
67*57705Sbostic                               goto bcg1;
68*57705Sbostic                               break;
69*57705Sbostic                    case 'r': l_sr_flag = 1;
70*57705Sbostic                              break;
71*57705Sbostic                    case 'p': l_print = (l_print)?0:1;
72*57705Sbostic                              break;
73*57705Sbostic                    case 'g': l_global = (l_global)?0:1;
74*57705Sbostic                              break;
75*57705Sbostic                    case 'N': l_count2 = 1;
76*57705Sbostic                              break;
77*57705Sbostic                    default: *errnum = -1;
78*57705Sbostic                             strcpy(help_msg, "illegal modifier to s");
79*57705Sbostic                             return;
80*57705Sbostic                  } /* end-switch */
81*57705Sbostic          } /* end-for */
82*57705Sbostic       ss = getc(inputt);
83*57705Sbostic       if (l_sr_flag == 1)
84*57705Sbostic         goto bcg2;
85*57705Sbostic       else
86*57705Sbostic         goto bcg1;
87*57705Sbostic     }
88*57705Sbostic 
89*57705Sbostic   if (l_first_pass_flag)
90*57705Sbostic     {
91*57705Sbostic       free(l_match);
92*57705Sbostic       free(l_repl);
93*57705Sbostic     }
94*57705Sbostic   else
95*57705Sbostic       l_first_pass_flag = 1;
96*57705Sbostic   l_match = l_match2;
97*57705Sbostic   *errnum = 0;
98*57705Sbostic   l_repl = get_pattern(ss, inputt, errnum, 1);
99*57705Sbostic   if (sigint_flag)
100*57705Sbostic     SIGINT_ACTION;
101*57705Sbostic   l_global = l_print = 0;
102*57705Sbostic   if (*errnum < 0)
103*57705Sbostic     {
104*57705Sbostic       if ((*errnum == -1) && (ss == '\n'))
105*57705Sbostic           l_print = (int)1; /* note: \n still in stream for next getc */
106*57705Sbostic       else
107*57705Sbostic         return;
108*57705Sbostic     }
109*57705Sbostic   *errnum = 0;
110*57705Sbostic 
111*57705Sbostic   l_count2 = 1;
112*57705Sbostic 
113*57705Sbostic   while (((ss=getc(inputt)) != '\n') && (ss != EOF))
114*57705Sbostic        {
115*57705Sbostic          if (ss == 'g')
116*57705Sbostic            l_global = 1;
117*57705Sbostic          else if (ss == 'p')
118*57705Sbostic            l_print = (l_print | (int)1);
119*57705Sbostic          else if (ss == 'n')
120*57705Sbostic            l_print = (l_print | (int)2);
121*57705Sbostic          else if (ss == 'l')
122*57705Sbostic            l_print = (l_print | (int)4);
123*57705Sbostic          else if ((ss > ('0'-1)) && (ss < ('9'+1)))
124*57705Sbostic              l_count2 = dig_num_conv(inputt, errnum);
125*57705Sbostic          else
126*57705Sbostic            {
127*57705Sbostic              *errnum = -1;
128*57705Sbostic              strcpy(help_msg, "illegal command option");
129*57705Sbostic              return;
130*57705Sbostic            }
131*57705Sbostic        }
132*57705Sbostic 
133*57705Sbostic bcg1:
134*57705Sbostic   if ((RE_flag == 0) && (l_match[1] == '\0'))
135*57705Sbostic     {
136*57705Sbostic       *errnum = -1;
137*57705Sbostic       ungetc(ss, inputt);
138*57705Sbostic       return;
139*57705Sbostic     }
140*57705Sbostic   else if ((l_sr_flag == 0) && (l_match[1] || (RE_patt == NULL)))
141*57705Sbostic     {
142*57705Sbostic       free(RE_patt);
143*57705Sbostic       RE_patt = (char *)malloc(sizeof(char)*(2+strlen(l_match)));
144*57705Sbostic       bcopy(l_match, RE_patt);
145*57705Sbostic     }
146*57705Sbostic   RE_sol = (l_match[1] == '^')?1:0;
147*57705Sbostic   if ((l_match[1]) && (regfree(&RE_comp), l_err = regcomp(&RE_comp, &l_match[1], 0)))
148*57705Sbostic     {
149*57705Sbostic       regerror(l_err, &RE_comp, help_msg, 128);
150*57705Sbostic       *errnum = -1;
151*57705Sbostic       RE_flag = 0;
152*57705Sbostic       ungetc(ss, inputt);
153*57705Sbostic       return;
154*57705Sbostic     }
155*57705Sbostic   RE_flag = 1;
156*57705Sbostic   if (sigint_flag)
157*57705Sbostic     SIGINT_ACTION;
158*57705Sbostic bcg2:
159*57705Sbostic   current = start;
160*57705Sbostic   l_s_flag = 0;
161*57705Sbostic   do
162*57705Sbostic     {
163*57705Sbostic       if (sigint_flag)
164*57705Sbostic         SIGINT_ACTION;
165*57705Sbostic       RE_match[0].rm_eo = 0;
166*57705Sbostic       get_line(current->handle, current->len);
167*57705Sbostic       l_count = l_count2;
168*57705Sbostic       l_local = text;
169*57705Sbostic #ifndef REG_STARTEND
170*57705Sbostic       l_offset = 0;
171*57705Sbostic #endif
172*57705Sbostic       do
173*57705Sbostic         {
174*57705Sbostic           RE_match[0].rm_so = RE_match[0].rm_eo;
175*57705Sbostic #ifdef REG_STARTEND
176*57705Sbostic           l_matched = regexec_n(&RE_comp, l_local, (size_t)RE_SEC, RE_match, 0, l_count, (size_t)current->len, 0);
177*57705Sbostic #else
178*57705Sbostic           l_matched = regexec_n(&RE_comp, l_local, (size_t)RE_SEC, RE_match, 0, l_count, &l_offset, 0);
179*57705Sbostic #endif
180*57705Sbostic           if (l_matched == 0)
181*57705Sbostic             {
182*57705Sbostic               if ((l_s_flag == 0) && (g_flag == 0))
183*57705Sbostic                 u_clr_stk();
184*57705Sbostic               l_count = l_s_flag = 1;
185*57705Sbostic               /* the l_local passed into re_replace is not freed in re_replace
186*57705Sbostic                * because it is "text", the global line holder, for the first
187*57705Sbostic                * pass through this loop. The value returned by re_replace is
188*57705Sbostic                * a new string (with the first replacement in it). If the 'g'
189*57705Sbostic                * flag was set with substitute then this new string is passed in
190*57705Sbostic                * for the second pass and can be freed once re_replace is done
191*57705Sbostic                * with it. (...and so on for the rest of the 'g' passes.
192*57705Sbostic                * RE_match[0].rm_eo is changed in re_replace to be the
193*57705Sbostic                * new location of the next character immediately after
194*57705Sbostic                * the replacement since it is likely the position of that
195*57705Sbostic                * character has changed because of the replacement.
196*57705Sbostic                */
197*57705Sbostic #ifdef REG_STARTEND
198*57705Sbostic               l_local = re_replace(l_local, (size_t)(RE_SEC-1), RE_match, &l_repl[1]);
199*57705Sbostic #else
200*57705Sbostic               l_local = re_replace(l_local, (size_t)(RE_SEC-1), RE_match, &l_repl[1], l_offset);
201*57705Sbostic #endif
202*57705Sbostic             }
203*57705Sbostic           if (l_global == 0)
204*57705Sbostic             break;
205*57705Sbostic           if (l_local[RE_match[0].rm_eo] == '\0')
206*57705Sbostic             break;
207*57705Sbostic         } while (!l_matched);
208*57705Sbostic 
209*57705Sbostic       l_cnt = l_nflag = 0;
210*57705Sbostic       l_kval = current;
211*57705Sbostic       l_temp_line = current->above;
212*57705Sbostic       l_temp_line2 = current->below;
213*57705Sbostic       l_local_temp = l_local;
214*57705Sbostic       while (1)
215*57705Sbostic            {
216*57705Sbostic              /* make the new string the one for this line. Check if
217*57705Sbostic               * it needs to be split.
218*57705Sbostic               */
219*57705Sbostic              if ((l_local[l_cnt] == '\n') || (l_local[l_cnt] == '\0'))
220*57705Sbostic                {
221*57705Sbostic                  if (l_local[l_cnt] == '\0')
222*57705Sbostic                    l_nflag = 1;
223*57705Sbostic                  l_local[l_cnt] = '\0';
224*57705Sbostic                  l_s_ret = (LINE *)malloc(sizeof(LINE));
225*57705Sbostic                  if (l_s_ret == NULL)
226*57705Sbostic                    {
227*57705Sbostic                      *errnum = -1;
228*57705Sbostic                      strcpy(help_msg, "out of memory error");
229*57705Sbostic                      return;
230*57705Sbostic                    }
231*57705Sbostic                  (l_s_ret->len) = strlen(l_local);
232*57705Sbostic                  (l_s_ret->handle) = add_line(l_local, l_s_ret->len);
233*57705Sbostic                  (l_s_ret->above) = l_temp_line;
234*57705Sbostic                  (l_s_ret->below) = NULL;
235*57705Sbostic                  if (l_temp_line == NULL)
236*57705Sbostic                    top = l_s_ret;
237*57705Sbostic                  else
238*57705Sbostic                    {
239*57705Sbostic                      u_add_stk(&(l_temp_line->below));
240*57705Sbostic                      (l_temp_line->below) = l_s_ret;
241*57705Sbostic                    }
242*57705Sbostic                  l_temp_line = l_s_ret;
243*57705Sbostic                  if ((l_local[l_cnt] == '\0') && (l_nflag == 1))
244*57705Sbostic                    break;
245*57705Sbostic                  else
246*57705Sbostic                    {
247*57705Sbostic                      l_local = &(l_local[l_cnt+1]);
248*57705Sbostic                      l_cnt = 0;
249*57705Sbostic                    }
250*57705Sbostic                } /* end-if */
251*57705Sbostic              else
252*57705Sbostic                l_cnt++;
253*57705Sbostic            } /* end-while */
254*57705Sbostic       (l_s_ret->below) = l_temp_line2;
255*57705Sbostic       ku_chk(current, current, l_kval->below);
256*57705Sbostic       if (current == End)
257*57705Sbostic         End = l_s_ret;
258*57705Sbostic       current = l_s_ret;
259*57705Sbostic       l_last = current;
260*57705Sbostic       if (l_temp_line2 == NULL)
261*57705Sbostic         bottom = l_s_ret;
262*57705Sbostic       else
263*57705Sbostic         {
264*57705Sbostic           u_add_stk(&(l_temp_line2->above));
265*57705Sbostic           (l_temp_line2->above) = current;
266*57705Sbostic         }
267*57705Sbostic       if (l_local_temp != text)
268*57705Sbostic         free(l_local_temp);
269*57705Sbostic       current = current->below;
270*57705Sbostic     } while (current != (End->below));
271*57705Sbostic 
272*57705Sbostic   if (l_s_flag == 0)
273*57705Sbostic     {
274*57705Sbostic       current = start;
275*57705Sbostic       strcpy(help_msg, "no matches found for substitution");
276*57705Sbostic       *errnum = -1;
277*57705Sbostic       ungetc('\n', inputt);
278*57705Sbostic       return;
279*57705Sbostic     }
280*57705Sbostic 
281*57705Sbostic   change_flag = 1;
282*57705Sbostic   current = l_last;
283*57705Sbostic 
284*57705Sbostic   if (l_print > 0)
285*57705Sbostic     {
286*57705Sbostic       start = End = current;
287*57705Sbostic       ungetc(ss, inputt);
288*57705Sbostic       if (l_print == (l_print | (int)1))
289*57705Sbostic         p(inputt, errnum, 0);
290*57705Sbostic       if (l_print == (l_print | (int)2))
291*57705Sbostic         p(inputt, errnum, 1);
292*57705Sbostic       if (l_print == (l_print | (int)4))
293*57705Sbostic         l(inputt, errnum);
294*57705Sbostic       if (*errnum < 0)
295*57705Sbostic         return;
296*57705Sbostic     }
297*57705Sbostic 
298*57705Sbostic   if (l_sr_flag == -1)
299*57705Sbostic     {
300*57705Sbostic       regfree(&RE_comp);
301*57705Sbostic       regcomp(&RE_comp, &RE_patt[1], 0);
302*57705Sbostic     }
303*57705Sbostic   *errnum = 1;
304*57705Sbostic } /* end-s */
305