aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard M. Stallman1998-01-09 22:34:48 +0000
committerRichard M. Stallman1998-01-09 22:34:48 +0000
commit1f24f4fdd2b7203aa75728a4437cb0520a8e6877 (patch)
treee4605350016c0460fc86a383d2700e54b72f12a6 /src
parent6bb762b32476cd8f778a17f225e657f079a41728 (diff)
downloademacs-1f24f4fdd2b7203aa75728a4437cb0520a8e6877.tar.gz
emacs-1f24f4fdd2b7203aa75728a4437cb0520a8e6877.zip
(Fformat): Do all the work directly--don't use doprnt.
Calculate the right size the first time, so no need to retry. Count chars and bytes in the result. Convert single-byte strings to multibyte as needed.
Diffstat (limited to 'src')
-rw-r--r--src/editfns.c290
1 files changed, 157 insertions, 133 deletions
diff --git a/src/editfns.c b/src/editfns.c
index 14c908243a1..7f47d596b13 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -132,7 +132,7 @@ DEFUN ("char-to-string", Fchar_to_string, Schar_to_string, 1, 1, 0,
132 CHECK_NUMBER (character, 0); 132 CHECK_NUMBER (character, 0);
133 133
134 len = CHAR_STRING (XFASTINT (character), workbuf, str); 134 len = CHAR_STRING (XFASTINT (character), workbuf, str);
135 return make_string (str, len); 135 return make_multibyte_string (str, 1, len);
136} 136}
137 137
138DEFUN ("string-to-char", Fstring_to_char, Sstring_to_char, 1, 1, 0, 138DEFUN ("string-to-char", Fstring_to_char, Sstring_to_char, 1, 1, 0,
@@ -151,48 +151,6 @@ A multibyte character is handled correctly.")
151 XSETFASTINT (val, 0); 151 XSETFASTINT (val, 0);
152 return val; 152 return val;
153} 153}
154
155DEFUN ("sref", Fsref, Ssref, 2, 2, 0,
156 "Return the character in STRING at INDEX. INDEX starts at 0.\n\
157A multibyte character is handled correctly.\n\
158INDEX not pointing at character boundary is an error.")
159 (str, idx)
160 Lisp_Object str, idx;
161{
162 register int idxval, len, i;
163 register unsigned char *p, *q;
164 register Lisp_Object val;
165
166 CHECK_STRING (str, 0);
167 CHECK_NUMBER (idx, 1);
168 idxval = XINT (idx);
169 if (idxval < 0 || idxval >= (len = XVECTOR (str)->size))
170 args_out_of_range (str, idx);
171
172 p = XSTRING (str)->data + idxval;
173 if (!NILP (current_buffer->enable_multibyte_characters)
174 && !CHAR_HEAD_P (*p)
175 && idxval > 0)
176 {
177 /* We must check if P points to a tailing byte of a multibyte
178 form. If so, we signal error. */
179 i = idxval - 1;
180 q = p - 1;
181 while (i > 0 && *q >= 0xA0) i--, q--;
182
183 if (*q == LEADING_CODE_COMPOSITION)
184 i = multibyte_form_length (XSTRING (str)->data + i, len - i);
185 else
186 i = BYTES_BY_CHAR_HEAD (*q);
187 if (q + i > p)
188 error ("Not character boundary");
189 }
190
191 len = XSTRING (str)->size - idxval;
192 XSETFASTINT (val, STRING_CHAR (p, len));
193 return val;
194}
195
196 154
197static Lisp_Object 155static Lisp_Object
198buildmark (charpos, bytepos) 156buildmark (charpos, bytepos)
@@ -887,7 +845,7 @@ DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
887 error ("Invalid time specification"); 845 error ("Invalid time specification");
888 846
889 /* This is probably enough. */ 847 /* This is probably enough. */
890 size = XSTRING (format_string)->size * 6 + 50; 848 size = XSTRING (format_string)->size_byte * 6 + 50;
891 849
892 while (1) 850 while (1)
893 { 851 {
@@ -1288,7 +1246,7 @@ void
1288general_insert_function (insert_func, insert_from_string_func, 1246general_insert_function (insert_func, insert_from_string_func,
1289 inherit, nargs, args) 1247 inherit, nargs, args)
1290 void (*insert_func) P_ ((unsigned char *, int)); 1248 void (*insert_func) P_ ((unsigned char *, int));
1291 void (*insert_from_string_func) P_ ((Lisp_Object, int, int, int)); 1249 void (*insert_from_string_func) P_ ((Lisp_Object, int, int, int, int, int));
1292 int inherit, nargs; 1250 int inherit, nargs;
1293 register Lisp_Object *args; 1251 register Lisp_Object *args;
1294{ 1252{
@@ -1312,7 +1270,10 @@ general_insert_function (insert_func, insert_from_string_func,
1312 } 1270 }
1313 else if (STRINGP (val)) 1271 else if (STRINGP (val))
1314 { 1272 {
1315 (*insert_from_string_func) (val, 0, XSTRING (val)->size, inherit); 1273 (*insert_from_string_func) (val, 0, 0,
1274 XSTRING (val)->size,
1275 XSTRING (val)->size_byte,
1276 inherit);
1316 } 1277 }
1317 else 1278 else
1318 { 1279 {
@@ -1469,7 +1430,7 @@ make_buffer_string (start, end, props)
1469 if (start < GPT && GPT < end) 1430 if (start < GPT && GPT < end)
1470 move_gap (start); 1431 move_gap (start);
1471 1432
1472 result = make_uninit_string (end_byte - start_byte); 1433 result = make_uninit_multibyte_string (end - start, end_byte - start_byte);
1473 bcopy (BYTE_POS_ADDR (start_byte), XSTRING (result)->data, 1434 bcopy (BYTE_POS_ADDR (start_byte), XSTRING (result)->data,
1474 end_byte - start_byte); 1435 end_byte - start_byte);
1475 1436
@@ -1873,7 +1834,9 @@ Both characters must have the same length of multi-byte form.")
1873DEFUN ("translate-region", Ftranslate_region, Stranslate_region, 3, 3, 0, 1834DEFUN ("translate-region", Ftranslate_region, Stranslate_region, 3, 3, 0,
1874 "From START to END, translate characters according to TABLE.\n\ 1835 "From START to END, translate characters according to TABLE.\n\
1875TABLE is a string; the Nth character in it is the mapping\n\ 1836TABLE is a string; the Nth character in it is the mapping\n\
1876for the character with code N. Returns the number of characters changed.") 1837for the character with code N.\n\
1838This function does not alter multibyte characters.\n\
1839It returns the number of characters changed.")
1877 (start, end, table) 1840 (start, end, table)
1878 Lisp_Object start; 1841 Lisp_Object start;
1879 Lisp_Object end; 1842 Lisp_Object end;
@@ -1884,38 +1847,40 @@ for the character with code N. Returns the number of characters changed.")
1884 register int nc; /* New character. */ 1847 register int nc; /* New character. */
1885 int cnt; /* Number of changes made. */ 1848 int cnt; /* Number of changes made. */
1886 int size; /* Size of translate table. */ 1849 int size; /* Size of translate table. */
1887 int charpos; 1850 int pos;
1888 1851
1889 validate_region (&start, &end); 1852 validate_region (&start, &end);
1890 CHECK_STRING (table, 2); 1853 CHECK_STRING (table, 2);
1891 1854
1892 size = XSTRING (table)->size; 1855 size = XSTRING (table)->size_byte;
1893 tt = XSTRING (table)->data; 1856 tt = XSTRING (table)->data;
1894 1857
1895 pos_byte = CHAR_TO_BYTE (XINT (start)); 1858 pos_byte = CHAR_TO_BYTE (XINT (start));
1896 stop = CHAR_TO_BYTE (XINT (end)); 1859 stop = CHAR_TO_BYTE (XINT (end));
1897 modify_region (current_buffer, XINT (start), XINT (end)); 1860 modify_region (current_buffer, XINT (start), XINT (end));
1898 charpos = XINT (start); 1861 pos = XINT (start);
1899 1862
1900 cnt = 0; 1863 cnt = 0;
1901 for (; pos_byte < stop; ++pos_byte) 1864 for (; pos_byte < stop; )
1902 { 1865 {
1903 register unsigned char *p = BYTE_POS_ADDR (pos_byte); 1866 register unsigned char *p = BYTE_POS_ADDR (pos_byte);
1904 register int oc = *p; /* Old character. */ 1867 int len;
1905 if (CHAR_HEAD_P (*p)) 1868 int oc;
1906 charpos++;
1907 1869
1908 if (oc < size) 1870 oc = STRING_CHAR_AND_LENGTH (p, stop - pos_byte, len);
1871 if (oc < size && len == 1)
1909 { 1872 {
1910 nc = tt[oc]; 1873 nc = tt[oc];
1911 if (nc != oc) 1874 if (nc != oc)
1912 { 1875 {
1913 record_change (charpos, 1); 1876 record_change (pos, 1);
1914 *p = nc; 1877 *p = nc;
1915 signal_after_change (charpos, 1, 1); 1878 signal_after_change (pos, 1, 1);
1916 ++cnt; 1879 ++cnt;
1917 } 1880 }
1918 } 1881 }
1882 pos_byte += len;
1883 pos++;
1919 } 1884 }
1920 1885
1921 return make_number (cnt); 1886 return make_number (cnt);
@@ -2103,11 +2068,12 @@ minibuffer contents show.")
2103 } 2068 }
2104 if (XSTRING (val)->size > message_length) 2069 if (XSTRING (val)->size > message_length)
2105 { 2070 {
2106 message_length = XSTRING (val)->size; 2071 message_length = XSTRING (val)->size_byte;
2107 message_text = (char *)xrealloc (message_text, message_length); 2072 message_text = (char *)xrealloc (message_text, message_length);
2108 } 2073 }
2109 bcopy (XSTRING (val)->data, message_text, XSTRING (val)->size); 2074 bcopy (XSTRING (val)->data, message_text, XSTRING (val)->size_byte);
2110 message2 (message_text, XSTRING (val)->size); 2075 message2 (message_text, XSTRING (val)->size_byte,
2076 STRING_MULTIBYTE (val));
2111 return val; 2077 return val;
2112 } 2078 }
2113} 2079}
@@ -2151,13 +2117,13 @@ minibuffer contents show.")
2151 message_text = (char *)xmalloc (80); 2117 message_text = (char *)xmalloc (80);
2152 message_length = 80; 2118 message_length = 80;
2153 } 2119 }
2154 if (XSTRING (val)->size > message_length) 2120 if (XSTRING (val)->size_byte > message_length)
2155 { 2121 {
2156 message_length = XSTRING (val)->size; 2122 message_length = XSTRING (val)->size_byte;
2157 message_text = (char *)xrealloc (message_text, message_length); 2123 message_text = (char *)xrealloc (message_text, message_length);
2158 } 2124 }
2159 bcopy (XSTRING (val)->data, message_text, XSTRING (val)->size); 2125 bcopy (XSTRING (val)->data, message_text, XSTRING (val)->size_byte);
2160 message2 (message_text, XSTRING (val)->size); 2126 message2 (message_text, XSTRING (val)->size_byte);
2161 return val; 2127 return val;
2162#endif /* not HAVE_MENUS */ 2128#endif /* not HAVE_MENUS */
2163 } 2129 }
@@ -2195,6 +2161,15 @@ DEFUN ("current-message", Fcurrent_message, Scurrent_message, 0, 0, 0,
2195 : Qnil); 2161 : Qnil);
2196} 2162}
2197 2163
2164/* Number of bytes that STRING will occupy when put into the result.
2165 MULTIBYTE is nonzero if the result should be multibyte. */
2166
2167#define CONVERTED_BYTE_SIZE(MULTIBYTE, STRING) \
2168 (((MULTIBYTE) && ! STRING_MULTIBYTE (STRING)) \
2169 ? XSTRING (STRING)->size_byte \
2170 : count_size_as_multibyte (XSTRING (STRING)->data, \
2171 XSTRING (STRING)->size_byte))
2172
2198DEFUN ("format", Fformat, Sformat, 1, MANY, 0, 2173DEFUN ("format", Fformat, Sformat, 1, MANY, 0,
2199 "Format a string out of a control-string and arguments.\n\ 2174 "Format a string out of a control-string and arguments.\n\
2200The first argument is a control string.\n\ 2175The first argument is a control string.\n\
@@ -2216,22 +2191,39 @@ Use %% to put a single % into the output.")
2216{ 2191{
2217 register int n; /* The number of the next arg to substitute */ 2192 register int n; /* The number of the next arg to substitute */
2218 register int total = 5; /* An estimate of the final length */ 2193 register int total = 5; /* An estimate of the final length */
2219 char *buf; 2194 char *buf, *p;
2220 register unsigned char *format, *end; 2195 register unsigned char *format, *end;
2221 int length; 2196 int length, nchars;
2197 /* Nonzero if the output should be a multibyte string,
2198 which is true if any of the inputs is one. */
2199 int multibyte = 0;
2200 unsigned char *this_format;
2201 int longest_format = 0;
2202
2222 extern char *index (); 2203 extern char *index ();
2204
2223 /* It should not be necessary to GCPRO ARGS, because 2205 /* It should not be necessary to GCPRO ARGS, because
2224 the caller in the interpreter should take care of that. */ 2206 the caller in the interpreter should take care of that. */
2225 2207
2208 for (n = 0; n < nargs; n++)
2209 if (STRINGP (args[n]) && STRING_MULTIBYTE (args[n]))
2210 multibyte = 1;
2211
2226 CHECK_STRING (args[0], 0); 2212 CHECK_STRING (args[0], 0);
2227 format = XSTRING (args[0])->data; 2213 format = XSTRING (args[0])->data;
2228 end = format + XSTRING (args[0])->size; 2214 end = format + XSTRING (args[0])->size_byte;
2215
2216 /* Make room in result for all the non-%-codes in the control string. */
2217 total += CONVERTED_BYTE_SIZE (multibyte, args[0]);
2218
2219 /* Add to TOTAL enough space to hold the converted arguments. */
2229 2220
2230 n = 0; 2221 n = 0;
2231 while (format != end) 2222 while (format != end)
2232 if (*format++ == '%') 2223 if (*format++ == '%')
2233 { 2224 {
2234 int minlen; 2225 int minlen, thissize = 0;
2226 unsigned char *this_format_start = format - 1;
2235 2227
2236 /* Process a numeric arg and skip it. */ 2228 /* Process a numeric arg and skip it. */
2237 minlen = atoi (format); 2229 minlen = atoi (format);
@@ -2242,6 +2234,9 @@ Use %% to put a single % into the output.")
2242 || *format == '-' || *format == ' ' || *format == '.') 2234 || *format == '-' || *format == ' ' || *format == '.')
2243 format++; 2235 format++;
2244 2236
2237 if (format - this_format_start + 1 > longest_format)
2238 longest_format = format - this_format_start + 1;
2239
2245 if (*format == '%') 2240 if (*format == '%')
2246 format++; 2241 format++;
2247 else if (++n >= nargs) 2242 else if (++n >= nargs)
@@ -2264,11 +2259,7 @@ Use %% to put a single % into the output.")
2264 string: 2259 string:
2265 if (*format != 's' && *format != 'S') 2260 if (*format != 's' && *format != 'S')
2266 error ("format specifier doesn't match argument type"); 2261 error ("format specifier doesn't match argument type");
2267 total += XSTRING (args[n])->size; 2262 thissize = CONVERTED_BYTE_SIZE (multibyte, args[n]);
2268 /* We have to put an arbitrary limit on minlen
2269 since otherwise it could make alloca fail. */
2270 if (minlen < XSTRING (args[n])->size + 1000)
2271 total += minlen;
2272 } 2263 }
2273 /* Would get MPV otherwise, since Lisp_Int's `point' to low memory. */ 2264 /* Would get MPV otherwise, since Lisp_Int's `point' to low memory. */
2274 else if (INTEGERP (args[n]) && *format != 's') 2265 else if (INTEGERP (args[n]) && *format != 's')
@@ -2281,22 +2272,14 @@ Use %% to put a single % into the output.")
2281 if (*format == 'e' || *format == 'f' || *format == 'g') 2272 if (*format == 'e' || *format == 'f' || *format == 'g')
2282 args[n] = Ffloat (args[n]); 2273 args[n] = Ffloat (args[n]);
2283#endif 2274#endif
2284 total += 30; 2275 thissize = 30;
2285 /* We have to put an arbitrary limit on minlen
2286 since otherwise it could make alloca fail. */
2287 if (minlen < 1000)
2288 total += minlen;
2289 } 2276 }
2290#ifdef LISP_FLOAT_TYPE 2277#ifdef LISP_FLOAT_TYPE
2291 else if (FLOATP (args[n]) && *format != 's') 2278 else if (FLOATP (args[n]) && *format != 's')
2292 { 2279 {
2293 if (! (*format == 'e' || *format == 'f' || *format == 'g')) 2280 if (! (*format == 'e' || *format == 'f' || *format == 'g'))
2294 args[n] = Ftruncate (args[n], Qnil); 2281 args[n] = Ftruncate (args[n], Qnil);
2295 total += 30; 2282 thissize = 60;
2296 /* We have to put an arbitrary limit on minlen
2297 since otherwise it could make alloca fail. */
2298 if (minlen < 1000)
2299 total += minlen;
2300 } 2283 }
2301#endif 2284#endif
2302 else 2285 else
@@ -2307,64 +2290,106 @@ Use %% to put a single % into the output.")
2307 args[n] = tem; 2290 args[n] = tem;
2308 goto string; 2291 goto string;
2309 } 2292 }
2293
2294 if (thissize < minlen)
2295 thissize = minlen;
2296
2297 total += thissize + 4;
2310 } 2298 }
2311 2299
2312 { 2300 this_format = (unsigned char *) alloca (longest_format + 1);
2313 register int nstrings = n + 1;
2314 2301
2315 /* Allocate twice as many strings as we have %-escapes; floats occupy 2302 /* Allocate the space for the result.
2316 two slots, and we're not sure how many of those we have. */ 2303 Note that TOTAL is an overestimate. */
2317 register unsigned char **strings 2304 if (total < 1000)
2318 = (unsigned char **) alloca (2 * nstrings * sizeof (unsigned char *)); 2305 buf = (unsigned char *) alloca (total + 1);
2319 int i; 2306 else
2307 buf = (unsigned char *) xmalloc (total + 1);
2320 2308
2321 i = 0; 2309 p = buf;
2322 for (n = 0; n < nstrings; n++) 2310 nchars = 0;
2323 { 2311 n = 0;
2324 if (n >= nargs)
2325 strings[i++] = (unsigned char *) "";
2326 else if (INTEGERP (args[n]))
2327 /* We checked above that the corresponding format effector
2328 isn't %s, which would cause MPV. */
2329 strings[i++] = (unsigned char *) XINT (args[n]);
2330#ifdef LISP_FLOAT_TYPE
2331 else if (FLOATP (args[n]))
2332 {
2333 union { double d; char *half[2]; } u;
2334 2312
2335 u.d = XFLOAT (args[n])->data; 2313 /* Scan the format and store result in BUF. */
2336 strings[i++] = (unsigned char *) u.half[0]; 2314 format = XSTRING (args[0])->data;
2337 strings[i++] = (unsigned char *) u.half[1]; 2315 while (format != end)
2338 } 2316 {
2339#endif 2317 if (*format == '%')
2340 else if (i == 0) 2318 {
2341 /* The first string is treated differently 2319 int minlen;
2342 because it is the format string. */ 2320 unsigned char *this_format_start = format;
2343 strings[i++] = XSTRING (args[n])->data;
2344 else
2345 strings[i++] = (unsigned char *) XSTRING (args[n]);
2346 }
2347 2321
2348 /* Make room in result for all the non-%-codes in the control string. */ 2322 format++;
2349 total += XSTRING (args[0])->size;
2350 2323
2351 /* Format it in bigger and bigger buf's until it all fits. */ 2324 /* Process a numeric arg and skip it. */
2352 while (1) 2325 minlen = atoi (format);
2353 { 2326 if (minlen < 0)
2354 buf = (char *) alloca (total + 1); 2327 minlen = - minlen;
2355 buf[total - 1] = 0;
2356 2328
2357 length = doprnt_lisp (buf, total + 1, strings[0], 2329 while ((*format >= '0' && *format <= '9')
2358 end, i-1, (char **) strings + 1); 2330 || *format == '-' || *format == ' ' || *format == '.')
2359 if (buf[total - 1] == 0) 2331 format++;
2360 break;
2361 2332
2362 total *= 2; 2333 if (*format++ == '%')
2363 } 2334 {
2364 } 2335 *p++ = '%';
2336 nchars++;
2337 continue;
2338 }
2339
2340 ++n;
2341
2342 if (STRINGP (args[n]))
2343 {
2344 int padding, nbytes;
2345
2346 nbytes = copy_text (XSTRING (args[n])->data, p,
2347 XSTRING (args[n])->size_byte,
2348 STRING_MULTIBYTE (args[n]), multibyte);
2349 p += nbytes;
2350 nchars += XSTRING (args[n])->size;
2351
2352 /* If spec requires it, pad on right with spaces. */
2353 padding = minlen - XSTRING (args[n])->size;
2354 while (padding-- > 0)
2355 {
2356 *p++ = ' ';
2357 nchars++;
2358 }
2359 }
2360 else if (INTEGERP (args[n]) || FLOATP (args[n]))
2361 {
2362 int this_nchars;
2363
2364 bcopy (this_format_start, this_format,
2365 format - this_format_start);
2366 this_format[format - this_format_start] = 0;
2367
2368 sprintf (p, this_format, XINT (args[n]));
2369
2370 this_nchars = strlen (p);
2371 p += this_nchars;
2372 nchars += this_nchars;
2373 }
2374 }
2375 else if (multibyte && !STRING_MULTIBYTE (args[0]))
2376 {
2377 /* Convert a single-byte character to multibyte. */
2378 int len = copy_text (format, p, 1, 0, 1);
2379
2380 p += len;
2381 format++;
2382 nchars++;
2383 }
2384 else
2385 *p++ = *format++, nchars++;
2386 }
2387
2388 /* If we allocated BUF with malloc, free it too. */
2389 if (total >= 1000)
2390 xfree (buf);
2365 2391
2366 /* UNGCPRO; */ 2392 return make_multibyte_string (buf, nchars, p - buf);
2367 return make_string (buf, length);
2368} 2393}
2369 2394
2370/* VARARGS 1 */ 2395/* VARARGS 1 */
@@ -2823,7 +2848,6 @@ functions if all the text being accessed has this property.");
2823 defsubr (&Sgoto_char); 2848 defsubr (&Sgoto_char);
2824 defsubr (&Sstring_to_char); 2849 defsubr (&Sstring_to_char);
2825 defsubr (&Schar_to_string); 2850 defsubr (&Schar_to_string);
2826 defsubr (&Ssref);
2827 defsubr (&Sbuffer_substring); 2851 defsubr (&Sbuffer_substring);
2828 defsubr (&Sbuffer_substring_no_properties); 2852 defsubr (&Sbuffer_substring_no_properties);
2829 defsubr (&Sbuffer_string); 2853 defsubr (&Sbuffer_string);