]> git.ipfire.org Git - thirdparty/util-linux.git/blame - text-utils/hexdump-parse.c
po-man: add uk.po (from translationproject.org)
[thirdparty/util-linux.git] / text-utils / hexdump-parse.c
CommitLineData
6dbe3af9
KZ
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
b50945d4 34 /* 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
7eda085c
KZ
35 * - added Native Language Support
36 */
37
6dbe3af9
KZ
38#include <sys/types.h>
39#include <sys/file.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <ctype.h>
43#include <string.h>
44#include "hexdump.h"
7eda085c 45#include "nls.h"
85bf44b7 46#include "xalloc.h"
bec2d458 47#include "strutils.h"
098ab077 48#include "colors.h"
6dbe3af9 49
ffc43748 50static void escape(char *p1);
098ab077 51static struct list_head *color_fmt(char *cfmt, int bcnt);
1be6ed6a
OO
52
53static void __attribute__ ((__noreturn__)) badcnt(const char *s)
54{
55 errx(EXIT_FAILURE, _("bad byte count for conversion character %s"), s);
56}
57
58static void __attribute__ ((__noreturn__)) badsfmt(void)
59{
60 errx(EXIT_FAILURE, _("%%s requires a precision or a byte count"));
61}
62
63static void __attribute__ ((__noreturn__)) badfmt(const char *fmt)
64{
65 errx(EXIT_FAILURE, _("bad format {%s}"), fmt);
66}
67
68static void __attribute__ ((__noreturn__)) badconv(const char *ch)
69{
70 errx(EXIT_FAILURE, _("bad conversion character %%%s"), ch);
71}
fd6b7a7f 72
d01d144c 73#define first_letter(s,f) strchr(f, *(s))
f65e62e0 74
046921da 75struct hexdump_fu *endfu; /* format at end-of-data */
6dbe3af9 76
1f77e9c3 77void addfile(char *name, struct hexdump *hex)
6dbe3af9 78{
3917a95d 79 char *fmt, *buf = NULL;
6dbe3af9 80 FILE *fp;
6e908327 81 size_t n = 0;
6dbe3af9 82
85bf44b7
SK
83 if ((fp = fopen(name, "r")) == NULL)
84 err(EXIT_FAILURE, _("can't read %s"), name);
96ea3d32
OO
85
86 while (getline(&buf, &n, fp) != -1) {
3917a95d 87 fmt = buf;
96ea3d32 88
3917a95d
OO
89 while (*fmt && isspace(*fmt))
90 ++fmt;
91 if (!*fmt || *fmt == '#')
6dbe3af9 92 continue;
96ea3d32 93
1f77e9c3 94 add_fmt(fmt, hex);
6dbe3af9 95 }
96ea3d32
OO
96
97 free(buf);
9db51207 98 fclose(fp);
6dbe3af9
KZ
99}
100
ccedcc55
KZ
101static char *next_number(const char *str, int *num)
102{
103 char *end = NULL;
104
105 errno = 0;
106 *num = strtol(str, &end, 10);
107
108 if (errno || !end || end == str)
109 return NULL;
110 return end;
111}
112
1f77e9c3 113void add_fmt(const char *fmt, struct hexdump *hex)
6dbe3af9 114{
cb986008 115 const char *p, *savep;
bb8ae572 116 struct hexdump_fs *tfs;
046921da 117 struct hexdump_fu *tfu;
6dbe3af9 118
ffc43748 119 /* Start new linked list of format units. */
bb8ae572 120 tfs = xcalloc(1, sizeof(struct hexdump_fs));
bbc8c153
OO
121 INIT_LIST_HEAD(&tfs->fslist);
122 INIT_LIST_HEAD(&tfs->fulist);
1f77e9c3 123 list_add_tail(&tfs->fslist, &hex->fshead);
bafd2d46 124
ffc43748 125 /* Take the format string and break it up into format units. */
cb986008 126 p = fmt;
9db51207 127 while (TRUE) {
ffc43748 128 /* Skip leading white space. */
0acd3f5d 129 if (!*(p = skip_space(p)))
6dbe3af9
KZ
130 break;
131
ffc43748 132 /* Allocate a new format unit and link it in. */
046921da 133 tfu = xcalloc(1, sizeof(struct hexdump_fu));
acf74fc2
OO
134 tfu->reps = 1;
135
bbc8c153
OO
136 INIT_LIST_HEAD(&tfu->fulist);
137 INIT_LIST_HEAD(&tfu->prlist);
138 list_add_tail(&tfu->fulist, &tfs->fulist);
6dbe3af9 139
ffc43748 140 /* If leading digit, repetition count. */
9db51207 141 if (isdigit(*p)) {
ccedcc55
KZ
142 p = next_number(p, &tfu->reps);
143 if (!p || (!isspace(*p) && *p != '/'))
6dbe3af9 144 badfmt(fmt);
ccedcc55 145
6dbe3af9 146 /* may overwrite either white space or slash */
6dbe3af9
KZ
147 tfu->flags = F_SETREP;
148 /* skip trailing white space */
0acd3f5d 149 p = skip_space(++p);
6dbe3af9
KZ
150 }
151
ffc43748 152 /* Skip slash and trailing white space. */
6dbe3af9 153 if (*p == '/')
82233c2a 154 p = skip_space(++p);
6dbe3af9
KZ
155
156 /* byte count */
9db51207 157 if (isdigit(*p)) {
ccedcc55
KZ
158 p = next_number(p, &tfu->bcnt);
159 if (!p || !isspace(*p))
6dbe3af9 160 badfmt(fmt);
6dbe3af9 161 /* skip trailing white space */
0acd3f5d 162 p = skip_space(++p);
6dbe3af9
KZ
163 }
164
165 /* format */
166 if (*p != '"')
167 badfmt(fmt);
9db51207 168 savep = ++p;
acf74fc2 169 while (*p != '"') {
7e6e290b 170 if (!*p++)
6dbe3af9 171 badfmt(fmt);
acf74fc2 172 }
85bf44b7 173 tfu->fmt = xmalloc(p - savep + 1);
cb986008 174 xstrncpy(tfu->fmt, savep, p - savep + 1);
6dbe3af9 175 escape(tfu->fmt);
acf74fc2 176 ++p;
6dbe3af9
KZ
177 }
178}
179
ffc43748 180static const char *spec = ".#-+ 0123456789";
fd6b7a7f 181
bb8ae572 182int block_size(struct hexdump_fs *fs)
6dbe3af9 183{
046921da 184 struct hexdump_fu *fu;
acf74fc2 185 int bcnt, prec, cursize = 0;
cb986008 186 char *fmt;
9db51207 187 struct list_head *p;
6dbe3af9
KZ
188
189 /* figure out the data block size needed for each format unit */
bbc8c153 190 list_for_each (p, &fs->fulist) {
046921da 191 fu = list_entry(p, struct hexdump_fu, fulist);
6dbe3af9
KZ
192 if (fu->bcnt) {
193 cursize += fu->bcnt * fu->reps;
194 continue;
195 }
9db51207 196 bcnt = prec = 0;
cb986008 197 fmt = fu->fmt;
9db51207
OO
198 while (*fmt) {
199 if (*fmt != '%') {
200 ++fmt;
6dbe3af9 201 continue;
9db51207 202 }
6dbe3af9
KZ
203 /*
204 * skip any special chars -- save precision in
205 * case it's a %s format.
206 */
acf74fc2
OO
207 while (strchr(spec + 1, *++fmt))
208 ;
ccedcc55
KZ
209 if (*fmt == '.' && isdigit(*++fmt))
210 fmt = next_number(fmt, &prec);
d01d144c 211 if (first_letter(fmt, "diouxX"))
6dbe3af9 212 bcnt += 4;
d01d144c 213 else if (first_letter(fmt, "efgEG"))
6dbe3af9 214 bcnt += 8;
f65e62e0 215 else if (*fmt == 's')
6dbe3af9 216 bcnt += prec;
d01d144c 217 else if (*fmt == 'c' || (*fmt == '_' && first_letter(++fmt, "cpu")))
f65e62e0 218 ++bcnt;
9db51207 219 ++fmt;
6dbe3af9
KZ
220 }
221 cursize += bcnt * fu->reps;
222 }
223 return(cursize);
224}
225
1f77e9c3 226void rewrite_rules(struct hexdump_fs *fs, struct hexdump *hex)
6dbe3af9
KZ
227{
228 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
4c73d29c 229 struct hexdump_pr *pr;
046921da 230 struct hexdump_fu *fu;
9db51207 231 struct list_head *p, *q;
acf74fc2 232 char *p1, *p2, *fmtp;
7235e703 233 char savech, cs[4];
acf74fc2 234 int nconv, prec = 0;
6dbe3af9 235
bbc8c153 236 list_for_each (p, &fs->fulist) {
046921da 237 fu = list_entry(p, struct hexdump_fu, fulist);
6dbe3af9 238 /*
ffc43748 239 * Break each format unit into print units; each
6dbe3af9
KZ
240 * conversion character gets its own.
241 */
9db51207
OO
242 nconv = 0;
243 fmtp = fu->fmt;
244 while (*fmtp) {
4c73d29c 245 pr = xcalloc(1, sizeof(struct hexdump_pr));
bbc8c153
OO
246 INIT_LIST_HEAD(&pr->prlist);
247 list_add_tail(&pr->prlist, &fu->prlist);
6dbe3af9 248
ffc43748 249 /* Skip preceding text and up to the next % sign. */
eef27d32
OO
250 p1 = fmtp;
251 while (*p1 && *p1 != '%')
252 ++p1;
6dbe3af9 253
ffc43748 254 /* Only text in the string. */
6dbe3af9 255 if (!*p1) {
d2740b0e 256 pr->fmt = xstrdup(fmtp);
6dbe3af9
KZ
257 pr->flags = F_TEXT;
258 break;
259 }
260
261 /*
ffc43748 262 * Get precision for %s -- if have a byte count, don't
6dbe3af9
KZ
263 * need it.
264 */
265 if (fu->bcnt) {
266 sokay = USEBCNT;
267 /* skip to conversion character */
577bb86f 268 for (p1++; strchr(spec, *p1); p1++)
eef27d32 269 ;
6dbe3af9
KZ
270 } else {
271 /* skip any special chars, field width */
eef27d32
OO
272 while (strchr(spec + 1, *++p1))
273 ;
dabfe2ad 274 if (*p1 == '.' && isdigit(*++p1)) {
6dbe3af9 275 sokay = USEPREC;
ccedcc55 276 p1 = next_number(p1, &prec);
ffc43748 277 } else
6dbe3af9
KZ
278 sokay = NOTOKAY;
279 }
280
ffc43748
KZ
281 p2 = p1 + 1; /* Set end pointer. */
282 cs[0] = *p1; /* Set conversion string. */
283 cs[1] = 0;
6dbe3af9
KZ
284
285 /*
ffc43748 286 * Figure out the byte count for each conversion;
6dbe3af9
KZ
287 * rewrite the format as necessary, set up blank-
288 * padding for end of data.
289 */
f65e62e0
OO
290 if (*cs == 'c') {
291 pr->flags = F_CHAR;
292 switch(fu->bcnt) {
293 case 0:
294 case 1:
295 pr->bcnt = 1;
296 break;
297 default:
298 p1[1] = '\0';
299 badcnt(p1);
300 }
d01d144c 301 } else if (first_letter(cs, "di")) {
f65e62e0
OO
302 pr->flags = F_INT;
303 goto isint;
d01d144c 304 } else if (first_letter(cs, "ouxX")) {
f65e62e0 305 pr->flags = F_UINT;
7235e703
NC
306isint: cs[3] = '\0';
307 cs[2] = cs[0];
308 cs[1] = 'l';
309 cs[0] = 'l';
f65e62e0
OO
310 switch(fu->bcnt) {
311 case 0:
312 pr->bcnt = 4;
313 break;
314 case 1:
315 case 2:
316 case 4:
317 case 8:
318 pr->bcnt = fu->bcnt;
319 break;
320 default:
321 p1[1] = '\0';
322 badcnt(p1);
323 }
d01d144c 324 } else if (first_letter(cs, "efgEG")) {
f65e62e0
OO
325 pr->flags = F_DBL;
326 switch(fu->bcnt) {
327 case 0:
328 pr->bcnt = 8;
329 break;
330 case 4:
331 case 8:
332 pr->bcnt = fu->bcnt;
333 break;
334 default:
335 p1[1] = '\0';
336 badcnt(p1);
337 }
338 } else if(*cs == 's') {
339 pr->flags = F_STR;
340 switch(sokay) {
eef27d32
OO
341 case NOTOKAY:
342 badsfmt();
343 case USEBCNT:
344 pr->bcnt = fu->bcnt;
345 break;
346 case USEPREC:
347 pr->bcnt = prec;
348 break;
f65e62e0
OO
349 }
350 } else if (*cs == '_') {
351 ++p2;
352 switch(p1[1]) {
353 case 'A':
354 endfu = fu;
355 fu->flags |= F_IGNORE;
b1557fe9 356 /* fallthrough */
f65e62e0
OO
357 case 'a':
358 pr->flags = F_ADDRESS;
359 ++p2;
d01d144c 360 if (first_letter(p1 + 2, "dox")) {
7235e703
NC
361 cs[0] = 'l';
362 cs[1] = 'l';
363 cs[2] = p1[2];
364 cs[3] = '\0';
f65e62e0
OO
365 } else {
366 p1[3] = '\0';
eef27d32 367 badconv(p1);
f65e62e0
OO
368 }
369 break;
370 case 'c':
371 pr->flags = F_C;
372 /* cs[0] = 'c'; set in conv_c */
373 goto isint2;
374 case 'p':
375 pr->flags = F_P;
376 cs[0] = 'c';
377 goto isint2;
378 case 'u':
379 pr->flags = F_U;
380 /* cs[0] = 'c'; set in conv_u */
381 isint2: switch(fu->bcnt) {
382 case 0:
383 case 1:
384 pr->bcnt = 1;
385 break;
386 default:
387 p1[2] = '\0';
388 badcnt(p1);
389 }
390 break;
391 default:
392 p1[2] = '\0';
393 badconv(p1);
394 }
395 } else {
396 p1[1] = '\0';
397 badconv(p1);
6dbe3af9
KZ
398 }
399
098ab077
OO
400 /* Color unit(s) specified */
401 if (*p2 == '_' && p2[1] == 'L') {
402 if (colors_wanted()) {
403 char *a;
404
405 /* "cut out" the color_unit(s) */
406 a = strchr(p2, '[');
407 p2 = strrchr(p2, ']');
408 if (a++ && p2)
409 pr->colorlist = color_fmt(xstrndup(a, p2++ - a), pr->bcnt);
410 else
411 badconv(p2);
412 }
413 /* we don't want colors, quietly skip over them */
414 else {
415 p2 = strrchr(p2, ']');
416 /* be a bit louder if we don't know how to skip over them */
417 if (!p2)
418 badconv("_L");
419 ++p2;
420 }
421 }
6dbe3af9 422 /*
4c73d29c 423 * Copy to hexdump_pr format string, set conversion character
6dbe3af9
KZ
424 * pointer, update original.
425 */
426 savech = *p2;
ffc43748 427 p1[0] = '\0';
85bf44b7 428 pr->fmt = xmalloc(strlen(fmtp) + strlen(cs) + 1);
eef27d32
OO
429 strcpy(pr->fmt, fmtp);
430 strcat(pr->fmt, cs);
6dbe3af9
KZ
431 *p2 = savech;
432 pr->cchar = pr->fmt + (p1 - fmtp);
433 fmtp = p2;
434
ffc43748 435 /* Only one conversion character if byte count */
85bf44b7
SK
436 if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++)
437 errx(EXIT_FAILURE,
438 _("byte count with multiple conversion characters"));
6dbe3af9
KZ
439 }
440 /*
ffc43748 441 * If format unit byte count not specified, figure it out
6dbe3af9
KZ
442 * so can adjust rep count later.
443 */
444 if (!fu->bcnt)
bbc8c153 445 list_for_each(q, &fu->prlist)
4c73d29c
OO
446 fu->bcnt
447 += (list_entry(q, struct hexdump_pr, prlist))->bcnt;
6dbe3af9
KZ
448 }
449 /*
ffc43748 450 * If the format string interprets any data at all, and it's
6dbe3af9
KZ
451 * not the same as the blocksize, and its last format unit
452 * interprets any data at all, and has no iteration count,
453 * repeat it as necessary.
454 *
ffc43748 455 * If rep count is greater than 1, no trailing whitespace
6dbe3af9
KZ
456 * gets output from the last iteration of the format unit.
457 */
bbc8c153 458 list_for_each (p, &fs->fulist) {
046921da 459 fu = list_entry(p, struct hexdump_fu, fulist);
acf74fc2
OO
460
461 if (list_entry_is_last(&fu->fulist, &fs->fulist) &&
1f77e9c3 462 fs->bcnt < hex->blocksize &&
acf74fc2 463 !(fu->flags&F_SETREP) && fu->bcnt)
1f77e9c3 464 fu->reps += (hex->blocksize - fs->bcnt) / fu->bcnt;
74ce680a
SK
465 if (fu->reps > 1 && !list_empty(&fu->prlist)) {
466 pr = list_last_entry(&fu->prlist, struct hexdump_pr, prlist);
577bb86f
SK
467 if (!pr)
468 continue;
74ce680a
SK
469 for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
470 p2 = isspace(*p1) ? p1 : NULL;
471 if (p2)
472 pr->nospace = p2;
6dbe3af9 473 }
6dbe3af9
KZ
474 }
475}
476
098ab077
OO
477/* [!]color[:string|:hex_number|:oct_number][@offt|@offt_start-offt_end],... */
478static struct list_head *color_fmt(char *cfmt, int bcnt)
479{
480 struct hexdump_clr *hc, *hcnext;
481 struct list_head *ret_head;
482 char *clr, *fmt;
483
484 ret_head = xmalloc(sizeof(struct list_head));
485 hcnext = hc = xcalloc(1, sizeof(struct hexdump_clr));
486
487 INIT_LIST_HEAD(&hc->colorlist);
488 INIT_LIST_HEAD(ret_head);
489 list_add_tail(&hc->colorlist, ret_head);
490
491 fmt = cfmt;
492 while (cfmt && *cfmt) {
493 char *end;
494 /* invert this condition */
495 if (*cfmt == '!') {
496 hcnext->invert = 1;
497 ++cfmt;
498 }
499
500 clr = xstrndup(cfmt, strcspn(cfmt, ":@,"));
501 cfmt += strlen(clr);
58ce71e6 502 hcnext->fmt = color_sequence_from_colorname(clr);
098ab077
OO
503 free(clr);
504
505 if (!hcnext->fmt)
506 return NULL;
507
508 /* only colorize this specific value */
509 if (*cfmt == ':') {
510 ++cfmt;
511 /* a hex or oct value */
512 if (*cfmt == '0') {
513 /* hex */
514 errno = 0;
515 end = NULL;
516 if (cfmt[1] == 'x' || cfmt[1] == 'X')
517 hcnext->val = strtoul(cfmt + 2, &end, 16);
518 else
519 hcnext->val = strtoul(cfmt, &end, 8);
520 if (errno || end == cfmt)
521 badfmt(fmt);
522 cfmt = end;
523 /* a string */
524 } else {
525 off_t fmt_end;
526 char endchar;
527 char *endstr;
528
529 hcnext->val = -1;
530 /* temporarily null-delimit the format, so we can reverse-search
531 * for the start of an offset specifier */
532 fmt_end = strcspn(cfmt, ",");
533 endchar = cfmt[fmt_end];
534 cfmt[fmt_end] = '\0';
535 endstr = strrchr(cfmt, '@');
536
537 if (endstr) {
538 if (endstr[1] != '\0')
539 --endstr;
540 hcnext->str = xstrndup(cfmt, endstr - cfmt + 1);
541 } else
542 hcnext->str = xstrndup(cfmt, fmt_end);
543
544 /* restore the character */
545 cfmt[fmt_end] = endchar;
546 cfmt += strlen(hcnext->str);
547 }
548
549 /* no specific value */
550 } else
551 hcnext->val = -1;
552
553 /* only colorize at this offset */
554 hcnext->range = bcnt;
555 if (cfmt && *cfmt == '@') {
556 errno = 0;
557 hcnext->offt = strtoul(++cfmt, &cfmt, 10);
558 if (errno)
559 badfmt(fmt);
560
561 /* offset range */
562 if (*cfmt == '-') {
563 ++cfmt;
564 errno = 0;
565
566 hcnext->range =
567 strtoul(cfmt, &cfmt, 10) - hcnext->offt + 1;
568 if (errno)
569 badfmt(fmt);
570 /* offset range must be between 0 and format byte count */
3bf7ede9 571 if (hcnext->range < 0)
098ab077 572 badcnt("_L");
3bf7ede9
OO
573 /* the offset extends over several print units, clone
574 * the condition, link it in and adjust the address/offset */
575 while (hcnext->range > bcnt) {
576 hc = xcalloc(1, sizeof(struct hexdump_clr));
577 memcpy(hc, hcnext, sizeof(struct hexdump_clr));
578
579 hc->range = bcnt;
580
581 INIT_LIST_HEAD(&hc->colorlist);
582 list_add_tail(&hc->colorlist, ret_head);
583
584 hcnext->offt += bcnt;
585 hcnext->range -= bcnt;
586 }
098ab077
OO
587 }
588 /* no specific offset */
589 } else
590 hcnext->offt = (off_t)-1;
591
592 /* check if the string we're looking for is the same length as the range */
593 if (hcnext->str && (int)strlen(hcnext->str) != hcnext->range)
594 badcnt("_L");
595
596 /* link in another condition */
597 if (cfmt && *cfmt == ',') {
598 ++cfmt;
599
600 hcnext = xcalloc(1, sizeof(struct hexdump_clr));
601 INIT_LIST_HEAD(&hcnext->colorlist);
602 list_add_tail(&hcnext->colorlist, ret_head);
603 }
604 }
605 return ret_head;
606}
6dbe3af9 607
ffc43748 608static void escape(char *p1)
6dbe3af9 609{
ffc43748 610 char *p2;
6dbe3af9
KZ
611
612 /* alphabetic escape sequences have to be done in place */
9c2cb9b0
OO
613 p2 = p1;
614 while (TRUE) {
6dbe3af9
KZ
615 if (!*p1) {
616 *p2 = *p1;
617 break;
618 }
619 if (*p1 == '\\')
620 switch(*++p1) {
621 case 'a':
622 /* *p2 = '\a'; */
623 *p2 = '\007';
624 break;
625 case 'b':
626 *p2 = '\b';
627 break;
628 case 'f':
629 *p2 = '\f';
630 break;
631 case 'n':
632 *p2 = '\n';
633 break;
634 case 'r':
635 *p2 = '\r';
636 break;
637 case 't':
638 *p2 = '\t';
639 break;
640 case 'v':
641 *p2 = '\v';
642 break;
643 default:
644 *p2 = *p1;
645 break;
646 }
9c2cb9b0 647 ++p1; ++p2;
6dbe3af9
KZ
648 }
649}