1 /* This file is part of GNU tar.
2 Copyright 2006-2023 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 3, 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, see <http://www.gnu.org/licenses/>. */
27 enum replace_segm_type
29 segm_literal
, /* Literal segment */
30 segm_backref
, /* Back-reference segment */
31 segm_case_ctl
/* Case control segment (GNU extension) */
36 ctl_stop
, /* Stop case conversion */
37 ctl_upcase_next
,/* Turn the next character to uppercase */
38 ctl_locase_next
,/* Turn the next character to lowercase */
39 ctl_upcase
, /* Turn the replacement to uppercase until ctl_stop */
40 ctl_locase
/* Turn the replacement to lowercase until ctl_stop */
45 struct replace_segm
*next
;
46 enum replace_segm_type type
;
53 } literal
; /* type == segm_literal */
54 size_t ref
; /* type == segm_backref */
55 enum case_ctl_type ctl
; /* type == segm_case_ctl */
61 struct transform
*next
;
62 enum transform_type transform_type
;
64 unsigned match_number
;
66 /* Compiled replacement expression */
67 struct replace_segm
*repl_head
, *repl_tail
;
68 size_t segm_count
; /* Number of elements in the above list */
73 static int transform_flags
= XFORM_ALL
;
74 static struct transform
*transform_head
, *transform_tail
;
76 static struct transform
*
79 struct transform
*p
= xzalloc (sizeof *p
);
81 transform_tail
->next
= p
;
88 static struct replace_segm
*
89 add_segment (struct transform
*tf
)
91 struct replace_segm
*segm
= xmalloc (sizeof *segm
);
94 tf
->repl_tail
->next
= segm
;
103 add_literal_segment (struct transform
*tf
, const char *str
, const char *end
)
105 size_t len
= end
- str
;
108 struct replace_segm
*segm
= add_segment (tf
);
109 segm
->type
= segm_literal
;
110 segm
->v
.literal
.ptr
= xmalloc (len
+ 1);
111 memcpy (segm
->v
.literal
.ptr
, str
, len
);
112 segm
->v
.literal
.ptr
[len
] = 0;
113 segm
->v
.literal
.size
= len
;
118 add_char_segment (struct transform
*tf
, int chr
)
120 struct replace_segm
*segm
= add_segment (tf
);
121 segm
->type
= segm_literal
;
122 segm
->v
.literal
.ptr
= xmalloc (2);
123 segm
->v
.literal
.ptr
[0] = chr
;
124 segm
->v
.literal
.ptr
[1] = 0;
125 segm
->v
.literal
.size
= 1;
129 add_backref_segment (struct transform
*tf
, size_t ref
)
131 struct replace_segm
*segm
= add_segment (tf
);
132 segm
->type
= segm_backref
;
137 parse_xform_flags (int *pflags
, int c
)
142 *pflags
|= XFORM_REGFILE
;
146 *pflags
&= ~XFORM_REGFILE
;
150 *pflags
|= XFORM_LINK
;
154 *pflags
&= ~XFORM_LINK
;
158 *pflags
|= XFORM_SYMLINK
;
162 *pflags
&= ~XFORM_SYMLINK
;
172 add_case_ctl_segment (struct transform
*tf
, enum case_ctl_type ctl
)
174 struct replace_segm
*segm
= add_segment (tf
);
175 segm
->type
= segm_case_ctl
;
180 parse_transform_expr (const char *expr
)
184 char *str
, *beg
, *cur
;
187 struct transform
*tf
= new_transform ();
191 if (strncmp (expr
, "flags=", 6) == 0)
194 for (expr
+= 6; *expr
; expr
++)
201 if (parse_xform_flags (&transform_flags
, *expr
))
202 USAGE_ERROR ((0, 0, _("Unknown transform flag: %c"),
207 USAGE_ERROR ((0, 0, _("Invalid transform expression")));
212 USAGE_ERROR ((0, 0, _("Invalid transform expression")));
214 /* Scan regular expression */
215 for (i
= 2; expr
[i
] && expr
[i
] != delim
; i
++)
216 if (expr
[i
] == '\\' && expr
[i
+1])
219 if (expr
[i
] != delim
)
220 USAGE_ERROR ((0, 0, _("Invalid transform expression")));
222 /* Scan replacement expression */
223 for (j
= i
+ 1; expr
[j
] && expr
[j
] != delim
; j
++)
224 if (expr
[j
] == '\\' && expr
[j
+1])
227 if (expr
[j
] != delim
)
228 USAGE_ERROR ((0, 0, _("Invalid transform expression")));
231 tf
->transform_type
= transform_first
;
232 tf
->flags
= transform_flags
;
233 for (p
= expr
+ j
+ 1; *p
&& *p
!= ';'; p
++)
237 tf
->transform_type
= transform_global
;
245 cflags
|= REG_EXTENDED
;
248 case '0': case '1': case '2': case '3': case '4':
249 case '5': case '6': case '7': case '8': case '9':
250 tf
->match_number
= strtoul (p
, (char**) &p
, 0);
255 if (parse_xform_flags (&tf
->flags
, *p
))
256 USAGE_ERROR ((0, 0, _("Unknown flag in transform expression: %c"),
263 /* Extract and compile regex */
264 str
= xmalloc (i
- 1);
265 memcpy (str
, expr
+ 2, i
- 2);
268 rc
= regcomp (&tf
->regex
, str
, cflags
);
273 regerror (rc
, &tf
->regex
, errbuf
, sizeof (errbuf
));
274 USAGE_ERROR ((0, 0, _("Invalid transform expression: %s"), errbuf
));
277 if (str
[0] == '^' || (i
> 2 && str
[i
- 3] == '$'))
278 tf
->transform_type
= transform_first
;
282 /* Extract and compile replacement expr */
284 str
= xmalloc (j
- i
+ 1);
285 memcpy (str
, expr
+ i
, j
- i
);
288 for (cur
= beg
= str
; *cur
;)
294 add_literal_segment (tf
, beg
, cur
);
297 case '0': case '1': case '2': case '3': case '4':
298 case '5': case '6': case '7': case '8': case '9':
299 n
= strtoul (cur
, &cur
, 10);
300 if (n
> tf
->regex
.re_nsub
)
301 USAGE_ERROR ((0, 0, _("Invalid transform replacement: back reference out of range")));
302 add_backref_segment (tf
, n
);
306 add_char_segment (tf
, '\\');
311 add_char_segment (tf
, '\a');
316 add_char_segment (tf
, '\b');
321 add_char_segment (tf
, '\f');
326 add_char_segment (tf
, '\n');
331 add_char_segment (tf
, '\r');
336 add_char_segment (tf
, '\t');
341 add_char_segment (tf
, '\v');
346 add_char_segment (tf
, '&');
351 /* Turn the replacement to lowercase until a '\U' or '\E'
353 add_case_ctl_segment (tf
, ctl_locase
);
358 /* Turn the next character to lowercase, */
359 add_case_ctl_segment (tf
, ctl_locase_next
);
364 /* Turn the replacement to uppercase until a '\L' or '\E'
366 add_case_ctl_segment (tf
, ctl_upcase
);
371 /* Turn the next character to uppercase, */
372 add_case_ctl_segment (tf
, ctl_upcase_next
);
377 /* Stop case conversion started by '\L' or '\U'. */
378 add_case_ctl_segment (tf
, ctl_stop
);
384 add_char_segment (tf
, delim
);
390 add_literal_segment (tf
, buf
, buf
+ 2);
397 else if (*cur
== '&')
399 add_literal_segment (tf
, beg
, cur
);
400 add_backref_segment (tf
, 0);
406 add_literal_segment (tf
, beg
, cur
);
413 set_transform_expr (const char *expr
)
416 expr
= parse_transform_expr (expr
);
419 /* Run case conversion specified by CASE_CTL on array PTR of SIZE
420 characters. Returns pointer to statically allocated storage. */
422 run_case_conv (enum case_ctl_type case_ctl
, char *ptr
, size_t size
)
424 static char *case_ctl_buffer
;
425 static size_t case_ctl_bufsize
;
428 if (case_ctl_bufsize
< size
)
430 case_ctl_bufsize
= size
;
431 case_ctl_buffer
= xrealloc (case_ctl_buffer
, case_ctl_bufsize
);
433 memcpy (case_ctl_buffer
, ptr
, size
);
436 case ctl_upcase_next
:
437 case_ctl_buffer
[0] = toupper ((unsigned char) case_ctl_buffer
[0]);
440 case ctl_locase_next
:
441 case_ctl_buffer
[0] = tolower ((unsigned char) case_ctl_buffer
[0]);
445 for (p
= case_ctl_buffer
; p
< case_ctl_buffer
+ size
; p
++)
446 *p
= toupper ((unsigned char) *p
);
450 for (p
= case_ctl_buffer
; p
< case_ctl_buffer
+ size
; p
++)
451 *p
= tolower ((unsigned char) *p
);
457 return case_ctl_buffer
;
461 static struct obstack stk
;
462 static bool stk_init
;
465 _single_transform_name_to_obstack (struct transform
*tf
, char *input
)
470 enum case_ctl_type case_ctl
= ctl_stop
, /* Current case conversion op */
471 save_ctl
= ctl_stop
; /* Saved case_ctl for \u and \l */
473 /* Reset case conversion after a single-char operation */
474 #define CASE_CTL_RESET() if (case_ctl == ctl_upcase_next \
475 || case_ctl == ctl_locase_next) \
477 case_ctl = save_ctl; \
478 save_ctl = ctl_stop; \
481 rmp
= xmalloc ((tf
->regex
.re_nsub
+ 1) * sizeof (*rmp
));
488 rc
= regexec (&tf
->regex
, input
, tf
->regex
.re_nsub
+ 1, rmp
, 0);
492 struct replace_segm
*segm
;
497 if (tf
->match_number
&& nmatches
< tf
->match_number
)
499 obstack_grow (&stk
, input
, disp
);
505 obstack_grow (&stk
, input
, rmp
[0].rm_so
);
507 for (segm
= tf
->repl_head
; segm
; segm
= segm
->next
)
511 case segm_literal
: /* Literal segment */
512 if (case_ctl
== ctl_stop
)
513 ptr
= segm
->v
.literal
.ptr
;
516 ptr
= run_case_conv (case_ctl
,
518 segm
->v
.literal
.size
);
521 obstack_grow (&stk
, ptr
, segm
->v
.literal
.size
);
524 case segm_backref
: /* Back-reference segment */
525 if (rmp
[segm
->v
.ref
].rm_so
!= -1
526 && rmp
[segm
->v
.ref
].rm_eo
!= -1)
528 size_t size
= rmp
[segm
->v
.ref
].rm_eo
529 - rmp
[segm
->v
.ref
].rm_so
;
530 ptr
= input
+ rmp
[segm
->v
.ref
].rm_so
;
531 if (case_ctl
!= ctl_stop
)
533 ptr
= run_case_conv (case_ctl
, ptr
, size
);
537 obstack_grow (&stk
, ptr
, size
);
544 case ctl_upcase_next
:
545 case ctl_locase_next
:
560 case_ctl
= segm
->v
.ctl
;
567 disp
= strlen (input
);
568 obstack_grow (&stk
, input
, disp
);
573 if (tf
->transform_type
== transform_first
)
575 obstack_grow (&stk
, input
, strlen (input
));
580 obstack_1grow (&stk
, 0);
585 _transform_name_to_obstack (int flags
, char *input
, char **output
)
587 struct transform
*tf
;
588 bool alloced
= false;
596 for (tf
= transform_head
; tf
; tf
= tf
->next
)
598 if (tf
->flags
& flags
)
600 _single_transform_name_to_obstack (tf
, input
);
601 input
= obstack_finish (&stk
);
610 transform_name_fp (char **pinput
, int flags
,
611 char *(*fun
)(char *, void *), void *dat
)
614 bool ret
= _transform_name_to_obstack (flags
, *pinput
, &str
);
617 assign_string (pinput
, fun
? fun (str
, dat
) : str
);
618 obstack_free (&stk
, str
);
623 assign_string (pinput
, fun (str
, dat
));
631 transform_name (char **pinput
, int type
)
633 return transform_name_fp (pinput
, type
, NULL
, NULL
);
637 transform_program_p (void)
639 return transform_head
!= NULL
;