aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard M. Stallman2003-04-09 01:28:44 +0000
committerRichard M. Stallman2003-04-09 01:28:44 +0000
commitd147ee841ac0a468d9504583ceeb2e3397d3dd90 (patch)
treeaab3b87f051f81e832cebceb788d9b577ea6438c /src
parent60b898c674e57707feb2f1edab0b92fc5008a7e6 (diff)
downloademacs-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.c140
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);