comparison src/macterm.c @ 65346:88cf9abcfe60

(struct xlfdpat_block, struct xlfdpat): New structs. (xlfdpat_destroy, xlfdpat_create, xlfdpat_exact_p) (xlfdpat_block_match_1, xlfdpat_match): New functions. (xlfdpat_block_match): New macro. (mac_to_x_fontname): Don't use tolower for non-ASCII characters. (x_font_name_to_mac_font_name): Set coding.dst_multibyte to 0. (add_font_name_table_entry): Increase font_name_table_size more rapidly. (mac_c_string_match): Remove function. (mac_do_list_fonts): Use XLFD pattern match instead of regular expression match.
author YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
date Tue, 06 Sep 2005 08:07:32 +0000
parents ac7314b59792
children 44af31946762 46dfd959d88a 10fe5fadaf89
comparison
equal deleted inserted replaced
65345:7e5239b21c5d 65346:88cf9abcfe60
6082 #endif /* MAC_TODO */ 6082 #endif /* MAC_TODO */
6083 } 6083 }
6084 6084
6085 6085
6086 /*********************************************************************** 6086 /***********************************************************************
6087 XLFD Pattern Match
6088 ***********************************************************************/
6089
6090 /* An XLFD pattern is divided into blocks delimited by '*'. This
6091 structure holds information for each block. */
6092 struct xlfdpat_block
6093 {
6094 /* Length of the pattern string in this block. Non-zero except for
6095 the first and the last blocks. */
6096 int len;
6097
6098 /* Pattern string except the last character in this block. The last
6099 character is replaced with NUL in order to use it as a
6100 sentinel. */
6101 unsigned char *pattern;
6102
6103 /* Last character of the pattern string. Must not be '?'. */
6104 unsigned char last_char;
6105
6106 /* One of the tables for the Boyer-Moore string search. It
6107 specifies the number of positions to proceed for each character
6108 with which the match fails. */
6109 int skip[256];
6110
6111 /* The skip value for the last character in the above `skip' is
6112 assigned to `infinity' in order to simplify a loop condition.
6113 The original value is saved here. */
6114 int last_char_skip;
6115 };
6116
6117 struct xlfdpat
6118 {
6119 /* Normalized pattern string. "Normalized" means that capital
6120 letters are lowered, blocks are not empty except the first and
6121 the last ones, and trailing '?'s in a block that is not the last
6122 one are moved to the next one. The last character in each block
6123 is replaced with NUL. */
6124 unsigned char *buf;
6125
6126 /* Number of characters except '*'s and trailing '?'s in the
6127 normalized pattern string. */
6128 int nchars;
6129
6130 /* Number of trailing '?'s in the normalized pattern string. */
6131 int trailing_anychars;
6132
6133 /* Number of blocks and information for each block. The latter is
6134 NULL if the pattern is exact (no '*' or '?' in it). */
6135 int nblocks;
6136 struct xlfdpat_block *blocks;
6137 };
6138
6139 static void
6140 xlfdpat_destroy (pat)
6141 struct xlfdpat *pat;
6142 {
6143 if (pat)
6144 {
6145 if (pat->buf)
6146 {
6147 if (pat->blocks)
6148 xfree (pat->blocks);
6149 xfree (pat->buf);
6150 }
6151 xfree (pat);
6152 }
6153 }
6154
6155 static struct xlfdpat *
6156 xlfdpat_create (pattern)
6157 char *pattern;
6158 {
6159 struct xlfdpat *pat;
6160 int nblocks, i, skip;
6161 unsigned char last_char, *p, *q, *anychar_head;
6162 struct xlfdpat_block *blk;
6163
6164 pat = xmalloc (sizeof (struct xlfdpat));
6165 if (pat == NULL)
6166 goto error;
6167
6168 pat->buf = xmalloc (strlen (pattern) + 1);
6169 if (pat->buf == NULL)
6170 goto error;
6171
6172 /* Normalize the pattern string and store it to `pat->buf'. */
6173 nblocks = 0;
6174 anychar_head = NULL;
6175 q = pat->buf;
6176 last_char = '\0';
6177 for (p = pattern; *p; p++)
6178 {
6179 unsigned char c = *p;
6180
6181 if (c == '*')
6182 if (last_char == '*')
6183 /* ...a** -> ...a* */
6184 continue;
6185 else
6186 {
6187 if (last_char == '?')
6188 if (anychar_head > pat->buf && *(anychar_head - 1) == '*')
6189 /* ...*??* -> ...*?? */
6190 continue;
6191 else
6192 /* ...a??* -> ...a*?? */
6193 {
6194 *anychar_head++ = '*';
6195 c = '?';
6196 }
6197 nblocks++;
6198 }
6199 else if (c == '?')
6200 {
6201 if (last_char != '?')
6202 anychar_head = q;
6203 }
6204 else
6205 /* On Mac OS X 10.3, tolower also converts non-ASCII
6206 characters for some locales. */
6207 if (isascii (c))
6208 c = tolower (c);
6209
6210 *q++ = last_char = c;
6211 }
6212 *q = '\0';
6213 nblocks++;
6214 pat->nblocks = nblocks;
6215 if (last_char != '?')
6216 pat->trailing_anychars = 0;
6217 else
6218 {
6219 pat->trailing_anychars = q - anychar_head;
6220 q = anychar_head;
6221 }
6222 pat->nchars = q - pat->buf - (nblocks - 1);
6223
6224 if (anychar_head == NULL && nblocks == 1)
6225 {
6226 /* The pattern is exact. */
6227 pat->blocks = NULL;
6228 return pat;
6229 }
6230
6231 pat->blocks = xmalloc (sizeof (struct xlfdpat_block) * nblocks);
6232 if (pat->blocks == NULL)
6233 goto error;
6234
6235 /* Divide the normalized pattern into blocks. */
6236 p = pat->buf;
6237 for (blk = pat->blocks; blk < pat->blocks + nblocks - 1; blk++)
6238 {
6239 blk->pattern = p;
6240 while (*p != '*')
6241 p++;
6242 blk->len = p - blk->pattern;
6243 p++;
6244 }
6245 blk->pattern = p;
6246 blk->len = q - blk->pattern;
6247
6248 /* Setup a table for the Boyer-Moore string search. */
6249 for (blk = pat->blocks; blk < pat->blocks + nblocks; blk++)
6250 if (blk->len != 0)
6251 {
6252 blk->last_char = blk->pattern[blk->len - 1];
6253 blk->pattern[blk->len - 1] = '\0';
6254
6255 for (skip = 1; skip < blk->len; skip++)
6256 if (blk->pattern[blk->len - skip - 1] == '?')
6257 break;
6258
6259 for (i = 0; i < 256; i++)
6260 blk->skip[i] = skip;
6261
6262 p = blk->pattern + (blk->len - skip);
6263 while (--skip > 0)
6264 blk->skip[*p++] = skip;
6265
6266 blk->last_char_skip = blk->skip[blk->last_char];
6267 }
6268
6269 return pat;
6270
6271 error:
6272 xlfdpat_destroy (pat);
6273 return NULL;
6274 }
6275
6276 static INLINE int
6277 xlfdpat_exact_p (pat)
6278 struct xlfdpat *pat;
6279 {
6280 return (pat)->blocks == NULL;
6281 }
6282
6283 /* Return the first string in STRING + 0, ..., STRING + START_MAX such
6284 that the pattern in *BLK matches with its prefix. Return NULL
6285 there is no such strings. STRING must be lowered in advance. */
6286
6287 static char *
6288 xlfdpat_block_match_1 (blk, string, start_max)
6289 struct xlfdpat_block *blk;
6290 unsigned char *string;
6291 int start_max;
6292 {
6293 int start, infinity;
6294 unsigned char *p, *s;
6295
6296 xassert (blk->len > 0);
6297 xassert (start_max + blk->len <= strlen (string));
6298 xassert (blk->pattern[blk->len - 1] != '?');
6299
6300 /* See the comments in the function `boyer_moore' (search.c) for the
6301 use of `infinity'. */
6302 infinity = start_max + blk->len + 1;
6303 blk->skip[blk->last_char] = infinity;
6304
6305 start = 0;
6306 do
6307 {
6308 /* Check the last character of the pattern. */
6309 s = string + blk->len - 1;
6310 do
6311 {
6312 start += blk->skip[*(s + start)];
6313 }
6314 while (start <= start_max);
6315
6316 if (start < infinity)
6317 /* Couldn't find the last character. */
6318 return NULL;
6319
6320 /* No less than `infinity' means we could find the last
6321 character at `s[start - infinity]'. */
6322 start -= infinity;
6323
6324 /* Check the remaining characters. We prefer making no-'?'
6325 cases faster because the use of '?' is really rare. */
6326 p = blk->pattern;
6327 s = string + start;
6328 do
6329 {
6330 while (*p++ == *s++)
6331 ;
6332 }
6333 while (*(p - 1) == '?');
6334
6335 if (*(p - 1) == '\0')
6336 /* Matched. */
6337 return string + start;
6338
6339 /* Didn't match. */
6340 start += blk->last_char_skip;
6341 }
6342 while (start <= start_max);
6343
6344 return NULL;
6345 }
6346
6347 #define xlfdpat_block_match(b, s, m) \
6348 ((b)->len == 1 ? memchr ((s), (b)->last_char, (m) + 1) \
6349 : xlfdpat_block_match_1 (b, s, m))
6350
6351 /* Check if XLFD pattern PAT, which is generated by `xfldpat_create',
6352 matches with STRING. STRING must be lowered in advance. */
6353
6354 static int
6355 xlfdpat_match (pat, string)
6356 struct xlfdpat *pat;
6357 unsigned char *string;
6358 {
6359 int str_len, nblocks, i, start_max;
6360 struct xlfdpat_block *blk;
6361 unsigned char *s;
6362
6363 xassert (pat->nblocks > 0);
6364
6365 if (xlfdpat_exact_p (pat))
6366 return strcmp (pat->buf, string) == 0;
6367
6368 /* The number of the characters in the string must not be smaller
6369 than that in the pattern. */
6370 str_len = strlen (string);
6371 if (str_len < pat->nchars + pat->trailing_anychars)
6372 return 0;
6373
6374 /* Chop off the trailing '?'s. */
6375 str_len -= pat->trailing_anychars;
6376
6377 /* The last block. When it is non-empty, it must match at the end
6378 of the string. */
6379 nblocks = pat->nblocks;
6380 blk = pat->blocks + (nblocks - 1);
6381 if (nblocks == 1)
6382 /* The last block is also the first one. */
6383 return (str_len == blk->len
6384 && (blk->len == 0 || xlfdpat_block_match (blk, string, 0)));
6385 else if (blk->len != 0)
6386 if (!xlfdpat_block_match (blk, string + (str_len - blk->len), 0))
6387 return 0;
6388
6389 /* The first block. When it is non-empty, it must match at the
6390 beginning of the string. */
6391 blk = pat->blocks;
6392 if (blk->len != 0)
6393 {
6394 s = xlfdpat_block_match (blk, string, 0);
6395 if (s == NULL)
6396 return 0;
6397 string = s + blk->len;
6398 }
6399
6400 /* The rest of the blocks. */
6401 start_max = str_len - pat->nchars;
6402 for (i = 1, blk++; i < nblocks - 1; i++, blk++)
6403 {
6404 s = xlfdpat_block_match (blk, string, start_max);
6405 if (s == NULL)
6406 return 0;
6407 start_max -= s - string;
6408 string = s + blk->len;
6409 }
6410
6411 return 1;
6412 }
6413
6414
6415 /***********************************************************************
6087 Fonts 6416 Fonts
6088 ***********************************************************************/ 6417 ***********************************************************************/
6089 6418
6090 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */ 6419 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6091 6420
6176 Style style; 6505 Style style;
6177 char *charset; 6506 char *charset;
6178 { 6507 {
6179 Str31 foundry, cs; 6508 Str31 foundry, cs;
6180 Str255 family; 6509 Str255 family;
6181 char xf[256], *result, *p; 6510 char xf[256], *result;
6511 unsigned char *p;
6182 6512
6183 if (sscanf (name, "%31[^-]-%255[^-]-%31s", foundry, family, cs) == 3) 6513 if (sscanf (name, "%31[^-]-%255[^-]-%31s", foundry, family, cs) == 3)
6184 charset = cs; 6514 charset = cs;
6185 else 6515 else
6186 { 6516 {
6193 size, size * 10, size ? 75 : 0, size ? 75 : 0, size * 10, charset); 6523 size, size * 10, size ? 75 : 0, size ? 75 : 0, size * 10, charset);
6194 6524
6195 result = xmalloc (strlen (foundry) + strlen (family) + strlen (xf) + 3 + 1); 6525 result = xmalloc (strlen (foundry) + strlen (family) + strlen (xf) + 3 + 1);
6196 sprintf (result, "-%s-%s-%s", foundry, family, xf); 6526 sprintf (result, "-%s-%s-%s", foundry, family, xf);
6197 for (p = result; *p; p++) 6527 for (p = result; *p; p++)
6198 *p = tolower(*p); 6528 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
6529 for some locales. */
6530 if (isascii (*p))
6531 *p = tolower (*p);
6199 return result; 6532 return result;
6200 } 6533 }
6201 6534
6202 6535
6203 /* Convert an X font spec to the corresponding mac font name, which 6536 /* Convert an X font spec to the corresponding mac font name, which
6251 strcpy (mf, mf_decoded); 6584 strcpy (mf, mf_decoded);
6252 else 6585 else
6253 { 6586 {
6254 setup_coding_system (coding_system, &coding); 6587 setup_coding_system (coding_system, &coding);
6255 coding.src_multibyte = 1; 6588 coding.src_multibyte = 1;
6256 coding.dst_multibyte = 1; 6589 coding.dst_multibyte = 0;
6257 coding.mode |= CODING_MODE_LAST_BLOCK; 6590 coding.mode |= CODING_MODE_LAST_BLOCK;
6258 encode_coding (&coding, mf_decoded, mf, 6591 encode_coding (&coding, mf_decoded, mf,
6259 strlen (mf_decoded), sizeof (Str255) - 1); 6592 strlen (mf_decoded), sizeof (Str255) - 1);
6260 mf[coding.produced] = '\0'; 6593 mf[coding.produced] = '\0';
6261 } 6594 }
6265 static void 6598 static void
6266 add_font_name_table_entry (char *font_name) 6599 add_font_name_table_entry (char *font_name)
6267 { 6600 {
6268 if (font_name_table_size == 0) 6601 if (font_name_table_size == 0)
6269 { 6602 {
6270 font_name_table_size = 16; 6603 font_name_table_size = 256;
6271 font_name_table = (char **) 6604 font_name_table = (char **)
6272 xmalloc (font_name_table_size * sizeof (char *)); 6605 xmalloc (font_name_table_size * sizeof (char *));
6273 } 6606 }
6274 else if (font_name_count + 1 >= font_name_table_size) 6607 else if (font_name_count + 1 >= font_name_table_size)
6275 { 6608 {
6276 font_name_table_size += 16; 6609 font_name_table_size *= 2;
6277 font_name_table = (char **) 6610 font_name_table = (char **)
6278 xrealloc (font_name_table, 6611 xrealloc (font_name_table,
6279 font_name_table_size * sizeof (char *)); 6612 font_name_table_size * sizeof (char *));
6280 } 6613 }
6281 6614
6496 11, /* AVGWIDTH */ 6829 11, /* AVGWIDTH */
6497 -1 6830 -1
6498 }; 6831 };
6499 6832
6500 static Lisp_Object 6833 static Lisp_Object
6501 mac_c_string_match (regexp, string, nonspecial, exact)
6502 Lisp_Object regexp;
6503 const char *string, *nonspecial;
6504 int exact;
6505 {
6506 if (exact)
6507 {
6508 if (strcmp (string, nonspecial) == 0)
6509 return build_string (string);
6510 }
6511 else if (strstr (string, nonspecial))
6512 {
6513 Lisp_Object str = build_string (string);
6514
6515 if (fast_string_match (regexp, str) >= 0)
6516 return str;
6517 }
6518
6519 return Qnil;
6520 }
6521
6522 static Lisp_Object
6523 mac_do_list_fonts (pattern, maxnames) 6834 mac_do_list_fonts (pattern, maxnames)
6524 char *pattern; 6835 char *pattern;
6525 int maxnames; 6836 int maxnames;
6526 { 6837 {
6527 int i, n_fonts = 0; 6838 int i, n_fonts = 0;
6528 Lisp_Object font_list = Qnil, pattern_regex, fontname; 6839 Lisp_Object font_list = Qnil;
6529 char *regex = (char *) alloca (strlen (pattern) * 2 + 3); 6840 struct xlfdpat *pat;
6530 char *scaled, *ptr; 6841 char *scaled, *ptr;
6531 int scl_val[XLFD_SCL_LAST], *field, *val; 6842 int scl_val[XLFD_SCL_LAST], *field, *val;
6532 char *longest_start, *cur_start, *nonspecial; 6843 int exact;
6533 int longest_len, exact;
6534 6844
6535 if (font_name_table == NULL) /* Initialize when first used. */ 6845 if (font_name_table == NULL) /* Initialize when first used. */
6536 init_font_name_table (); 6846 init_font_name_table ();
6537 6847
6538 for (i = 0; i < XLFD_SCL_LAST; i++) 6848 for (i = 0; i < XLFD_SCL_LAST; i++)
6586 : -1)); 6896 : -1));
6587 } 6897 }
6588 else 6898 else
6589 scl_val[XLFD_SCL_PIXEL_SIZE] = -1; 6899 scl_val[XLFD_SCL_PIXEL_SIZE] = -1;
6590 6900
6591 ptr = regex; 6901 pat = xlfdpat_create (pattern);
6592 *ptr++ = '^'; 6902 if (pat == NULL)
6593 6903 return Qnil;
6594 longest_start = cur_start = ptr; 6904
6595 longest_len = 0; 6905 exact = xlfdpat_exact_p (pat);
6596 exact = 1; 6906
6597 6907 for (i = 0; i < font_name_count; i++)
6598 /* Turn pattern into a regexp and do a regexp match. Also find the 6908 {
6599 longest substring containing no special characters. */ 6909 if (xlfdpat_match (pat, font_name_table[i]))
6600 for (; *pattern; pattern++)
6601 {
6602 if (*pattern == '?' || *pattern == '*')
6603 { 6910 {
6604 if (ptr - cur_start > longest_len) 6911 font_list = Fcons (build_string (font_name_table[i]), font_list);
6605 {
6606 longest_start = cur_start;
6607 longest_len = ptr - cur_start;
6608 }
6609 exact = 0;
6610
6611 if (*pattern == '?')
6612 *ptr++ = '.';
6613 else /* if (*pattern == '*') */
6614 {
6615 *ptr++ = '.';
6616 *ptr++ = '*';
6617 }
6618 cur_start = ptr;
6619 }
6620 else
6621 *ptr++ = tolower (*pattern);
6622 }
6623
6624 if (ptr - cur_start > longest_len)
6625 {
6626 longest_start = cur_start;
6627 longest_len = ptr - cur_start;
6628 }
6629
6630 *ptr = '$';
6631 *(ptr + 1) = '\0';
6632
6633 nonspecial = xmalloc (longest_len + 1);
6634 strncpy (nonspecial, longest_start, longest_len);
6635 nonspecial[longest_len] = '\0';
6636
6637 pattern_regex = build_string (regex);
6638
6639 for (i = 0; i < font_name_count; i++)
6640 {
6641 fontname = mac_c_string_match (pattern_regex, font_name_table[i],
6642 nonspecial, exact);
6643 if (!NILP (fontname))
6644 {
6645 font_list = Fcons (fontname, font_list);
6646 if (exact || maxnames > 0 && ++n_fonts >= maxnames) 6912 if (exact || maxnames > 0 && ++n_fonts >= maxnames)
6647 break; 6913 break;
6648 } 6914 }
6649 else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 6915 else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0
6650 && (ptr = strstr (font_name_table[i], "-0-0-0-0-m-0-"))) 6916 && (ptr = strstr (font_name_table[i], "-0-0-0-0-m-0-")))
6651 { 6917 {
6652 int former_len = ptr - font_name_table[i]; 6918 int former_len = ptr - font_name_table[i];
6653 6919
6654 scaled = xmalloc (strlen (font_name_table[i]) + 20 + 1); 6920 scaled = xmalloc (strlen (font_name_table[i]) + 20 + 1);
6921 if (scaled == NULL)
6922 continue;
6655 memcpy (scaled, font_name_table[i], former_len); 6923 memcpy (scaled, font_name_table[i], former_len);
6656 sprintf (scaled + former_len, 6924 sprintf (scaled + former_len,
6657 "-%d-%d-75-75-m-%d-%s", 6925 "-%d-%d-75-75-m-%d-%s",
6658 scl_val[XLFD_SCL_PIXEL_SIZE], 6926 scl_val[XLFD_SCL_PIXEL_SIZE],
6659 scl_val[XLFD_SCL_POINT_SIZE], 6927 scl_val[XLFD_SCL_POINT_SIZE],
6660 scl_val[XLFD_SCL_AVGWIDTH], 6928 scl_val[XLFD_SCL_AVGWIDTH],
6661 ptr + sizeof ("-0-0-0-0-m-0-") - 1); 6929 ptr + sizeof ("-0-0-0-0-m-0-") - 1);
6662 fontname = mac_c_string_match (pattern_regex, scaled, 6930
6663 nonspecial, exact); 6931 if (xlfdpat_match (pat, scaled))
6664 xfree (scaled);
6665 if (!NILP (fontname))
6666 { 6932 {
6667 font_list = Fcons (fontname, font_list); 6933 font_list = Fcons (build_string (scaled), font_list);
6934 xfree (scaled);
6668 if (exact || maxnames > 0 && ++n_fonts >= maxnames) 6935 if (exact || maxnames > 0 && ++n_fonts >= maxnames)
6669 break; 6936 break;
6670 } 6937 }
6938 else
6939 xfree (scaled);
6671 } 6940 }
6672 } 6941 }
6673 6942
6674 xfree (nonspecial); 6943 xlfdpat_destroy (pat);
6675 6944
6676 return font_list; 6945 return font_list;
6677 } 6946 }
6678 6947
6679 /* Return a list of names of available fonts matching PATTERN on frame F. 6948 /* Return a list of names of available fonts matching PATTERN on frame F.