1 /* This file is part of GNU tar.
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 2, or (at your option) any later
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
28 transform_type = transform_none;
30 static struct obstack stk;
32 enum replace_segm_type
34 segm_literal, /* Literal segment */
35 segm_backref, /* Back-reference segment */
40 struct replace_segm *next;
41 enum replace_segm_type type;
53 static struct replace_segm *repl_head, *repl_tail;
56 static struct replace_segm *
59 struct replace_segm *segm = xmalloc (sizeof *segm);
62 repl_tail->next = segm;
71 add_literal_segment (char *str, char *end)
73 size_t len = end - str;
76 struct replace_segm *segm = add_segment ();
77 segm->type = segm_literal;
78 segm->v.literal.ptr = xmalloc (len + 1);
79 memcpy (segm->v.literal.ptr, str, len);
80 segm->v.literal.ptr[len] = 0;
81 segm->v.literal.size = len;
86 add_char_segment (int chr)
88 struct replace_segm *segm = add_segment ();
89 segm->type = segm_literal;
90 segm->v.literal.ptr = xmalloc (2);
91 segm->v.literal.ptr[0] = chr;
92 segm->v.literal.ptr[1] = 0;
93 segm->v.literal.size = 2;
97 add_backref_segment (size_t ref)
99 struct replace_segm *segm = add_segment ();
100 segm->type = segm_backref;
105 set_transform_expr (const char *expr)
109 char *str, *beg, *cur;
113 if (transform_type == transform_none)
117 /* Redefinition of the transform expression */
122 USAGE_ERROR ((0, 0, _("Invalid transform expression")));
126 /* Scan regular expression */
127 for (i = 2; expr[i] && expr[i] != delim; i++)
128 if (expr[i] == '\\' && expr[i+1])
131 if (expr[i] != delim)
132 USAGE_ERROR ((0, 0, _("Invalid transform expression")));
134 /* Scan replacement expression */
135 for (j = i + 1; expr[j] && expr[j] != delim; j++)
136 if (expr[j] == '\\' && expr[j+1])
139 if (expr[j] != delim)
140 USAGE_ERROR ((0, 0, _("Invalid transform expression")));
143 transform_type = transform_first;
144 for (p = expr + j + 1; *p; p++)
148 transform_type = transform_global;
156 cflags |= REG_EXTENDED;
160 USAGE_ERROR ((0, 0, _("Unknown flag in transform expression")));
163 /* Extract and compile regex */
164 str = xmalloc (i - 1);
165 memcpy (str, expr + 2, i - 2);
168 rc = regcomp (®ex, str, cflags);
173 regerror (rc, ®ex, errbuf, sizeof (errbuf));
174 USAGE_ERROR ((0, 0, _("Invalid transform expression: %s"), errbuf));
177 if (str[0] == '^' || str[strlen (str) - 1] == '$')
178 transform_type = transform_first;
182 /* Extract and compile replacement expr */
184 str = xmalloc (j - i + 1);
185 memcpy (str, expr + i, j - i);
188 for (cur = beg = str; *cur;)
194 add_literal_segment (beg, cur);
197 case '0': case '1': case '2': case '3': case '4':
198 case '5': case '6': case '7': case '8': case '9':
199 n = strtoul (cur, &cur, 10);
200 if (n > regex.re_nsub)
201 USAGE_ERROR ((0, 0, _("Invalid transform replacement: back reference out of range")));
202 add_backref_segment (n);
206 add_char_segment ('\\');
211 add_char_segment ('\a');
216 add_char_segment ('\b');
221 add_char_segment ('\f');
226 add_char_segment ('\n');
231 add_char_segment ('\r');
236 add_char_segment ('\t');
241 add_char_segment ('\v');
246 add_char_segment ('&');
256 add_literal_segment (buf, buf + 2);
263 else if (*cur == '&')
265 add_literal_segment (beg, cur);
266 add_backref_segment (0);
272 add_literal_segment (beg, cur);
277 _transform_name_to_obstack (char *input)
283 if (transform_type == transform_none)
286 rmp = xmalloc ((regex.re_nsub + 1) * sizeof (*rmp));
292 rc = regexec (®ex, input, regex.re_nsub + 1, rmp, 0);
296 struct replace_segm *segm;
301 obstack_grow (&stk, input, rmp[0].rm_so);
303 for (segm = repl_head; segm; segm = segm->next)
307 case segm_literal: /* Literal segment */
308 obstack_grow (&stk, segm->v.literal.ptr,
309 segm->v.literal.size);
312 case segm_backref: /* Back-reference segment */
313 if (rmp[segm->v.ref].rm_so != -1
314 && rmp[segm->v.ref].rm_eo != -1)
316 input + rmp[segm->v.ref].rm_so,
317 rmp[segm->v.ref].rm_eo - rmp[segm->v.ref].rm_so);
324 disp = strlen (input);
325 obstack_grow (&stk, input, disp);
330 if (transform_type == transform_first)
332 obstack_grow (&stk, input, strlen (input));
337 obstack_1grow (&stk, 0);
343 transform_name_fp (char **pinput, char *(*fun)(char *))
346 bool ret = _transform_name_to_obstack (*pinput);
349 str = obstack_finish (&stk);
350 assign_string (pinput, fun ? fun (str) : str);
351 obstack_free (&stk, str);
357 transform_name (char **pinput)
359 return transform_name_fp (pinput, NULL);
364 read_and_transform_loop ()
367 while (fgets (buf, sizeof buf, stdin))
369 char *p = buf + strlen (buf);
372 if (transform_name (buf, &p))
373 printf ("=> %s\n", p);