diff options
| author | Richard M. Stallman | 2003-04-09 01:28:44 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 2003-04-09 01:28:44 +0000 |
| commit | d147ee841ac0a468d9504583ceeb2e3397d3dd90 (patch) | |
| tree | aab3b87f051f81e832cebceb788d9b577ea6438c /src | |
| parent | 60b898c674e57707feb2f1edab0b92fc5008a7e6 (diff) | |
| download | emacs-d147ee841ac0a468d9504583ceeb2e3397d3dd90.tar.gz emacs-d147ee841ac0a468d9504583ceeb2e3397d3dd90.zip | |
(Fformat): Translate positions of text properties
in the format string to apply them to the result.
Diffstat (limited to 'src')
| -rw-r--r-- | src/editfns.c | 140 |
1 files changed, 114 insertions, 26 deletions
diff --git a/src/editfns.c b/src/editfns.c index 360e067a298..f436ee15717 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -3201,7 +3201,7 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3201 | register int n; /* The number of the next arg to substitute */ | 3201 | register int n; /* The number of the next arg to substitute */ |
| 3202 | register int total; /* An estimate of the final length */ | 3202 | register int total; /* An estimate of the final length */ |
| 3203 | char *buf, *p; | 3203 | char *buf, *p; |
| 3204 | register unsigned char *format, *end; | 3204 | register unsigned char *format, *end, *format_start; |
| 3205 | int nchars; | 3205 | int nchars; |
| 3206 | /* Nonzero if the output should be a multibyte string, | 3206 | /* Nonzero if the output should be a multibyte string, |
| 3207 | which is true if any of the inputs is one. */ | 3207 | which is true if any of the inputs is one. */ |
| @@ -3220,9 +3220,20 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3220 | int *precision = (int *) (alloca(nargs * sizeof (int))); | 3220 | int *precision = (int *) (alloca(nargs * sizeof (int))); |
| 3221 | int longest_format; | 3221 | int longest_format; |
| 3222 | Lisp_Object val; | 3222 | Lisp_Object val; |
| 3223 | int arg_intervals = 0; | ||
| 3224 | |||
| 3225 | /* discarded[I] is 1 if byte I of the format | ||
| 3226 | string was not copied into the output. | ||
| 3227 | It is 2 if byte I was not the first byte of its character. */ | ||
| 3228 | char *discarded; | ||
| 3229 | |||
| 3230 | /* Each element records, for one argument, | ||
| 3231 | the start and end bytepos in the output string, | ||
| 3232 | and whether the argument is a string with intervals. | ||
| 3233 | info[0] is unused. Unused elements have -1 for start. */ | ||
| 3223 | struct info | 3234 | struct info |
| 3224 | { | 3235 | { |
| 3225 | int start, end; | 3236 | int start, end, intervals; |
| 3226 | } *info = 0; | 3237 | } *info = 0; |
| 3227 | 3238 | ||
| 3228 | /* It should not be necessary to GCPRO ARGS, because | 3239 | /* It should not be necessary to GCPRO ARGS, because |
| @@ -3232,12 +3243,13 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3232 | This is not always right; sometimes the result needs to be multibyte | 3243 | This is not always right; sometimes the result needs to be multibyte |
| 3233 | because of an object that we will pass through prin1, | 3244 | because of an object that we will pass through prin1, |
| 3234 | and in that case, we won't know it here. */ | 3245 | and in that case, we won't know it here. */ |
| 3235 | for (n = 0; n < nargs; n++) { | 3246 | for (n = 0; n < nargs; n++) |
| 3236 | if (STRINGP (args[n]) && STRING_MULTIBYTE (args[n])) | 3247 | { |
| 3237 | multibyte = 1; | 3248 | if (STRINGP (args[n]) && STRING_MULTIBYTE (args[n])) |
| 3238 | /* Piggyback on this loop to initialize precision[N]. */ | 3249 | multibyte = 1; |
| 3239 | precision[n] = -1; | 3250 | /* Piggyback on this loop to initialize precision[N]. */ |
| 3240 | } | 3251 | precision[n] = -1; |
| 3252 | } | ||
| 3241 | 3253 | ||
| 3242 | CHECK_STRING (args[0]); | 3254 | CHECK_STRING (args[0]); |
| 3243 | /* We may have to change "%S" to "%s". */ | 3255 | /* We may have to change "%S" to "%s". */ |
| @@ -3248,12 +3260,25 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3248 | retry: | 3260 | retry: |
| 3249 | 3261 | ||
| 3250 | format = SDATA (args[0]); | 3262 | format = SDATA (args[0]); |
| 3263 | format_start = format; | ||
| 3251 | end = format + SBYTES (args[0]); | 3264 | end = format + SBYTES (args[0]); |
| 3252 | longest_format = 0; | 3265 | longest_format = 0; |
| 3253 | 3266 | ||
| 3254 | /* Make room in result for all the non-%-codes in the control string. */ | 3267 | /* Make room in result for all the non-%-codes in the control string. */ |
| 3255 | total = 5 + CONVERTED_BYTE_SIZE (multibyte, args[0]); | 3268 | total = 5 + CONVERTED_BYTE_SIZE (multibyte, args[0]); |
| 3256 | 3269 | ||
| 3270 | /* Allocate the info and discarded tables. */ | ||
| 3271 | { | ||
| 3272 | int nbytes = nargs * sizeof *info; | ||
| 3273 | int i; | ||
| 3274 | info = (struct info *) alloca (nbytes); | ||
| 3275 | bzero (info, nbytes); | ||
| 3276 | for (i = 0; i <= nargs; i++) | ||
| 3277 | info[i].start = -1; | ||
| 3278 | discarded = (char *) alloca (SBYTES (args[0])); | ||
| 3279 | bzero (discarded, SBYTES (args[0])); | ||
| 3280 | } | ||
| 3281 | |||
| 3257 | /* Add to TOTAL enough space to hold the converted arguments. */ | 3282 | /* Add to TOTAL enough space to hold the converted arguments. */ |
| 3258 | 3283 | ||
| 3259 | n = 0; | 3284 | n = 0; |
| @@ -3458,6 +3483,7 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3458 | int negative = 0; | 3483 | int negative = 0; |
| 3459 | unsigned char *this_format_start = format; | 3484 | unsigned char *this_format_start = format; |
| 3460 | 3485 | ||
| 3486 | discarded[format - format_start] = 1; | ||
| 3461 | format++; | 3487 | format++; |
| 3462 | 3488 | ||
| 3463 | /* Process a numeric arg and skip it. */ | 3489 | /* Process a numeric arg and skip it. */ |
| @@ -3471,7 +3497,10 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3471 | fixed. */ | 3497 | fixed. */ |
| 3472 | while ((*format >= '0' && *format <= '9') | 3498 | while ((*format >= '0' && *format <= '9') |
| 3473 | || *format == '-' || *format == ' ' || *format == '.') | 3499 | || *format == '-' || *format == ' ' || *format == '.') |
| 3474 | format++; | 3500 | { |
| 3501 | discarded[format - format_start] = 1; | ||
| 3502 | format++; | ||
| 3503 | } | ||
| 3475 | 3504 | ||
| 3476 | if (*format++ == '%') | 3505 | if (*format++ == '%') |
| 3477 | { | 3506 | { |
| @@ -3482,6 +3511,9 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3482 | 3511 | ||
| 3483 | ++n; | 3512 | ++n; |
| 3484 | 3513 | ||
| 3514 | discarded[format - format_start - 1] = 1; | ||
| 3515 | info[n].start = nchars; | ||
| 3516 | |||
| 3485 | if (STRINGP (args[n])) | 3517 | if (STRINGP (args[n])) |
| 3486 | { | 3518 | { |
| 3487 | /* handle case (precision[n] >= 0) */ | 3519 | /* handle case (precision[n] >= 0) */ |
| @@ -3541,17 +3573,7 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3541 | /* If this argument has text properties, record where | 3573 | /* If this argument has text properties, record where |
| 3542 | in the result string it appears. */ | 3574 | in the result string it appears. */ |
| 3543 | if (STRING_INTERVALS (args[n])) | 3575 | if (STRING_INTERVALS (args[n])) |
| 3544 | { | 3576 | info[n].intervals = arg_intervals = 1; |
| 3545 | if (!info) | ||
| 3546 | { | ||
| 3547 | int nbytes = nargs * sizeof *info; | ||
| 3548 | info = (struct info *) alloca (nbytes); | ||
| 3549 | bzero (info, nbytes); | ||
| 3550 | } | ||
| 3551 | |||
| 3552 | info[n].start = start; | ||
| 3553 | info[n].end = end; | ||
| 3554 | } | ||
| 3555 | } | 3577 | } |
| 3556 | else if (INTEGERP (args[n]) || FLOATP (args[n])) | 3578 | else if (INTEGERP (args[n]) || FLOATP (args[n])) |
| 3557 | { | 3579 | { |
| @@ -3578,6 +3600,8 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3578 | p += this_nchars; | 3600 | p += this_nchars; |
| 3579 | nchars += this_nchars; | 3601 | nchars += this_nchars; |
| 3580 | } | 3602 | } |
| 3603 | |||
| 3604 | info[n].end = nchars; | ||
| 3581 | } | 3605 | } |
| 3582 | else if (STRING_MULTIBYTE (args[0])) | 3606 | else if (STRING_MULTIBYTE (args[0])) |
| 3583 | { | 3607 | { |
| @@ -3588,7 +3612,11 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3588 | && !CHAR_HEAD_P (*format)) | 3612 | && !CHAR_HEAD_P (*format)) |
| 3589 | maybe_combine_byte = 1; | 3613 | maybe_combine_byte = 1; |
| 3590 | *p++ = *format++; | 3614 | *p++ = *format++; |
| 3591 | while (! CHAR_HEAD_P (*format)) *p++ = *format++; | 3615 | while (! CHAR_HEAD_P (*format)) |
| 3616 | { | ||
| 3617 | discarded[format - format_start] = 2; | ||
| 3618 | *p++ = *format++; | ||
| 3619 | } | ||
| 3592 | nchars++; | 3620 | nchars++; |
| 3593 | } | 3621 | } |
| 3594 | else if (multibyte) | 3622 | else if (multibyte) |
| @@ -3619,7 +3647,7 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3619 | arguments has text properties, set up text properties of the | 3647 | arguments has text properties, set up text properties of the |
| 3620 | result string. */ | 3648 | result string. */ |
| 3621 | 3649 | ||
| 3622 | if (STRING_INTERVALS (args[0]) || info) | 3650 | if (STRING_INTERVALS (args[0]) || arg_intervals) |
| 3623 | { | 3651 | { |
| 3624 | Lisp_Object len, new_len, props; | 3652 | Lisp_Object len, new_len, props; |
| 3625 | struct gcpro gcpro1; | 3653 | struct gcpro gcpro1; |
| @@ -3631,15 +3659,75 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3631 | 3659 | ||
| 3632 | if (CONSP (props)) | 3660 | if (CONSP (props)) |
| 3633 | { | 3661 | { |
| 3634 | new_len = make_number (SCHARS (val)); | 3662 | int bytepos = 0, position = 0, translated = 0, argn = 1; |
| 3635 | extend_property_ranges (props, len, new_len); | 3663 | Lisp_Object list; |
| 3664 | |||
| 3665 | /* Adjust the bounds of each text property | ||
| 3666 | to the proper start and end in the output string. */ | ||
| 3667 | /* We take advantage of the fact that the positions in PROPS | ||
| 3668 | are in increasing order, so that we can do (effectively) | ||
| 3669 | one scan through the position space of the format string. | ||
| 3670 | |||
| 3671 | BYTEPOS is the byte position in the format string, | ||
| 3672 | POSITION is the untranslated char position in it, | ||
| 3673 | TRANSLATED is the translated char position in BUF, | ||
| 3674 | and ARGN is the number of the next arg we will come to. */ | ||
| 3675 | for (list = props; CONSP (list); list = XCDR (list)) | ||
| 3676 | { | ||
| 3677 | Lisp_Object item, pos; | ||
| 3678 | |||
| 3679 | item = XCAR (list); | ||
| 3680 | |||
| 3681 | /* First adjust the property start position. */ | ||
| 3682 | pos = XINT (XCAR (item)); | ||
| 3683 | |||
| 3684 | /* Advance BYTEPOS, POSITION, TRANSLATED and ARGN | ||
| 3685 | up to this position. */ | ||
| 3686 | for (; position < pos; bytepos++) | ||
| 3687 | { | ||
| 3688 | if (! discarded[bytepos]) | ||
| 3689 | position++, translated++; | ||
| 3690 | else if (discarded[bytepos] == 1) | ||
| 3691 | { | ||
| 3692 | position++; | ||
| 3693 | if (translated == info[argn].start) | ||
| 3694 | { | ||
| 3695 | translated += info[argn].end - info[argn].start; | ||
| 3696 | argn++; | ||
| 3697 | } | ||
| 3698 | } | ||
| 3699 | } | ||
| 3700 | |||
| 3701 | XSETCAR (item, make_number (translated)); | ||
| 3702 | |||
| 3703 | /* Likewise adjust the property end position. */ | ||
| 3704 | pos = XINT (XCAR (XCDR (item))); | ||
| 3705 | |||
| 3706 | for (; bytepos < pos; bytepos++) | ||
| 3707 | { | ||
| 3708 | if (! discarded[bytepos]) | ||
| 3709 | position++, translated++; | ||
| 3710 | else if (discarded[bytepos] == 1) | ||
| 3711 | { | ||
| 3712 | position++; | ||
| 3713 | if (translated == info[argn].start) | ||
| 3714 | { | ||
| 3715 | translated += info[argn].end - info[argn].start; | ||
| 3716 | argn++; | ||
| 3717 | } | ||
| 3718 | } | ||
| 3719 | } | ||
| 3720 | |||
| 3721 | XSETCAR (XCDR (item), make_number (translated)); | ||
| 3722 | } | ||
| 3723 | |||
| 3636 | add_text_properties_from_list (val, props, make_number (0)); | 3724 | add_text_properties_from_list (val, props, make_number (0)); |
| 3637 | } | 3725 | } |
| 3638 | 3726 | ||
| 3639 | /* Add text properties from arguments. */ | 3727 | /* Add text properties from arguments. */ |
| 3640 | if (info) | 3728 | if (arg_intervals) |
| 3641 | for (n = 1; n < nargs; ++n) | 3729 | for (n = 1; n < nargs; ++n) |
| 3642 | if (info[n].end) | 3730 | if (info[n].intervals) |
| 3643 | { | 3731 | { |
| 3644 | len = make_number (SCHARS (args[n])); | 3732 | len = make_number (SCHARS (args[n])); |
| 3645 | new_len = make_number (info[n].end - info[n].start); | 3733 | new_len = make_number (info[n].end - info[n].start); |