+
+void
+xml_skip_internal_subset(struct xml_context *ctx)
+{
+ TRACE(ctx, "skip_internal_subset");
+ /* AlreadyParsed: '[' */
+ uns c;
+ while ((c = xml_get_char(ctx)) != ']')
+ {
+ if (c != '<')
+ continue;
+ if ((c = xml_get_char(ctx)) == '?')
+ {
+ xml_inc(ctx);
+ xml_skip_pi(ctx);
+ }
+ else if (c != '!')
+ xml_dec(ctx);
+ else if (xml_get_char(ctx) == '-')
+ {
+ xml_inc(ctx);
+ xml_skip_comment(ctx);
+ }
+ else
+ while ((c = xml_get_char(ctx)) != '>')
+ if (c == '\'' || c == '"')
+ while (xml_get_char(ctx) != c);
+ }
+ xml_dec(ctx);
+}
+
+/*** Validation of attribute values ***/
+
+static uns
+xml_check_tokens(char *value, uns first_cat, uns next_cat, uns seq)
+{
+ char *p = value;
+ uns u;
+ while (1)
+ {
+ p = utf8_32_get(p, &u);
+ if (!(xml_char_cat(u) & first_cat))
+ return 0;
+ while (*p & ~0x20)
+ {
+ p = utf8_32_get(p, &u);
+ if (!(xml_char_cat(u) & next_cat))
+ return 0;
+ }
+ if (!*p)
+ return 1;
+ if (!seq)
+ return 0;
+ p++;
+ }
+}
+
+static uns
+xml_is_name(struct xml_context *ctx, char *value)
+{
+ /* Name ::= NameStartChar (NameChar)* */
+ return xml_check_tokens(value, ctx->cat_sname, ctx->cat_name, 0);
+}
+
+static uns
+xml_is_names(struct xml_context *ctx, char *value)
+{
+ /* Names ::= Name (#x20 Name)* */
+ return xml_check_tokens(value, ctx->cat_sname, ctx->cat_name, 1);
+}
+
+static uns
+xml_is_nmtoken(struct xml_context *ctx, char *value)
+{
+ /* Nmtoken ::= (NameChar)+ */
+ return xml_check_tokens(value, ctx->cat_name, ctx->cat_name, 0);
+}
+
+static uns
+xml_is_nmtokens(struct xml_context *ctx, char *value)
+{
+ /* Nmtokens ::= Nmtoken (#x20 Nmtoken)* */
+ return xml_check_tokens(value, ctx->cat_name, ctx->cat_name, 1);
+}
+
+static void
+xml_err_attr_format(struct xml_context *ctx, struct xml_dtd_attr *dtd, char *type)
+{
+ xml_error(ctx, "Attribute %s in <%s> does not match the production of %s", dtd->name, dtd->elem->name, type);
+}
+
+void
+xml_validate_attr(struct xml_context *ctx, struct xml_dtd_attr *dtd, char *value)
+{
+ if (dtd->type == XML_ATTR_CDATA)
+ return;
+ xml_normalize_white(ctx, value);
+ switch (dtd->type)
+ {
+ case XML_ATTR_ID:
+ if (!xml_is_name(ctx, value))
+ xml_err_attr_format(ctx, dtd, "NAME");
+ //FIXME: add to a hash table
+ break;
+ case XML_ATTR_IDREF:
+ if (!xml_is_name(ctx, value))
+ xml_err_attr_format(ctx, dtd, "NAME");
+ // FIXME: find in hash table (beware forward references)
+ break;
+ case XML_ATTR_IDREFS:
+ if (!xml_is_names(ctx, value))
+ xml_err_attr_format(ctx, dtd, "NAMES");
+ // FIXME: find
+ break;
+ case XML_ATTR_ENTITY:
+ // FIXME
+ break;
+ case XML_ATTR_ENTITIES:
+ // FIXME
+ break;
+ case XML_ATTR_NMTOKEN:
+ if (!xml_is_nmtoken(ctx, value))
+ xml_err_attr_format(ctx, dtd, "NMTOKEN");
+ break;
+ case XML_ATTR_NMTOKENS:
+ if (!xml_is_nmtokens(ctx, value))
+ xml_err_attr_format(ctx, dtd, "NMTOKENS");
+ break;
+ case XML_ATTR_ENUM:
+ if (!xml_dtd_evals_find(ctx->dtd->tab_evals, dtd, value))
+ xml_error(ctx, "Attribute %s in <%s> contains an undefined enumeration value", dtd->name, dtd->elem->name);
+ break;
+ case XML_ATTR_NOTATION:
+ if (!xml_dtd_find_notn(ctx, value))
+ xml_error(ctx, "Attribute %s in <%s> contains an undefined notation", dtd->name, dtd->elem->name);
+ break;
+ }
+}