]>
Dogcows Code - chaz/tar/blob - src/transform.c
1 /* This file is part of GNU tar.
2 Copyright (C) 2006, 2007 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, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
22 static enum transform_type
28 transform_type
= transform_none
;
29 static unsigned match_number
= 0;
31 static struct obstack stk
;
33 enum replace_segm_type
35 segm_literal
, /* Literal segment */
36 segm_backref
, /* Back-reference segment */
37 segm_case_ctl
/* Case control segment (GNU extension) */
42 ctl_stop
, /* Stop case conversion */
43 ctl_upcase_next
,/* Turn the next character to uppercase */
44 ctl_locase_next
,/* Turn the next character to lowercase */
45 ctl_upcase
, /* Turn the replacement to uppercase until ctl_stop */
46 ctl_locase
/* Turn the replacement to lowercase until ctl_stop */
51 struct replace_segm
*next
;
52 enum replace_segm_type type
;
59 } literal
; /* type == segm_literal */
60 size_t ref
; /* type == segm_backref */
61 enum case_ctl_type ctl
; /* type == segm_case_ctl */
65 /* Compiled replacement expression */
66 static struct replace_segm
*repl_head
, *repl_tail
;
67 static size_t segm_count
; /* Number of elements in the above list */
69 static struct replace_segm
*
72 struct replace_segm
*segm
= xmalloc (sizeof *segm
);
75 repl_tail
->next
= segm
;
84 add_literal_segment (char *str
, char *end
)
86 size_t len
= end
- str
;
89 struct replace_segm
*segm
= add_segment ();
90 segm
->type
= segm_literal
;
91 segm
->v
.literal
.ptr
= xmalloc (len
+ 1);
92 memcpy (segm
->v
.literal
.ptr
, str
, len
);
93 segm
->v
.literal
.ptr
[len
] = 0;
94 segm
->v
.literal
.size
= len
;
99 add_char_segment (int chr
)
101 struct replace_segm
*segm
= add_segment ();
102 segm
->type
= segm_literal
;
103 segm
->v
.literal
.ptr
= xmalloc (2);
104 segm
->v
.literal
.ptr
[0] = chr
;
105 segm
->v
.literal
.ptr
[1] = 0;
106 segm
->v
.literal
.size
= 1;
110 add_backref_segment (size_t ref
)
112 struct replace_segm
*segm
= add_segment ();
113 segm
->type
= segm_backref
;
118 add_case_ctl_segment (enum case_ctl_type ctl
)
120 struct replace_segm
*segm
= add_segment ();
121 segm
->type
= segm_case_ctl
;
126 set_transform_expr (const char *expr
)
130 char *str
, *beg
, *cur
;
134 if (transform_type
== transform_none
)
138 /* Redefinition of the transform expression */
143 USAGE_ERROR ((0, 0, _("Invalid transform expression")));
147 /* Scan regular expression */
148 for (i
= 2; expr
[i
] && expr
[i
] != delim
; i
++)
149 if (expr
[i
] == '\\' && expr
[i
+1])
152 if (expr
[i
] != delim
)
153 USAGE_ERROR ((0, 0, _("Invalid transform expression")));
155 /* Scan replacement expression */
156 for (j
= i
+ 1; expr
[j
] && expr
[j
] != delim
; j
++)
157 if (expr
[j
] == '\\' && expr
[j
+1])
160 if (expr
[j
] != delim
)
161 USAGE_ERROR ((0, 0, _("Invalid transform expression")));
164 transform_type
= transform_first
;
165 for (p
= expr
+ j
+ 1; *p
; p
++)
169 transform_type
= transform_global
;
177 cflags
|= REG_EXTENDED
;
180 case '0': case '1': case '2': case '3': case '4':
181 case '5': case '6': case '7': case '8': case '9':
182 match_number
= strtoul (p
, (char**) &p
, 0);
187 USAGE_ERROR ((0, 0, _("Unknown flag in transform expression")));
190 /* Extract and compile regex */
191 str
= xmalloc (i
- 1);
192 memcpy (str
, expr
+ 2, i
- 2);
195 rc
= regcomp (®ex
, str
, cflags
);
200 regerror (rc
, ®ex
, errbuf
, sizeof (errbuf
));
201 USAGE_ERROR ((0, 0, _("Invalid transform expression: %s"), errbuf
));
204 if (str
[0] == '^' || str
[strlen (str
) - 1] == '$')
205 transform_type
= transform_first
;
209 /* Extract and compile replacement expr */
211 str
= xmalloc (j
- i
+ 1);
212 memcpy (str
, expr
+ i
, j
- i
);
215 for (cur
= beg
= str
; *cur
;)
221 add_literal_segment (beg
, cur
);
224 case '0': case '1': case '2': case '3': case '4':
225 case '5': case '6': case '7': case '8': case '9':
226 n
= strtoul (cur
, &cur
, 10);
227 if (n
> regex
.re_nsub
)
228 USAGE_ERROR ((0, 0, _("Invalid transform replacement: back reference out of range")));
229 add_backref_segment (n
);
233 add_char_segment ('\\');
238 add_char_segment ('\a');
243 add_char_segment ('\b');
248 add_char_segment ('\f');
253 add_char_segment ('\n');
258 add_char_segment ('\r');
263 add_char_segment ('\t');
268 add_char_segment ('\v');
273 add_char_segment ('&');
278 /* Turn the replacement to lowercase until a `\U' or `\E'
280 add_case_ctl_segment (ctl_locase
);
285 /* Turn the next character to lowercase, */
286 add_case_ctl_segment (ctl_locase_next
);
291 /* Turn the replacement to uppercase until a `\L' or `\E'
293 add_case_ctl_segment (ctl_upcase
);
298 /* Turn the next character to uppercase, */
299 add_case_ctl_segment (ctl_upcase_next
);
304 /* Stop case conversion started by `\L' or `\U'. */
305 add_case_ctl_segment (ctl_stop
);
315 add_literal_segment (buf
, buf
+ 2);
322 else if (*cur
== '&')
324 add_literal_segment (beg
, cur
);
325 add_backref_segment (0);
331 add_literal_segment (beg
, cur
);
335 /* Run case conversion specified by CASE_CTL on array PTR of SIZE
336 characters. Returns pointer to statically allocated storage. */
338 run_case_conv (enum case_ctl_type case_ctl
, char *ptr
, size_t size
)
340 static char *case_ctl_buffer
;
341 static size_t case_ctl_bufsize
;
344 if (case_ctl_bufsize
< size
)
346 case_ctl_bufsize
= size
;
347 case_ctl_buffer
= xrealloc (case_ctl_buffer
, case_ctl_bufsize
);
349 memcpy (case_ctl_buffer
, ptr
, size
);
352 case ctl_upcase_next
:
353 case_ctl_buffer
[0] = toupper (case_ctl_buffer
[0]);
356 case ctl_locase_next
:
357 case_ctl_buffer
[0] = tolower (case_ctl_buffer
[0]);
361 for (p
= case_ctl_buffer
; p
< case_ctl_buffer
+ size
; p
++)
366 for (p
= case_ctl_buffer
; p
< case_ctl_buffer
+ size
; p
++)
373 return case_ctl_buffer
;
377 _transform_name_to_obstack (char *input
)
382 enum case_ctl_type case_ctl
= ctl_stop
, /* Current case conversion op */
383 save_ctl
= ctl_stop
; /* Saved case_ctl for \u and \l */
385 /* Reset case conversion after a single-char operation */
386 #define CASE_CTL_RESET() if (case_ctl == ctl_upcase_next \
387 || case_ctl == ctl_locase_next) \
389 case_ctl = save_ctl; \
390 save_ctl = ctl_stop; \
393 if (transform_type
== transform_none
)
396 rmp
= xmalloc ((regex
.re_nsub
+ 1) * sizeof (*rmp
));
403 rc
= regexec (®ex
, input
, regex
.re_nsub
+ 1, rmp
, 0);
407 struct replace_segm
*segm
;
412 obstack_grow (&stk
, input
, rmp
[0].rm_so
);
415 if (match_number
&& nmatches
< match_number
)
417 obstack_grow (&stk
, input
, disp
);
422 for (segm
= repl_head
; segm
; segm
= segm
->next
)
426 case segm_literal
: /* Literal segment */
427 if (case_ctl
== ctl_stop
)
428 ptr
= segm
->v
.literal
.ptr
;
431 ptr
= run_case_conv (case_ctl
,
433 segm
->v
.literal
.size
);
436 obstack_grow (&stk
, ptr
, segm
->v
.literal
.size
);
439 case segm_backref
: /* Back-reference segment */
440 if (rmp
[segm
->v
.ref
].rm_so
!= -1
441 && rmp
[segm
->v
.ref
].rm_eo
!= -1)
443 size_t size
= rmp
[segm
->v
.ref
].rm_eo
444 - rmp
[segm
->v
.ref
].rm_so
;
445 ptr
= input
+ rmp
[segm
->v
.ref
].rm_so
;
446 if (case_ctl
!= ctl_stop
)
448 ptr
= run_case_conv (case_ctl
, ptr
, size
);
452 obstack_grow (&stk
, ptr
, size
);
459 case ctl_upcase_next
:
460 case ctl_locase_next
:
475 case_ctl
= segm
->v
.ctl
;
482 disp
= strlen (input
);
483 obstack_grow (&stk
, input
, disp
);
488 if (transform_type
== transform_first
)
490 obstack_grow (&stk
, input
, strlen (input
));
495 obstack_1grow (&stk
, 0);
501 transform_name_fp (char **pinput
, char *(*fun
)(char *, void *), void *dat
)
504 bool ret
= _transform_name_to_obstack (*pinput
);
507 str
= obstack_finish (&stk
);
508 assign_string (pinput
, fun
? fun (str
, dat
) : str
);
509 obstack_free (&stk
, str
);
515 assign_string (pinput
, fun (str
, dat
));
523 transform_name (char **pinput
)
525 return transform_name_fp (pinput
, NULL
, NULL
);
This page took 0.060619 seconds and 4 git commands to generate.