+static void
+free_font_capability (void *object)
+{
+ MFontCapability *cap = object;
+ int i;
+
+ if (cap->lang)
+ free (cap->lang);
+#ifdef HAVE_OTF
+ if (cap->script)
+ for (i = 0; i < MFONT_OTT_MAX; i++)
+ {
+ if (cap->features[i].str)
+ free (cap->features[i].str);
+ if (cap->features[i].tags)
+ free (cap->features[i].tags);
+ }
+#endif /* HAVE_OTF */
+ free (cap);
+}
+
+MFontCapability *
+mfont__get_capability (MSymbol sym)
+{
+ MFontCapability *cap = msymbol_get (sym, M_font_capability);
+ char *str, *p, *endp;
+ int i;
+
+ if (cap)
+ return cap;
+ str = MSYMBOL_NAME (sym);
+ if (str[0] != ':')
+ return NULL;
+ M17N_OBJECT (cap, free_font_capability, MERROR_FONT);
+ msymbol_put (sym, M_font_capability, cap);
+ M17N_OBJECT_UNREF (cap);
+ endp = str + MSYMBOL_NAMELEN (sym);
+ while (str < endp)
+ {
+ if (*str++ != ':')
+ continue;
+#ifdef HAVE_OTF
+ if (str[0] == 'o' && str[1] == 't' && str[2] == 'f' && str[3] == '=')
+ {
+ str += 4;
+ for (i = 0, p = str; i < 4 && p < endp; i++, p++);
+ if (i < 4)
+ break;
+ cap->script_tag = OTF_tag (str);
+ cap->script = find_script_from_otf_tag (cap->script_tag);
+ if (*p == '/')
+ {
+ for (i = 0, str = ++p; i < 4 && p < endp; i++, p++);
+ if (i < 4)
+ {
+ cap->script = Mnil;
+ break;
+ }
+ cap->langsys_tag = OTF_tag (str);
+ }
+ else
+ cap->langsys_tag = 0;
+
+ for (i = 0; i < MFONT_OTT_MAX; i++)
+ cap->features[i].nfeatures = -1;
+
+ while (*p == '=' || *p == '+')
+ {
+ int idx = *p == '=' ? MFONT_OTT_GSUB : MFONT_OTT_GPOS;
+
+ str = ++p;
+ while (p < endp && *p != '+') p++;
+ if (str < p)
+ {
+ int n;
+ /* We never have more than (p - str) tags. */
+ OTF_Tag *tags = alloca (sizeof (OTF_Tag) * (p - str));
+ char *p0;
+
+ cap->features[idx].str = malloc (p - str + 1);
+ for (i = n = 0, p0 = str; str + i < p; i++)
+ {
+ cap->features[idx].str[i] = str[i];
+ if (str[i] == ',' || str + i + 1 == p)
+ {
+ if (*p0 == '*')
+ tags[n] = 0;
+ else if (*p0 == '~')
+ tags[n] = OTF_tag (p0 + 1) | 0x80000000;
+ else
+ tags[n] = OTF_tag (p0);
+ n++;
+ p0 = str + i + 1;
+ }
+ }
+ cap->features[idx].str[i] = '\0';
+ cap->features[idx].nfeatures = n;
+ if (n > 0)
+ {
+ int size = sizeof (OTF_Tag) * n;
+
+ cap->features[idx].tags = malloc (size);
+ memcpy (cap->features[idx].tags, tags, size);
+ }
+ }
+ else
+ {
+ cap->features[idx].str = NULL;
+ cap->features[idx].nfeatures = 0;
+ }
+ }
+
+ for (i = 0; i < MFONT_OTT_MAX; i++)
+ if (cap->features[i].nfeatures < 0)
+ {
+ cap->features[i].str = strdup ("*");
+ cap->features[i].nfeatures = 1;
+ cap->features[i].tags = malloc (sizeof (OTF_Tag));
+ cap->features[i].tags[0] = 0;
+ }
+ str = p;
+ continue;
+ }
+#endif /* HAVE_OTF */
+ if (str[0] == 'l' && str[1] == 'a' && str[2] == 'n' && str[3] == 'g'
+ && str[4] == '=')
+ {
+ int count;
+
+ str += 5;
+ for (p = str, count = 2; p < endp && *p != ':'; p++)
+ if (*p == ',')
+ count++;
+ MTABLE_MALLOC (cap->lang, count, MERROR_FONT);
+ for (p = str, count = 0; p < endp && *p != ':'; p++)
+ if (*p == ',')
+ {
+ MSymbol lang = msymbol__with_len (str, p - str), sym;
+
+ if (msymbol_get (lang, Miso639_2))
+ cap->lang[count++] = lang;
+ else if ((sym = msymbol_get (lang, Miso639_1)) != Mnil)
+ cap->lang[count++] = sym;
+ else if (msymbol_get (lang, Mlanguage))
+ cap->lang[count++] = lang;
+ str = p + 1;
+ }
+ if (str < p)
+ cap->lang[count++] = msymbol__with_len (str, p - str);
+ cap->lang[count] = Mnil;
+ str = p;
+ }
+ else if (str[0] == 's' && str[1] == 'c' && str[2] == 'r' && str[3] == 'i'
+ && str[4] == 'p' && str[5] == 't' && str[6] == '=')
+ {
+ str += 7;
+ for (p = str; p < endp && *p != ':'; p++);
+ if (str < p)
+ cap->script = msymbol__with_len (str, p - str);
+ str = p;
+ }
+ }
+ return cap;
+}
+