Back to index

im-sdk  12.3.91
EIMIL.c
Go to the documentation of this file.
00001 /*
00002   EIMIL.c
00003     EIMIL parser/dictionary/data manager.
00004 */
00005 
00006 #include <stdio.h>
00007 #include <stdlib.h>
00008 #include <stdarg.h>
00009 #include <string.h>
00010 #include <EIMIL.h>
00011 #include "EIMILint.h"
00012 
00013 #define MAX_ELEMENT_DEPTH 10
00014 
00015 static int EIMIL_ID_counter = 0;
00016 #define EIMIL_ID_MAX ((1 << 15) - 1)
00017 
00018 static EIMIL_value EIMIL_t_val;
00019 
00020 static const unsigned char* EIMIL_xmlns_uri = "http://www.OpenI18N.org/EIMIL/NS/1.0";
00021 EIMIL_dictionary *pdic_internal = NULL;
00022 EIMIL_symbol *pEIMIL_nil_sym = NULL;
00023 EIMIL_symbol *pEIMIL_t_sym = NULL;
00024 EIMIL_symbol *pEIMIL_feedback_sym = NULL;
00025 EIMIL_symbol *pEIMIL_candidates_sym = NULL;
00026 
00027 static int EIMIL_inited = 0;
00028 
00029 /********************************************************************************
00030                      Char/Token manipulation functions.
00031  ********************************************************************************/
00032 
00033 #define EIMIL_isspace(c) ((c) == ' ' || (c) == '\n' || (c) == '\t' || (c) == '\r')
00034 #define EIMIL_istag_s(c) ((c) == '<')
00035 #define EIMIL_istag_e(c) ((c) == '>')
00036 #define EIMIL_isetag_mark(c) ((c) == '/')
00037 #define EIMIL_isPImark(c) ((c) == '?')
00038 #define EIMIL_isEXmark(c) ((c) == '!')
00039 #define EIMIL_isnewline(c) ((c) == '\n')
00040 #define EIMIL_isEq(c) ((c) == '=')
00041 #define EIMIL_ispresep(c) ((c) == ':')
00042 #define EIMIL_isquote(c) ((c) == '\x27' || (c) == '"')
00043 #define EIMIL_isrefstart(c) ((c) == '&')
00044 #define EIMIL_ischrefmark(c) ((c) == '#')
00045 #define EIMIL_ischrefhexmark(c) ((c) == 'x')
00046 #define EIMIL_ischrefdec(c) (((c) >= '0' && (c) <= '9'))
00047 #define EIMIL_chrefdec(c) ((c) - '0')
00048 #define EIMIL_ischrefhex(c) (((c) >= '0' && (c) <= '9')        \
00049                              || ((c) >= 'a' && (c) <= 'f')     \
00050                              || ((c) >= 'A' && (c) <= 'F'))
00051 #define EIMIL_chrefhex(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
00052                            ((c) >= 'a' && (c) <= 'f') ? ((c) - 'a') : ((c) - 'A'))
00053 #define EIMIL_isrefend(c) ((c) == ';')
00054 
00055 #define EIMIL_UTF32_EBYTE_MAX_FACTOR sizeof(UTF32)
00056 
00057 /* This function resolve character and entity references. */
00058 static UTF8*
00059 EIMIL_resolve_reference(
00060     Ebyte *s,
00061     Ebyte *e
00062 )
00063 {
00064     UTF32 ch;
00065     int size, n;
00066     UTF8 *ur, *uc;
00067     Ebyte *c1, *c2;
00068 
00069     ur = uc = (UTF8*) malloc((e - s + 1) * sizeof(UTF8));
00070     size = 0;
00071     for (c1 = s; (c1 < e); c1++) {
00072        if ((EIMIL_isrefstart(*c1))
00073            && (EIMIL_ischrefmark(c1[1]))
00074            && ((e - c1) > 2)) /* &#X; */ {
00075            if (EIMIL_ischrefhexmark(c1[2])) {
00076               ch = 0;
00077               for (c2 = c1 + 3; (c2 < e); c2++) {
00078                   if (EIMIL_isrefend(*c2)) break;
00079                   if (!EIMIL_ischrefhex(*c2)) break;
00080                   ch = ch * 16 + EIMIL_chrefhex(*c2);
00081                   if (ch > 0x10FFFF) goto error_cleanup;
00082               }
00083               if (((c2 - c1) > 3) && EIMIL_isrefend(*c2)) {
00084                   n = EIMIL_convert_UTF32char_to_UTF8(ch, uc);
00085                   uc += n;
00086                   size += n;
00087               } else {
00088                   goto error_cleanup;
00089               }
00090            } else {
00091               for (c2 = c1 + 2; (c2 < e); c2++) {
00092                   if (EIMIL_isrefend(*c2)) break;
00093                   if (!EIMIL_ischrefdec(*c2)) break;
00094                   ch = ch * 10 + EIMIL_chrefdec(*c2);
00095                   if (ch > 0x10FFFF) goto error_cleanup;
00096               }
00097               if (((c2 - c1) > 2) && EIMIL_isrefend(*c2)) {
00098                   n = EIMIL_convert_UTF32char_to_UTF8(ch, uc);
00099                   uc += n;
00100                   size += n;
00101               } else {
00102                   goto error_cleanup;
00103               }
00104            }
00105        } else {
00106            /* TODO:if we require decoding, do it here!
00107               Now we assume Ebyte is UTF8 octet stream.  */
00108            size++;
00109            *uc++ = *c1;
00110        }
00111     }
00112 
00113     size++;
00114     *uc = 0;
00115     ur = (UTF8*) realloc(ur, size * sizeof(UTF8));
00116     return ur;
00117 
00118 error_cleanup:
00119     free(ur);
00120     return NULL;
00121 }
00122 
00123 static void
00124 EIMIL_compute_line(
00125     EIMIL_parser_state *pps,
00126     Ebyte *c1,
00127     int *pline
00128 )
00129 {
00130     int n = 0;
00131     Ebyte *c = pps->current;
00132     if (c < c1) {
00133        for (; (c < c1); c++) {
00134            if (EIMIL_isnewline(*c)) {
00135               n++;
00136            }
00137        }
00138     } else {
00139        while (c > c1) {
00140            c--;
00141            if (EIMIL_isnewline(*c)) {
00142               n--;
00143            }
00144        }
00145     }
00146     *pline = pps->lineno + n;
00147 }
00148 
00149 static void
00150 EIMIL_set_point(
00151     EIMIL_parser_state *pps,
00152     Ebyte *c
00153 )
00154 {
00155     int line;
00156     EIMIL_compute_line(pps, c, &line);
00157     pps->current = c;
00158     pps->lineno = line;
00159     return;
00160 }
00161 
00162 void
00163 EIMIL_set_error(
00164     EIMIL_data *ped,
00165     const char* fmt,
00166     ...
00167 )
00168 {
00169     va_list va;
00170     char errbuf[EIMIL_MAXERRMSG];
00171 
00172     va_start(va, fmt);
00173     vsnprintf(errbuf, sizeof(errbuf), fmt, va);
00174     snprintf(ped->errstr, sizeof(ped->errstr),
00175             "%s\n", errbuf);
00176     va_end(va);
00177 }
00178 
00179 void
00180 EIMIL_set_error_pt(
00181     EIMIL_data *ped,
00182     Ebyte *c,
00183     const char* fmt,
00184     ...
00185 )
00186 {
00187     va_list va;
00188     int lineno;
00189     EIMIL_parser_state* pps = &ped->pcommon->ps;
00190     char errbuf[EIMIL_MAXERRMSG];
00191 
00192     if (c)
00193        EIMIL_compute_line(pps, c, &lineno);
00194     else
00195        lineno = pps->lineno;
00196 
00197     va_start(va, fmt);
00198     vsnprintf(errbuf, sizeof(errbuf), fmt, va);
00199     snprintf(ped->errstr, sizeof(ped->errstr),
00200             "%s (%d)\n", errbuf, lineno);
00201     va_end(va);
00202 }
00203 
00204 void
00205 EIMIL_set_out_of_memory(
00206     EIMIL_data *ped
00207 )
00208 {
00209     EIMIL_set_error(ped, "Out of memory.");
00210 }
00211 
00212 void
00213 EIMIL_set_EOF_error(
00214     EIMIL_data *ped,
00215     Ebyte *e
00216 )
00217 {
00218     EIMIL_set_error_pt(ped, e, "End of file during parsing."); \
00219 }
00220 
00221 Ebyte*
00222 EIMIL_get_ebyte_token(
00223     Ebyte *s,
00224     Ebyte *e
00225 )
00226 {
00227     Ebyte *ret;
00228 
00229     ret = (Ebyte*) malloc((e - s + 1) * sizeof(Ebyte));
00230     if (!ret) return NULL;
00231     memcpy(ret, s, (e - s) * sizeof(Ebyte));
00232     ret[e - s] = 0;
00233 
00234     return ret;
00235 }
00236 
00237 UTF8*
00238 EIMIL_get_UTF8_token(
00239     Ebyte *s,
00240     Ebyte *e
00241 )
00242 {
00243     UTF8 *pret, *p;
00244 
00245     pret = (UTF8*) malloc((e - s + 1) * sizeof(UTF8));
00246     if (!pret) return NULL;
00247 
00248     for (p = pret; s < e; p++, s++) {
00249        /* later we maybe need to convert code. */
00250        *p = *s;
00251     }
00252     *p = '\0';
00253 
00254     return pret;
00255 }
00256 
00257 #define EIMIL_check_EOF(c, e, ped) \
00258 do {                               \
00259     if ((c) >= (e)) {                     \
00260        EIMIL_set_EOF_error((ped), (e));\
00261        goto error_cleanup;         \
00262     }                              \
00263 }while (0)
00264 
00265 #define EIMIL_skip_S(c, e, pps)                         \
00266 for (; (((c) < (e)) && EIMIL_isspace(*c)); (c)++)
00267 
00268 static Ebyte*
00269 EIMIL_match(
00270     Ebyte *c,
00271     Ebyte *e,
00272     char *str
00273 )
00274 {
00275     Ebyte *c1;
00276     char *p;
00277     for (p = str, c1 = c; (c1 < e); c1++, p++) {
00278        if (!(*p)) return c;
00279        if (*c1 != *p) break;
00280     }
00281     return NULL;
00282 }
00283 
00284 static Ebyte*
00285 EIMIL_skip_to(
00286     Ebyte *c,
00287     Ebyte *e,
00288     char *str
00289 )
00290 {
00291     Ebyte *c1;
00292     char *p;
00293     for (; (c < e); c++) {
00294        for (p = str, c1 = c; (c1 < e); c1++, p++) {
00295            if (!(*p)) return c;
00296            if (*c1 != *p) break;
00297        }
00298     }
00299     return NULL;
00300 }
00301 
00302 /***************************************
00303             XML namespace
00304 ***************************************/
00305 static unsigned char* no_default_namespace_uri = "";
00306 #define EIMIL_XMLNS_INITIALI_SLOTS 16
00307 
00308 static EIMIL_XMLNS*
00309 EIMIL_expand_namespace_slot(
00310     EIMIL_parser_state *pps
00311 )
00312 {
00313     if (pps->xmlns_alloced <= pps->xmlns_entries) {
00314        int na;
00315        EIMIL_XMLNS *pns = pps->pxmlns;
00316        if (pps->xmlns_alloced == 0) {
00317            na = EIMIL_XMLNS_INITIALI_SLOTS;
00318            pns = (EIMIL_XMLNS*) malloc(na * sizeof(EIMIL_XMLNS));
00319        } else {
00320            na = pps->xmlns_alloced * 2;
00321            pns = (EIMIL_XMLNS*) realloc(pps->pxmlns,
00322                                     na * sizeof(EIMIL_XMLNS));
00323        }
00324        if (!pns) return NULL;
00325        pps->xmlns_alloced = na;
00326        pps->pxmlns = pns;
00327     }
00328 
00329     return pps->pxmlns + pps->xmlns_entries;
00330 }
00331 
00332 static unsigned char*
00333 EIMIL_get_prefix_namespace(
00334     EIMIL_parser_state *pps,
00335     unsigned char *prefix
00336 )
00337 {
00338     int i;
00339     int n = pps->xmlns_entries;
00340     EIMIL_XMLNS *pns = pps->pxmlns + n;
00341 
00342     for (i = 0; i < n; i++) {
00343        pns--;
00344        if (!pns->uri) continue;
00345        if ((prefix == pns->prefix)
00346            || (prefix && (strcmp(prefix, pns->prefix) == 0))) {
00347            if (pns->uri == no_default_namespace_uri) return NULL;
00348            return pns->uri;
00349        }
00350     }
00351     return NULL;
00352 }
00353 
00354 static int
00355 EIMIL_set_prefix_namespace(
00356     EIMIL_parser_state *pps,
00357     unsigned char *prefix,
00358     unsigned char *uri
00359 )
00360 {
00361     int i;
00362     int n = pps->xmlns_entries;
00363     EIMIL_XMLNS *pns = pps->pxmlns + n;
00364 
00365     for (i = 0; i < n; i++, pns--) {
00366        if (!pns->uri) {
00367            i = n;
00368            break;
00369        }
00370        if (prefix == pns->prefix) {
00371            break;
00372        } else if (prefix && (strcmp(prefix, pns->prefix) == 0)) {
00373            break;
00374        }
00375     }
00376     if (i == n) {
00377        pns = EIMIL_expand_namespace_slot(pps);
00378        if (!pns) return 0;
00379        pns->prefix = prefix;
00380        pps->xmlns_entries++;
00381     } else if ((pns->uri) && (pns->uri != no_default_namespace_uri)) {
00382        free(pns->uri);
00383     }
00384 
00385     if (*uri == '\0') {
00386        pns->uri = no_default_namespace_uri;
00387     } else {
00388        pns->uri = uri;
00389     }
00390     return 1;
00391 }
00392 
00393 static int
00394 EIMIL_namespace_newbind(
00395     EIMIL_parser_state *pps
00396 )
00397 {
00398     EIMIL_XMLNS *pns;
00399     pns = EIMIL_expand_namespace_slot(pps);
00400     if (!pns) return 0;
00401     pps->xmlns_entries++;
00402     pns->prefix = NULL;
00403     pns->uri = NULL;
00404 
00405     return 1;
00406 }
00407 
00408 int
00409 EIMIL_namespace_unbind(
00410     EIMIL_parser_state *pps
00411 )
00412 {
00413     int i;
00414     int n = pps->xmlns_entries;
00415     EIMIL_XMLNS *pns = pps->pxmlns + n;
00416 
00417     for (i = 1; i <= n; i++) {
00418        pns--;
00419        if (!pns->uri) break;
00420        if (pns->prefix) free(pns->prefix);
00421        if ((pns->uri) && (pns->uri != no_default_namespace_uri))
00422            free(pns->uri);
00423     }
00424     pps->xmlns_entries -= i;
00425     return 1;
00426 }
00427 
00428 /***************************************
00429              name
00430 ***************************************/
00431 
00432 static Ebyte*
00433 EIMIL_get_name(
00434     EIMIL_data *ped,
00435     Ebyte *c,
00436     Ebyte *e,
00437     UTF8 **pname,
00438     UTF8 **pprefix
00439 )
00440 {
00441 #if FAMAO
00442     EIMIL_parser_state *pps = &ped->pcommon->ps;
00443 #endif
00444     Ebyte *c1;
00445 
00446     *pprefix = *pname = NULL;
00447     c1 = c;
00448     while ((e > c)
00449           && !EIMIL_isspace(*c)
00450           && !EIMIL_ispresep(*c)
00451           && !EIMIL_istag_e(*c)
00452           && !EIMIL_isetag_mark(*c)) {
00453        c++;
00454     }
00455     if (e <= c) return NULL;
00456     if (EIMIL_ispresep(*c)) {
00457        *pprefix = EIMIL_get_UTF8_token(c1, c);
00458        c1 = c;
00459        while ((e > c)
00460               && !EIMIL_isspace(*c)
00461               && !EIMIL_istag_e(*c)
00462               && !EIMIL_isetag_mark(*c)) {
00463            c++;
00464        }
00465        if (e <= c) return NULL;
00466     }
00467     *pname = EIMIL_get_UTF8_token(c1, c);
00468 
00469     return c;
00470 }
00471 
00472 /***************************************
00473              attribute
00474 ***************************************/
00475 
00476 static void
00477 EIMIL_free_attrs(
00478     EIMIL_attrs *patr
00479 )
00480 {
00481     EIMIL_attrs *pa;
00482 
00483     for (pa = patr;pa->name;pa++) {
00484        free(pa->name);
00485        free(pa->val);
00486     }
00487     free(patr);
00488 }
00489 
00490 static int
00491 EIMIL_check_attrs(
00492     EIMIL_data *ped,
00493     EIMIL_attr_template *pat,
00494     EIMIL_attrs **ppatr
00495 )
00496 {
00497     int i, num;
00498     int eflag = 0;
00499 #if FAMAO
00500     EIMIL_parser_state *pps = &ped->pcommon->ps;
00501 #endif
00502     EIMIL_attrs *pa;
00503 
00504     if (*ppatr)
00505        for (num = 0, pa = *ppatr; pa->name; pa++) num++;
00506     else
00507        num = 0;
00508     if (!pat) return 1;
00509     for (; pat->name; pat++) {
00510        eflag = 0;
00511        for (pa = *ppatr, i = 0; i < num; pa++, i++) {
00512            if (strcmp(pat->name, pa->name) == 0) {
00513               if (eflag) {
00514                   EIMIL_set_error_pt(ped, NULL,
00515                                    "Duplicated attribute:%s",
00516                                    pa->name);
00517                   return 0;
00518               }
00519               if ((pat->type == EIMIL_attr_FIXED)
00520                   && (strcmp(pat->default_value, pa->val) != 0)) {
00521                   EIMIL_set_error_pt(ped, NULL, "attribute:%s must be %s",
00522                                    pat->name, pat->default_value);
00523                   return 0;
00524               }
00525               eflag = 1;
00526            }
00527        }
00528        if (!eflag && pat->default_value) {
00529            if (pat->type == EIMIL_attr_REQUIRED) {
00530               EIMIL_set_error_pt(ped, NULL, "attribute:%s is missing",
00531                                pat->name);
00532               return 0;
00533            }
00534            num++;
00535            *ppatr = pa = (EIMIL_attrs*) realloc(*ppatr,
00536                                            ((num + 1)
00537                                             * sizeof(EIMIL_attrs)));
00538            pa[num].name = NULL;
00539            pa[num].val = NULL;
00540            pa[num - 1].name = strdup(pat->name);
00541            pa[num - 1].val = (Ebyte*) strdup(pat->default_value);
00542        }
00543     }
00544     return 1;
00545 }
00546 
00547 static EIMIL_attrs*
00548 EIMIL_parse_attrs(
00549     EIMIL_data *ped
00550 )
00551 {
00552     EIMIL_parser_state *pps = &ped->pcommon->ps;
00553     Ebyte *c = pps->current;
00554     Ebyte *e = pps->end;
00555     Ebyte *c1;
00556     int atrnum = 0;
00557     EIMIL_attrs *patr_s = NULL;
00558     UTF8 *p, *prefix;
00559     UTF8 *name = NULL;
00560     Ebyte *val;
00561 
00562     while (e > c) {
00563        EIMIL_skip_S(c, e, pps);
00564        EIMIL_check_EOF(c, e, ped);
00565        if (EIMIL_istag_e(*c) || EIMIL_isetag_mark(*c)) break;
00566        /* ATTR S? = S? VAL */
00567        c1 = c;
00568        while ((e > c) && !EIMIL_isspace(*c) && !EIMIL_isEq(*c)) c++;
00569        EIMIL_check_EOF(c, e, ped);
00570        name = EIMIL_get_UTF8_token(c1, c);
00571 
00572        if (!name) goto error_cleanup;
00573        EIMIL_skip_S(c, e, pps);
00574        EIMIL_check_EOF(c, e, ped);
00575        if (!EIMIL_isEq(*c)) {
00576            EIMIL_set_error_pt(ped, c, "Attribute format is invalid");
00577            goto error_cleanup;
00578        }
00579        c++;
00580        EIMIL_check_EOF(c, e, ped);
00581        EIMIL_skip_S(c, e, pps);
00582        EIMIL_check_EOF(c, e, ped);
00583        {
00584            /* cut attribute value out. */
00585            c1 = c;
00586            if (!EIMIL_isquote(*c1)) {
00587               EIMIL_set_error_pt(ped, c, "Attribute value must be enclosed with quote");
00588               goto error_cleanup;
00589            }
00590            c++;
00591            while ((e > c) && (*c1 != *c)) c++;
00592            EIMIL_check_EOF(c, e, ped);
00593            val = EIMIL_get_ebyte_token(c1 + 1, c);
00594            c++;
00595        }
00596 
00597        /* XML namespace check. */
00598        if ((p = strchr(name, ':')) != NULL) {
00599            prefix = name;
00600            *p = '\0';
00601            p++;
00602        } else {
00603            prefix = NULL;
00604            p = name;
00605        }
00606        if (strcmp(p, "xmlns") == 0) {
00607            EIMIL_set_prefix_namespace(pps, prefix, val);
00608            continue;
00609        }
00610        if (prefix) {
00611            /* EIMIL never use any attributes in the global paritition.  */
00612            free(name);
00613            free(val);
00614            continue;
00615        }
00616 
00617        atrnum++;
00618        patr_s = (EIMIL_attrs*) realloc(patr_s, (atrnum + 1) * sizeof(EIMIL_attrs));
00619        patr_s[atrnum].name = NULL;
00620        patr_s[atrnum].val = NULL;
00621        patr_s[atrnum - 1].name = name;
00622        patr_s[atrnum - 1].val = val;
00623     }
00624 
00625     EIMIL_set_point(pps, c);
00626 
00627     return patr_s;
00628 
00629 error_cleanup:
00630     if (patr_s) EIMIL_free_attrs(patr_s);
00631     return NULL;
00632 }
00633 
00634 void
00635 EIMIL_remove_attr(
00636     EIMIL_attrs *patr
00637 )
00638 {
00639     EIMIL_attrs *p;
00640 
00641     ASSERT(patr->name);
00642     for (p = patr + 1; p->name; patr++, p++) *patr = *p;
00643     *patr = *p;
00644 }
00645 
00646 Ebyte*
00647 EIMIL_get_attr_cdata(
00648     Ebyte *val,
00649     UTF8 **result
00650 )
00651 {
00652     Ebyte *e;
00653 
00654     for (e = val; *e; e++);
00655 
00656     if (result) {
00657        *result = EIMIL_resolve_reference(val, e);
00658        if (!(*result)) return NULL;
00659     }
00660 
00661     return e;
00662 }
00663 
00664 Ebyte*
00665 EIMIL_get_attr_nmtoken(
00666     Ebyte *val,
00667     UTF8 **result
00668 )
00669 {
00670     Ebyte *s, *e, *p;
00671 
00672     for (s = val; (*s && EIMIL_isspace(*s)); s++);
00673     if (!(*s)) return NULL;
00674     for (e = s; (*e && !EIMIL_isspace(*e)); e++);
00675     for (p = e; *p; p++) {
00676        if (!EIMIL_isspace(*p)) return NULL;
00677     }
00678 
00679     if (result) {
00680        *result = EIMIL_resolve_reference(s, e);
00681        if (!(*result)) return NULL;
00682     }
00683 
00684     return e;
00685 }
00686 
00687 /*
00688   "  AAA   BBBB CCC  \0"  ==> "   BBBB CCC  \0", result == "AAA"
00689  */
00690 Ebyte*
00691 EIMIL_get_attr_nmtokens(
00692     Ebyte *val,
00693     UTF8 **result
00694 )
00695 {
00696     Ebyte *s, *e;
00697 
00698     for (s = val; (*s && EIMIL_isspace(*s)); s++);
00699     if (!(*s)) return NULL;
00700     for (e = s; (*e && !EIMIL_isspace(*e)); e++);
00701 
00702     if (result) {
00703        *result = EIMIL_resolve_reference(s, e);
00704        if (!(*result)) return NULL;
00705     }
00706 
00707     return e;
00708 }
00709 
00710 static enum EIMIL_TYPE
00711 EIMIL_get_type_from_attrs(
00712     EIMIL_data *ped,
00713     EIMIL_attrs *patr
00714 )
00715 {
00716 #if FAMAO
00717     EIMIL_parser_state *pps = &ped->pcommon->ps;
00718 #endif
00719     UTF8 *name;
00720     enum EIMIL_TYPE type;
00721 
00722     for (; patr->name; patr++) {
00723        if (strcmp(patr->name, "type") == 0) {
00724            if (!EIMIL_get_attr_nmtoken(patr->val, &name)) {
00725               type = EIMIL_TYPE_INVALID;
00726               break;
00727            }
00728            if (strcmp(name, "bool") == 0) type = EIMIL_TYPE_BOOL;
00729            else if (strcmp(name, "number") == 0) type = EIMIL_TYPE_NUMBER;
00730            else if (strcmp(name, "char") == 0) type = EIMIL_TYPE_CHAR;
00731            else if (strcmp(name, "mtext") == 0) type = EIMIL_TYPE_MTEXT;
00732            else type = EIMIL_TYPE_INVALID;
00733            free(name);
00734            free(patr->name);
00735            free(patr->val);
00736            EIMIL_remove_attr(patr);
00737            break;
00738        }
00739     }
00740     if (type == EIMIL_TYPE_INVALID) {
00741        EIMIL_set_error_pt(ped, NULL,
00742                         "`type' attribute must be `bool', `number', `char', or `mtext'.");
00743     }
00744     return type;
00745 }
00746 
00747 static UTF8*
00748 EIMIL_get_UTF8data_token(
00749     EIMIL_data *ped,
00750     int option
00751 )
00752 {
00753     EIMIL_parser_state *pps = &ped->pcommon->ps;
00754     Ebyte *c, *c1, *e;
00755     UTF8 *pu;
00756     c = pps->current;
00757     e = pps->end;
00758     
00759     if (option & EIMIL_PCDATA_TOKEN) {
00760        EIMIL_skip_S(c, e, pps);
00761        c1 = c;
00762        for (; c < e; c++) {
00763            if (EIMIL_isspace(*c) || EIMIL_istag_s(*c)) break;
00764        }
00765     } else if (option & EIMIL_PCDATA_QUOTED_TOKEN) {
00766        Ebyte q;
00767 
00768        EIMIL_skip_S(c, e, pps);
00769        c1 = c;
00770        q = *c;
00771        if (EIMIL_isquote(q)) {
00772            c++;
00773            for (; c < e; c++) {
00774               if (*c == q) break;
00775            }
00776            c++;
00777            if (c >= e) {
00778               EIMIL_set_error_pt(ped, c1,
00779                                "Corresponding quotation mark is missing.");
00780               return NULL;
00781            }
00782        } else {
00783            for (; c < e; c++) {
00784               if (EIMIL_isspace(*c) || EIMIL_istag_s(*c) || EIMIL_isquote(*c)) break;
00785            }
00786        }
00787     } else {
00788        c1 = c;
00789        for (; c < e; c++) {
00790            if (EIMIL_istag_s(*c)) break;
00791        }
00792     }
00793     EIMIL_set_point(pps, c);
00794     pu = EIMIL_resolve_reference(c1, c);
00795     return pu;
00796 }
00797 
00798 static int
00799 EIMIL_match_name(
00800     EIMIL_parser_state *pps,
00801     char *name
00802 )
00803 {
00804     Ebyte *c, *e;
00805     c = pps->current;
00806     e = pps->end;
00807 
00808     while (c < e) {
00809        if (!*name) return 1;
00810        if (*name != *c) return 0;
00811        name++;
00812        c++;
00813     }
00814 
00815     return 0;
00816 }
00817 
00818 /*
00819   Find out the next token.
00820   Return the point of the tag if it is found.
00821   Never move the points of pps.
00822 */
00823 static Ebyte*
00824 EIMIL_next_token(
00825     EIMIL_data *ped
00826 )
00827 {
00828     EIMIL_parser_state *pps = &ped->pcommon->ps;
00829     Ebyte *c, *e;
00830     c = pps->current;
00831     e = pps->end;
00832 
00833     for (; c < e; c++) {
00834        if (!EIMIL_isspace(*c)) return c;
00835     }
00836 
00837     return NULL;
00838 }
00839 
00840 /*
00841   Find out the next tag.
00842   Return the point of the tag if it is found.
00843   Never move the points of pps.
00844 */
00845 static Ebyte*
00846 EIMIL_next_tag(
00847     EIMIL_data *ped
00848 )
00849 {
00850     EIMIL_parser_state *pps = &ped->pcommon->ps;
00851     Ebyte *c, *e;
00852     c = pps->current;
00853     e = pps->end;
00854 
00855     for (; c < e; c++) {
00856        if (EIMIL_istag_s(*c)) return c;
00857     }
00858 
00859     return NULL;
00860 }
00861 
00862 /*
00863   Parse the current tag where pps->current points.
00864   tag's end must be in [pps->current, pps->end).
00865   Move the pps->current to the end of tag.
00866 */
00867 static enum EIMIL_TAG_TYPE
00868 EIMIL_parse_tag(
00869     EIMIL_data *ped,
00870     UTF8 **puri,
00871     UTF8 **pname,
00872     EIMIL_attrs **ppattrs
00873 )
00874 {
00875     EIMIL_parser_state *pps = &ped->pcommon->ps;
00876     Ebyte *c, *c1, *e;
00877     UTF8 *prefix = NULL;
00878     EIMIL_attrs *pat = NULL;
00879     enum EIMIL_TAG_TYPE tt = EIMIL_INVALID_TAG;
00880 
00881     *puri = *pname = NULL;
00882     *ppattrs = NULL;
00883     c = pps->current;
00884     e = pps->end;
00885     /*
00886       <?NAME <anychar>?>
00887       or 
00888       <!DOCTYPE <anychar>>
00889       or
00890       <![CDATA[ <anychar>]]>
00891       or
00892       <!-- <anychar> -->
00893       or 
00894       <TAG-NAME ATTRS S>
00895       or
00896       <TAG-NAME ATTRS S/>
00897       or
00898       </TAG-NAME S>
00899     */
00900     if (!EIMIL_istag_s(*c)) return EIMIL_CHARDATA;
00901     c++;
00902     EIMIL_check_EOF(c, e, ped);
00903     if (EIMIL_isPImark(*c)) {
00904        /* <?NAME <anychar>?> */
00905        c = EIMIL_skip_to(c, e, "?>");
00906        EIMIL_set_point(pps, c + 2);
00907        return EIMIL_PI_TAG;
00908     } else if (EIMIL_isEXmark(*c)) {
00909        if ((c1 = EIMIL_match(c, e, "!--")) != NULL) {
00910            c = EIMIL_skip_to(c1, e, "--");
00911            c += 2;
00912            if (!EIMIL_istag_e(*c)) {
00913               EIMIL_set_error_pt(ped, c, "`--' must not occur within comments.");
00914               return EIMIL_INVALID_TAG;
00915            }
00916            c++;
00917            EIMIL_check_EOF(c, e, ped);
00918            EIMIL_set_point(pps, c);
00919            return EIMIL_COMMENT_TAG;
00920        }
00921        if ((c1 = EIMIL_match(c, e, "!DOCTYPE")) != NULL) {
00922            c = EIMIL_skip_to(c1, e, ">");
00923            EIMIL_set_point(pps, c + 1);
00924            return EIMIL_DOCTYPE_TAG;
00925        }
00926        EIMIL_check_EOF(c1, e, ped);
00927        if ((c1 = EIMIL_match(c, e, "![CDATA[")) != NULL) {
00928            c = EIMIL_skip_to(c1, e, "]]>");
00929            EIMIL_set_point(pps, c + 3);
00930            return EIMIL_CDATA_TAG;
00931        }
00932        EIMIL_check_EOF(c1, e, ped);
00933        EIMIL_set_error_pt(ped, c, "Unknown token.  Normal tags must not start with `!'.");
00934     } else if (EIMIL_isetag_mark(*c)) {
00935        /* </TAG-NAME> */
00936        tt = EIMIL_END_TAG;
00937        c++;
00938        if (!(c = EIMIL_get_name(ped, c, e, pname, &prefix))) {
00939            EIMIL_check_EOF(c, e, ped);
00940            goto error_cleanup;
00941        }
00942        EIMIL_skip_S(c, e, pps);
00943     } else {
00944        EIMIL_namespace_newbind(pps);
00945        if (!(c = EIMIL_get_name(ped, c, e, pname, &prefix))) {
00946            EIMIL_check_EOF(c, e, ped);
00947            goto error_cleanup;
00948        }
00949        if (EIMIL_isspace(*c)) {
00950            EIMIL_set_point(pps, c);
00951            pat = EIMIL_parse_attrs(ped);
00952            c = pps->current;
00953        }
00954        EIMIL_skip_S(c, e, pps);
00955        EIMIL_check_EOF(c, e, ped);
00956        if (EIMIL_isetag_mark(*c)) {
00957            tt = EIMIL_EMPTY_TAG;
00958            /* <TAG-NAME ATTRS S/> */
00959            c++;
00960        } else {
00961            tt = EIMIL_START_TAG;
00962        }
00963     }
00964     if (!EIMIL_istag_e(*c)) goto error_cleanup;
00965 
00966     *puri = EIMIL_get_prefix_namespace(pps, prefix);
00967     if (prefix && !(*puri)) {
00968        EIMIL_set_error_pt(ped, c, "name is not belong to any namespace.");
00969        goto error_cleanup;
00970     }
00971 
00972     if (prefix) free(prefix);
00973     *ppattrs = pat;
00974     EIMIL_set_point(pps, c + 1);
00975 
00976     return tt;
00977 
00978 error_cleanup:
00979     if (prefix) free(prefix);
00980     if (*pname) free(*pname);
00981     *pname = *puri = NULL;
00982     *ppattrs = NULL;
00983     if (pat) {
00984        EIMIL_free_attrs(pat);
00985     }
00986 
00987     return EIMIL_INVALID_TAG;
00988 }
00989 
00990 /*
00991   Find out the element in contents, and parse it.
00992   pps->current is always reset to the pps->start at the startup.
00993  */
00994 static int
00995 EIMIL_parse_element(
00996     EIMIL_data *ped,
00997     EIMIL_element_template *pet,
00998     EIMIL_element_template *pet_current,
00999     void* private,
01000     UTF8 *current_element_name,
01001     UTF8 *current_element_uri
01002 )
01003 {
01004     EIMIL_parser_state *pps = &ped->pcommon->ps;
01005     UTF8 *name, *uri;
01006     const UTF8 *saved_uri;
01007     enum EIMIL_TAG_TYPE tt;
01008     int i, n;
01009     int option;
01010     int *pelemnums;
01011     void *saved_private;
01012     Ebyte *s, *c, *e;
01013     Ebyte *tag_end;
01014     EIMIL_attrs *pat = NULL;
01015     EIMIL_element_template *pet2;
01016 
01017     s = pps->start;
01018     e = pps->end;
01019 
01020     EIMIL_set_point(pps, s);
01021 
01022     if (pet_current)
01023        option = pet_current->option;
01024     else
01025        option = 0;
01026 
01027     if (pps->element_depth > MAX_ELEMENT_DEPTH) {
01028        EIMIL_set_error_pt(ped, NULL, "The limit of element depth is exceeded.");
01029        return 0;
01030     }
01031 
01032     /* count the number of pet */
01033     if (pet) {
01034        for (n = 0, pet2 = pet; pet2->name; pet2++) n++;
01035     } else {
01036        n = 0;
01037     }
01038 
01039     pelemnums = (int*) alloca(sizeof(int) * n);
01040     memset(pelemnums, 0, sizeof(int) * n);
01041     pet2 = pet;
01042 
01043     name = NULL;
01044     i = 0;
01045     while ((c = EIMIL_next_token(ped)) != NULL) {
01046 
01047        EIMIL_set_point(pps, c);
01048        if (name) free(name);
01049        tt = EIMIL_parse_tag(ped, &uri, &name, &pat);
01050        tag_end = pps->current;
01051        EIMIL_set_point(pps, c);
01052 
01053        /* 
01054           At this point,
01055           <TAG> <-- `tag_end' points
01056           ^-- `pps->current' points
01057        */
01058 
01059        if (tt == EIMIL_END_TAG) {
01060            if (current_element_name
01061               && (strcmp(name, current_element_name) == 0)
01062               && ((uri == current_element_uri)
01063                   || (uri && current_element_uri
01064                      && (strcmp(uri, current_element_uri) == 0)))) {
01065               EIMIL_namespace_unbind(pps);
01066               e = tag_end;
01067               break;
01068            }
01069            EIMIL_set_error_pt(ped, NULL, "Unbalanced end tag:%s, %s.",
01070                             name, current_element_name);
01071            goto error_cleanup;
01072        } else if ((tt == EIMIL_PI_TAG)
01073                  || (tt == EIMIL_COMMENT_TAG)
01074                  || (tt == EIMIL_DOCTYPE_TAG)
01075                  || (tt == EIMIL_CDATA_TAG)) {
01076            pps->start = tag_end;
01077            EIMIL_set_point(pps, tag_end);
01078            continue;
01079        } else if (tt == EIMIL_CHARDATA) {
01080            if (pet_current && (!(pet_current->option & EIMIL_allow_PCDATA))) {
01081               EIMIL_set_error_pt(ped, NULL, "Invalid character token.");
01082               goto error_cleanup;
01083            }
01084            if (pet_current && pet_current->func) {
01085               UTF8 *pu = EIMIL_get_UTF8data_token(ped, pet_current->option);
01086               if (!pu) goto error_cleanup;
01087               if (!((*pet_current->func)(ped, NULL, tt, pu, &private)))
01088                   goto error_cleanup;
01089               free(pu);
01090            } else {
01091               c = EIMIL_next_tag(ped);
01092               if (!c) {
01093                   EIMIL_set_error_pt(ped, NULL,
01094                                    "Cannot find out any start tag while parsing chardata.");
01095                   goto error_cleanup;
01096               }
01097               EIMIL_set_point(pps, c);
01098            }
01099            continue;
01100        } else if (tt == EIMIL_INVALID_TAG) {
01101            goto error_cleanup;
01102        }
01103 
01104        if ((uri) && (strcmp(uri, pps->current_uri) == 0)) {
01105            if (pet2) {
01106               if ((i > 0)
01107                   && (pet2->option & EIMIL_element_lock_template)) {
01108                   /* When EIMIL_element_lock_template is set,
01109                      other we don't check any other template than pet2.  */
01110                   if (strcmp(pet2->name, name) != 0) {
01111                      EIMIL_set_error_pt(ped, NULL, "%s must not be after %s.",
01112                                       name, pet2->name);
01113                      if (pat) EIMIL_free_attrs(pat);
01114                      goto error_cleanup;
01115                   }
01116               } else {
01117                   if (!(option & EIMIL_subelement_ordered)) pet2 = pet;
01118                   for (; pet2->name; pet2++) {
01119                      if (strcmp(pet2->name, name) == 0) break;
01120                   }
01121               }
01122            }
01123            if (!pet2 || !pet2->name) {
01124               EIMIL_set_error_pt(ped, NULL, "Unknown tag:%s.", name);
01125               if (pat) EIMIL_free_attrs(pat);
01126               goto error_cleanup;
01127            }
01128            if (pet2->attrtpls) {
01129               if (!EIMIL_check_attrs(ped, pet2->attrtpls, &pat)) {
01130                   goto error_cleanup;
01131               }
01132            }
01133            i++;
01134            pelemnums[pet2 - pet]++;
01135            EIMIL_SET_CURRENT_SUBELEMENT_TEMPLATE(pps, pet2->subelems);
01136            saved_uri = pps->current_uri;
01137            if (pet2->func) {
01138               pps->pcet = pet2;
01139               pps->element_idx = i;
01140               saved_private = private;
01141               if (!((*pet2->func)(ped, pat, tt, NULL, &private))) {
01142                   goto error_cleanup;
01143               }
01144            }
01145            if (tt == EIMIL_EMPTY_TAG) {
01146               EIMIL_namespace_unbind(pps);
01147               if (!(pet2->option & EIMIL_element_EMPTY)) {
01148                   EIMIL_set_error_pt(ped, NULL, "Tag %s must not be an empty element tag",
01149                                    name);
01150                   goto error_cleanup;
01151               }
01152               c = tag_end;
01153            } else {
01154               int status;
01155 
01156               if (pet2->option & EIMIL_element_EMPTY) {
01157                   EIMIL_set_error_pt(ped, NULL, "Tag %s must be an empty element tag",
01158                                    name);
01159                   goto error_cleanup;
01160               }
01161 
01162               pps->start = tag_end;
01163               status = EIMIL_parse_element(ped, pps->psubet, pet2,
01164                                         private, name, uri);
01165               /* Now `c' points the end of element.  */
01166               c = pps->end;
01167               if (status != -1) {
01168                   if (status)
01169                      EIMIL_set_error_pt(ped, tag_end,
01170                                       "End tag is missing:%s.",
01171                                       name);
01172                   goto error_cleanup;
01173               }
01174               if (pet2->func) {
01175                   pps->start = tag_end;
01176                   pps->end = pps->current;
01177                   pps->element_idx = i;
01178                   pps->pcet = pet2;
01179                   if (!((*pet2->func)(ped, pat, EIMIL_END_TAG, NULL, &private))) {
01180                      goto error_cleanup;
01181                   }
01182                   private = saved_private;
01183               }
01184            }
01185            EIMIL_SET_CURRENT_SUBELEMENT_TEMPLATE(pps, pet2->subelems);
01186            pps->current_uri = saved_uri;
01187        } else {
01188            int status;
01189            /* Ignore the element */
01190            if (pat) EIMIL_free_attrs(pat);
01191            if (tt == EIMIL_EMPTY_TAG) {
01192               EIMIL_namespace_unbind(pps);
01193               c = tag_end;
01194            } else {
01195               /* Skip to the end tag.  */
01196               pps->start = tag_end;
01197               status = EIMIL_parse_element(ped, pet, NULL,
01198                                         private, name, uri);
01199               /* Now `c' points the end of element.  */
01200               c = pps->end;
01201               if (status != -1) {
01202                   if (status)
01203                      EIMIL_set_error_pt(ped, tag_end,
01204                                       "End tag is mising:%s.",
01205                                       name);
01206                   goto error_cleanup;
01207               }
01208            }
01209        }
01210        pps->start = c;
01211        EIMIL_set_point(pps, c);
01212        pps->end = e;
01213     }
01214     if (name) free(name);
01215     name = NULL;
01216 
01217     pps->start = s;
01218     pps->end = e;
01219 
01220     if (pet) {
01221        /* Check the number of elements.  */
01222        int opt;
01223        int *pn;
01224        for (pet2 = pet, pn = pelemnums; pet2->name; pet2++, pn++) {
01225            opt = (pet2->option | EIMIL_element_option_mask);
01226            if ((opt == EIMIL_element_single) && (*pn != 1)) {
01227               EIMIL_set_error_pt(ped, NULL, "element:%s must be only 1.",
01228                                pet2->name);
01229               return 0;
01230            } else if ((opt == EIMIL_element_morethan1) && (*pn < 1)) {
01231               EIMIL_set_error_pt(ped, NULL, "element:%s must be more than 1.",
01232                                pet2->name);
01233               return 0;
01234            } else if ((opt == EIMIL_element_0or1) && (*pn > 1)) {
01235               EIMIL_set_error_pt(ped, NULL, "element:%s must be 0 or 1.",
01236                                pet2->name);
01237               return 0;
01238            }
01239        }
01240     }
01241 
01242     if (tt == EIMIL_END_TAG) return -1;
01243 
01244     return 1;
01245 
01246 error_cleanup:
01247     if (name) free(name);
01248     return 0;
01249 }
01250 
01251 /********************************************************************************
01252                      EIMIL value related services.
01253  ********************************************************************************/
01254 
01255 EIMIL_value*
01256 EIMIL_construct_number(
01257     int number
01258 )
01259 {
01260     EIMIL_value *pv;
01261     pv = (EIMIL_value*) malloc(sizeof(EIMIL_value));
01262     if (!pv) return NULL;
01263     pv->type = EIMIL_TYPE_NUMBER;
01264     pv->v.number = number;
01265     pv->refcount = 0;
01266     return pv;
01267 }
01268 
01269 EIMIL_value*
01270 EIMIL_construct_bool(
01271     int bool_val
01272 )
01273 {
01274     if (!bool_val) return NULL;
01275     return &EIMIL_t_val;
01276 }
01277 
01278 EIMIL_value*
01279 EIMIL_construct_char(
01280     UTF32 ch
01281 )
01282 {
01283     EIMIL_value *pv;
01284     pv = (EIMIL_value*) malloc(sizeof(EIMIL_value));
01285     if (!pv) return NULL;
01286     pv->type = EIMIL_TYPE_CHAR;
01287     pv->v.ch = ch;
01288     pv->refcount = 0;
01289     return pv;
01290 }
01291 
01292 EIMIL_value*
01293 EIMIL_construct_event(
01294     UTF8 *type,
01295     EIMIL_value *pv_val,
01296     EIMIL_value *pv_mod,
01297     EIMIL_value *pv_char,
01298     EIMIL_value *pv_mtext
01299 )
01300 {
01301     EIMIL_value *pv;
01302     ASSERT(!pv_val || pv_val->type == EIMIL_TYPE_NUMBER);
01303     ASSERT(!pv_mod || pv_mod->type == EIMIL_TYPE_NUMBER);
01304     ASSERT(!pv_char || pv_char->type == EIMIL_TYPE_CHAR);
01305     ASSERT(!pv_mtext || pv_mtext->type == EIMIL_TYPE_MTEXT);
01306     pv = (EIMIL_value*) malloc(sizeof(EIMIL_value));
01307     if (!pv) return NULL;
01308     pv->type = EIMIL_TYPE_EVENT;
01309 
01310     pv->v.event.type = strdup(type);
01311     pv->v.event.pv_val = pv_val;
01312     if (pv_val) EIMIL_ADDREF(*pv_val);
01313     pv->v.event.pv_mod = pv_mod;
01314     if (pv_mod) EIMIL_ADDREF(*pv_mod);
01315     pv->v.event.pv_char = pv_char;
01316     if (pv_char) EIMIL_ADDREF(*pv_char);
01317     pv->v.event.pv_mtext = pv_mtext;
01318     if (pv_mtext) EIMIL_ADDREF(*pv_mtext);
01319     pv->refcount = 0;
01320 
01321     return pv;
01322 }
01323 
01324 int
01325 EIMIL_construct_events_from_IMInputEvent(
01326     IMInputEvent *pimev,
01327     EIMIL_value ***pppevs
01328 )
01329 {
01330     EIMIL_value *pev;
01331 
01332     switch (pimev->type) {
01333       case IM_EventKeyList:
01334       {
01335          IMKeyListEvent *pimkev = (IMKeyListEvent*) pimev;
01336          IMKeyList keylist = pimkev->keylist;
01337          int i, n = pimkev->n_key;
01338          EIMIL_value **ppevs;
01339          EIMIL_value *pev_code, *pev_char, *pev_mod;
01340 
01341          ppevs = (EIMIL_value**) malloc(sizeof(EIMIL_value*) * n);
01342          if (!ppevs) return 0;
01343 
01344          for (i = 0; i < n; i++) {
01345              pev_code = EIMIL_construct_number(keylist[i].keyCode);
01346              if (!pev_code) return 0;
01347              pev_char = EIMIL_construct_char(keylist[i].keyChar);
01348              if (!pev_char) return 0;
01349              pev_mod = EIMIL_construct_number(keylist[i].modifier);
01350              if (!pev_mod) return 0;
01351              pev = EIMIL_construct_event("keyevent",
01352                                      pev_code, pev_char, pev_mod,
01353                                      NULL);
01354              if (!pev) return 0;
01355              ppevs[i] = pev;
01356          }
01357          *pppevs = ppevs;
01358          return n;
01359       }
01360     }
01361 
01362     return 0;
01363 }
01364 
01365 IMInputEvent*
01366 EIMIL_convert_event_to_IMInputEvent(
01367     EIMIL_event *pev
01368 )
01369 {
01370     if (strcmp(pev->type, "keyevent") == 0) {
01371        IMKeyListEvent *pimkev;
01372        IMKeyList keylist;
01373 
01374        pimkev = (IMKeyListEvent*) malloc(sizeof(IMKeyListEvent));
01375        if (!pimkev) return NULL;
01376        memset(pimkev, 0, sizeof(IMKeyListEvent));
01377        keylist = (IMKeyList) malloc(sizeof(IMKeyEventStruct));
01378        if (!keylist) return NULL;
01379        memset(keylist, 0, sizeof(IMKeyEventStruct));
01380 
01381        pimkev->type = IM_EventKeyList;
01382        pimkev->n_key = 1;
01383        pimkev->keylist = keylist;
01384        if (pev->pv_val) {
01385            keylist->keyCode = pev->pv_val->v.number;
01386            keylist->keyChar = pev->pv_char->v.ch;
01387            keylist->modifier = pev->pv_mod->v.number;
01388        }
01389 
01390        return (IMInputEvent*) pimkev;
01391     }
01392 
01393     return NULL;
01394 }
01395 
01396 EIMIL_value*
01397 EIMIL_construct_prop(
01398     EIMIL_symbol *psym
01399 )
01400 {
01401     EIMIL_value *pv;
01402     EIMIL_prop *pprop;
01403 
01404     ASSERT(psym->cat == EIMIL_CAT_PROPERTY);
01405 
01406     pv = (EIMIL_value*) malloc(sizeof(EIMIL_value));
01407     if (!pv) return NULL;
01408     pv->type = EIMIL_TYPE_PROP;
01409     pprop = &pv->v.prop;
01410     memset(pprop, 0, sizeof(EIMIL_prop));
01411     pprop->st = -1;
01412     pprop->end = -1;
01413     pprop->property_sym = psym;
01414     pprop->type = psym->obj.p.type;
01415     pv->refcount = 0;
01416     return pv;
01417 }
01418 
01419 EIMIL_value*
01420 EIMIL_construct_prop2(
01421     enum EIMIL_TYPE type
01422 )
01423 {
01424     EIMIL_value *pv;
01425     EIMIL_prop *pprop;
01426     pv = (EIMIL_value*) malloc(sizeof(EIMIL_value));
01427     if (!pv) return NULL;
01428     pv->type = EIMIL_TYPE_PROP;
01429     pprop = &pv->v.prop;
01430     memset(pprop, 0, sizeof(EIMIL_prop));
01431     pprop->st = -1;
01432     pprop->end = -1;
01433     pprop->type = type;
01434     pv->refcount = 0;
01435     return pv;
01436 }
01437 
01438 int
01439 EIMIL_add_prop(
01440     EIMIL_prop *pprop,
01441     EIMIL_value *pv
01442 )
01443 {
01444     EIMIL_value **ppv;
01445 
01446     ASSERT((!pv) || (pv->type == pprop->type));
01447 
01448     ppv = pprop->pvals;
01449     ppv = (EIMIL_value**) realloc(ppv, sizeof(EIMIL_value*) * (pprop->size + 1));
01450     if (!ppv) return 0;
01451     pprop->pvals = ppv;
01452     if (pv) EIMIL_ADDREF(*pv);
01453     ppv[pprop->size] = pv;
01454     pprop->size++;
01455 
01456     return 1;
01457 }
01458 
01459 int
01460 EIMIL_delete_prop(
01461     EIMIL_prop *pprop,
01462     int idx
01463 )
01464 {
01465     EIMIL_value **ppv;
01466 
01467     if ((idx < 0) || (idx >= pprop->size)) return 0;
01468     ppv = pprop->pvals + idx;
01469     EIMIL_RMREF(**ppv);
01470     if ((pprop->size - idx - 1) > 0)
01471        memmove(ppv, ppv + 1, sizeof(EIMIL_value*) * (pprop->size - idx - 1));
01472     pprop->size--;
01473 
01474     return 1;
01475 }
01476 
01477 void
01478 EIMIL_destruct_value(
01479     EIMIL_value *pv
01480 )
01481 {
01482     if (!pv) return;
01483     switch(pv->type) {
01484       case EIMIL_TYPE_PROP:
01485       {
01486          int i;
01487          EIMIL_value **ppv;
01488 
01489          EIMIL_detach_prop_from_mtext(pv);
01490          for (ppv = pv->v.prop.pvals, i = 0;
01491               i < pv->v.prop.size;
01492               ppv++, i++) {
01493              EIMIL_RMREF(**ppv);
01494          }
01495          if (pv->v.prop.pvals) free(pv->v.prop.pvals);
01496          break;
01497       }
01498       case EIMIL_TYPE_EVENT:
01499        if (pv->v.event.type) free(pv->v.event.type);
01500        if (pv->v.event.pv_val) EIMIL_RMREF(*pv->v.event.pv_val);
01501        if (pv->v.event.pv_mod) EIMIL_RMREF(*pv->v.event.pv_mod);
01502        if (pv->v.event.pv_char) EIMIL_RMREF(*pv->v.event.pv_char);
01503        if (pv->v.event.pv_mtext) EIMIL_RMREF(*pv->v.event.pv_mtext);
01504        break;
01505       case EIMIL_TYPE_MTEXT:
01506        EIMIL_destruct_mtext(&pv->v.mtext);
01507        break;
01508       default:
01509        break;
01510     }
01511 
01512     free(pv);
01513 }
01514 
01515 EIMIL_value*
01516 EIMIL_copy_value(
01517     EIMIL_value *pv
01518 )
01519 {
01520     EIMIL_value *pv2;
01521 
01522     if (pv->type == EIMIL_TYPE_BOOL) {
01523        ASSERT(pv == &EIMIL_t_val);
01524        return pv;
01525     }
01526 
01527     pv2 = (EIMIL_value*) malloc(sizeof(EIMIL_value));
01528     memset(pv2, 0, sizeof(EIMIL_value));
01529     if (!pv2) return NULL;
01530     pv2->type = pv->type;
01531     pv2->refcount = 0;
01532 
01533     switch(pv->type) {
01534       case EIMIL_TYPE_NUMBER:
01535        pv2->v.number = pv->v.number;
01536        break;
01537 
01538       case EIMIL_TYPE_CHAR:
01539        pv2->v.ch = pv->v.ch;
01540        break;
01541 
01542       case EIMIL_TYPE_PROP:
01543       {
01544          int i;
01545          EIMIL_value *pvtmp;
01546          pv2->v.prop = pv->v.prop;
01547          pv2->v.prop.pvals = (EIMIL_value**) malloc(sizeof(EIMIL_value*)
01548                                                * pv->v.prop.size);
01549          if (!pv2->v.prop.pvals) return NULL;
01550          for (i = 0; i < pv->v.prop.size; i++) {
01551              pvtmp = pv->v.prop.pvals[i];
01552              EIMIL_ADDREF(*pvtmp);
01553              pv2->v.prop.pvals[i] = pvtmp;
01554          }
01555          break;
01556       }
01557       case EIMIL_TYPE_EVENT:
01558        pv2->v.event.type = strdup(pv->v.event.type);
01559        if (!pv2->v.event.type) {
01560           free(pv2);
01561           return NULL;
01562        }
01563        if (pv->v.event.pv_val) {
01564           pv2->v.event.pv_val = EIMIL_copy_value(pv->v.event.pv_val);
01565           if (!pv2->v.event.pv_val) {
01566               free(pv2->v.event.type);
01567               free(pv2);
01568               return NULL;
01569           }
01570        }
01571        if (pv->v.event.pv_mod) {
01572           pv2->v.event.pv_mod = EIMIL_copy_value(pv->v.event.pv_mod);
01573           if (!pv2->v.event.pv_mod) {
01574               EIMIL_destruct_value(pv->v.event.pv_val);
01575               free(pv2->v.event.type);
01576               free(pv2);
01577               return NULL;
01578           }
01579        }
01580        if (pv->v.event.pv_char) {
01581           pv2->v.event.pv_char = EIMIL_copy_value(pv->v.event.pv_char);
01582           if (!pv2->v.event.pv_char) {
01583               EIMIL_destruct_value(pv->v.event.pv_val);
01584               EIMIL_destruct_value(pv->v.event.pv_mod);
01585               free(pv2->v.event.type);
01586               free(pv2);
01587               return NULL;
01588           }
01589        }
01590        if (!pv->v.event.pv_mtext) break;
01591       case EIMIL_TYPE_MTEXT:
01592       {
01593          int i, j;
01594          EIMIL_mtext *pmt2, *pmt;
01595          EIMIL_mtext_props *pmp;
01596          EIMIL_value **ppv;
01597 
01598          if (pv->type == EIMIL_TYPE_MTEXT) {
01599              pv2->v.mtext = pv->v.mtext;
01600              pmt = &pv->v.mtext;
01601              pmt2 = &pv2->v.mtext;
01602          }else{
01603              pmt = &pv->v.event.pv_mtext->v.mtext;
01604              pmt2 = &pv2->v.event.pv_mtext->v.mtext;
01605          }
01606          pmt2->ustr = (UTF32*) malloc(sizeof(UTF32) * pmt->len);
01607          if (!pmt2->ustr) {
01608              free(pv2);
01609              return NULL;
01610          }
01611          memcpy(pmt2->ustr, pmt->ustr, sizeof(UTF32) * pmt->len);
01612 
01613          pmt2->pslots = (EIMIL_mtext_props*) malloc(sizeof(EIMIL_mtext_props)
01614                                                * pmt->slotsnum);
01615          if (!pmt2->pslots) {
01616              free(pmt2->ustr);
01617              free(pv2);
01618              return NULL;
01619          }
01620          memcpy(pmt2->pslots, pmt->pslots,
01621                sizeof(EIMIL_mtext_props) * pmt->slotsnum);
01622 
01623          for (pmp = pmt2->pslots, i = 0;
01624               i < pmt2->slotsnum;
01625               i++, pmp++) {
01626              ppv = (EIMIL_value**) malloc(sizeof(EIMIL_value*) * pmp->num);
01627              if (!ppv) {
01628                 free(pmt2->pslots);
01629                 free(pmt2->ustr);
01630                 free(pv2);
01631                 return NULL;
01632              }
01633              memcpy(ppv, pmp->pprops, sizeof(EIMIL_value*) * pmp->num);
01634              pmp->pprops = ppv;
01635              for (j = 0; j < pmp->num; j++, ppv++) {
01636                 ASSERT((*ppv)->type == EIMIL_TYPE_PROP);
01637                 *ppv = EIMIL_copy_value(*ppv);
01638                 if (!*ppv) {
01639                     free(pmt2->pslots);
01640                     free(pmt2->ustr);
01641                     free(pv2);
01642                     return NULL;
01643                                    
01644                 }
01645                 (*ppv)->v.prop.target = pmt2;
01646                 EIMIL_ADDREF(**ppv);
01647              }
01648          }
01649          break;
01650       }
01651       default:
01652        abort();
01653     }
01654 
01655     return pv2;
01656 }
01657 
01658 int
01659 EIMIL_value_equal(
01660     EIMIL_value *pv1,
01661     EIMIL_value *pv2
01662 )
01663 {
01664        if (pv1 == pv2) return 1;
01665 
01666        /* TODO!!! */
01667 
01668        return 0;
01669 }
01670 
01671 int
01672 EIMIL_generate_diff(
01673     EIMIL_symbol *psym,
01674     EIMIL_value *pv2,
01675     IMDifferential *pdiff
01676 )
01677 {
01678     EIMIL_value *pv1;
01679 
01680     ASSERT(psym->cat == EIMIL_CAT_VARIABLE);
01681     pv1 = psym->obj.v.pv;
01682 
01683     memset(pdiff, 0, sizeof(IMDifferential));
01684 
01685     ASSERT((!pv2) || (psym->obj.v.type == pv2->type));
01686     switch(psym->obj.v.type) {
01687       case EIMIL_TYPE_NUMBER:
01688        if ((pv1 != pv2)
01689           || (pv1->v.number != pv2->v.number)) {
01690           pdiff->number = pv1->v.number;
01691           return 1;
01692        }
01693        break;
01694 
01695       case EIMIL_TYPE_BOOL:
01696        if ((pv1 != pv2)
01697           || (pv1->v.bool_val != pv2->v.bool_val)) {
01698           pdiff->bool_val = pv2->v.bool_val;
01699           return 1;
01700        }
01701        break;
01702 
01703       case EIMIL_TYPE_CHAR:
01704        if ((pv1 != pv2)
01705           || (pv1->v.ch != pv2->v.ch)) {
01706           pdiff->ch = pv2->v.ch;
01707           return 1;
01708        }
01709        break;
01710 
01711       case EIMIL_TYPE_MTEXT:
01712        return EIMIL_mtext_diff(&pv2->v.mtext, &pv1->v.mtext, pdiff);
01713        break;
01714       default:
01715        abort();
01716     }
01717 
01718     return 0;
01719 }
01720 
01721 
01722 /********************************************************************************
01723                      EIMIL dictionary service.
01724  ********************************************************************************/
01725 
01726 #define EIMIL_DICTIONARY_DEFAULT_SIZE 53 /* should be a primary number! */
01727 #define EIMIL_DICTIONARY_SUBSLOT_UNIT 8
01728 
01729 struct EIMIL_dictionary {
01730     int size;
01731     EIMIL_symbol ***namedic;
01732     EIMIL_symbol ***iddic;
01733 };
01734 
01735 EIMIL_dictionary*
01736 EIMIL_new_dictionary(
01737     int size,
01738     int id_req_p
01739 )
01740 {
01741     EIMIL_dictionary *pdic;
01742     EIMIL_symbol ***pppsym;
01743 
01744     if (size == 0)
01745        size = EIMIL_DICTIONARY_DEFAULT_SIZE;
01746 
01747     pdic = malloc(sizeof(EIMIL_dictionary));
01748     if (!pdic) {
01749        return NULL;
01750     }
01751     pdic->size = size;
01752     pppsym = (EIMIL_symbol***) malloc(sizeof(EIMIL_dictionary**) * size);
01753     if (!pppsym) {
01754        free(pdic);
01755        return NULL;
01756     }
01757     memset(pppsym, 0, sizeof(EIMIL_dictionary**) * size);
01758     pdic->namedic = pppsym;
01759     if (id_req_p) {
01760        pppsym = (EIMIL_symbol***) malloc(sizeof(EIMIL_dictionary**) * size);
01761        if (!pppsym) {
01762            free(pdic->namedic);
01763            free(pdic);
01764            return NULL;
01765        }
01766        memset(pppsym, 0, sizeof(EIMIL_dictionary**) * size);
01767        pdic->iddic = pppsym;
01768     } else {
01769        pdic->iddic = NULL;
01770     }
01771     return pdic;
01772 }
01773 
01774 void
01775 EIMIL_free_dictionary(
01776     EIMIL_dictionary *pdic
01777 )
01778 {
01779     if (!pdic) return;
01780 
01781     /* TODO: free EIMIL_objects!!! */
01782     free(pdic->namedic);
01783     if (pdic->iddic) free(pdic->iddic);
01784     free(pdic);
01785     return;
01786 }
01787 
01788 void
01789 EIMIL_free_dictionary_and_symbol(
01790     EIMIL_dictionary *pdic
01791 )
01792 {
01793     int i;
01794     EIMIL_symbol **pps;
01795 
01796     if (!pdic) return;
01797 
01798     for (i = 0; i < pdic->size; i++) {
01799        for (pps = pdic->namedic[i]; (pps && *pps); pps++) {
01800            EIMIL_destruct_symbol(*pps);
01801        }
01802         if (pdic->namedic[i]) free(pdic->namedic[i]);
01803     }
01804     if (pdic->iddic) {
01805         for (i = 0; i < pdic->size; i++) {
01806             if (pdic->iddic[i]) free(pdic->iddic[i]);
01807         }
01808     }
01809     EIMIL_free_dictionary(pdic);
01810     return;
01811 }
01812 
01813 static int
01814 hash_function_string(
01815     unsigned char *name,
01816     int size
01817 )
01818 {
01819     int i, v;
01820 
01821     for (v = 0; *name; i++, name++) {
01822        v = ((v << 8) + *name) % size;
01823     }
01824 
01825     return v;
01826 }
01827 
01828 #ifdef DEBUG
01829 static void
01830 list_symbols(
01831     EIMIL_dictionary *pdic
01832 )
01833 {
01834     int i;
01835     EIMIL_symbol **pps;
01836 
01837     for (i = 0; i < pdic->size; i++) {
01838        for (pps = pdic->namedic[i]; (pps && *pps); pps++) {
01839            fprintf(stdout, "SYM(name):%s(%d)\n",
01840                   (*pps)->name, (*pps)->symbolid);
01841            ASSERT(hash_function_string((*pps)->name, pdic->size)
01842                  == i);
01843        }
01844     }
01845     if (pdic->iddic) {
01846        for (i = 0; i < pdic->size; i++) {
01847            for (pps = pdic->iddic[i];(pps && *pps);pps++) {
01848               fprintf(stdout, "SYM(id):%s(%d)\n",
01849                      (*pps)->name, (*pps)->symbolid);
01850               ASSERT(((*pps)->symbolid %  pdic->size) == i);
01851            }
01852        }
01853     }
01854     return;
01855 }
01856 
01857 #endif
01858 
01859 static CARD32BIT
01860 EIMIL_generate_symbolid(
01861     EIMIL_data *ped,
01862     enum EIMIL_CATEGORY cat,
01863     enum EIMIL_TYPE type
01864 )
01865 {
01866     int c;
01867     CARD32BIT r = 0;
01868 
01869     switch (cat) {
01870       case EIMIL_CAT_VARIABLE:
01871        switch (type) {
01872         case EIMIL_TYPE_NIL:
01873          return EIMIL_SYMBOL_ID_NIL;
01874         case EIMIL_TYPE_T:
01875          return EIMIL_SYMBOL_ID_T;
01876         case EIMIL_TYPE_FEEDBACK:
01877          return EIMIL_SYMBOL_ID_FEEDBACK;
01878         case EIMIL_TYPE_CANDIDATES:
01879          return EIMIL_SYMBOL_ID_CANDIDATES;
01880         case EIMIL_TYPE_ANY:
01881          r = EIMIL_SYMBOL_ID_PRIVATE;
01882          break;
01883         case EIMIL_TYPE_BOOL:
01884          r = EIMIL_SYMBOL_ID_VARIABLE_BOOL;
01885          break;
01886         case EIMIL_TYPE_NUMBER:
01887          r = EIMIL_SYMBOL_ID_VARIABLE_NUMBER;
01888          break;
01889         case EIMIL_TYPE_CHAR:
01890          r = EIMIL_SYMBOL_ID_VARIABLE_CHAR;
01891          break;
01892         case EIMIL_TYPE_MTEXT:
01893          r = EIMIL_SYMBOL_ID_VARIABLE_MTEXT;
01894          break;
01895         case EIMIL_TYPE_EVENT:
01896          r = EIMIL_SYMBOL_ID_VARIABLE_EVENT;
01897          break;
01898         case EIMIL_TYPE_PROP:
01899          r = EIMIL_SYMBOL_ID_VARIABLE_PROP;
01900          break;
01901         default:
01902          abort();
01903        }
01904        break;
01905       case EIMIL_CAT_PROPERTY:
01906        switch (type) {
01907         case EIMIL_TYPE_BOOL:
01908          r = EIMIL_SYMBOL_ID_PROPERTY_BOOL;
01909          break;
01910         case EIMIL_TYPE_NUMBER:
01911          r = EIMIL_SYMBOL_ID_PROPERTY_NUMBER;
01912          break;
01913         case EIMIL_TYPE_CHAR:
01914          r = EIMIL_SYMBOL_ID_PROPERTY_CHAR;
01915          break;
01916         case EIMIL_TYPE_MTEXT:
01917          r = EIMIL_SYMBOL_ID_PROPERTY_MTEXT;
01918          break;
01919         default:
01920          abort();
01921        }
01922        break;
01923       case EIMIL_CAT_OPERATION:
01924        r = EIMIL_SYMBOL_ID_OPERATION;
01925        break;
01926       case EIMIL_CAT_FUNCTION:
01927        r = EIMIL_SYMBOL_ID_FUNCTION;
01928        break;
01929       case EIMIL_CAT_EXCEPTION:
01930        r = EIMIL_SYMBOL_ID_EXCEPTION;
01931        break;
01932       default:
01933        abort();
01934     }
01935 
01936     LOCK_SYNC_OBJECT(ped->pcommon->sync_object);
01937     c = ++ped->pcommon->id_counter;
01938     UNLOCK_SYNC_OBJECT(ped->pcommon->sync_object);
01939     if (c > EIMIL_ID_MAX) {
01940        /* TODO:  we should return error code.  */
01941        abort();
01942     }
01943 
01944     return ((r << 16) | c);
01945 }
01946 
01947 static EIMIL_symbol*
01948 EIMIL_make_symbol(
01949     char *name,
01950     int len,
01951     enum EIMIL_CATEGORY cat
01952 )
01953 {
01954     EIMIL_symbol *p;
01955 
01956     p = (EIMIL_symbol*) malloc(sizeof(EIMIL_symbol));
01957     if (!p) return NULL;
01958     memset(p, 0, sizeof(EIMIL_symbol));
01959     p->name = (char*) malloc(sizeof(char) * (len + 1));
01960     if (!p->name) {
01961        free(p);
01962        return NULL;
01963     }
01964     p->namelen = len;
01965     memcpy(p->name, name, len);
01966     p->name[len] = '\0';
01967     p->cat = cat;
01968 
01969     return p;
01970 }
01971 
01972 static EIMIL_symbol*
01973 lookup_symbol(
01974     EIMIL_dictionary *pdic,
01975     unsigned char *name
01976 )
01977 {
01978     EIMIL_symbol **p, *psym;
01979     int len = strlen(name);
01980     int hash = hash_function_string(name, pdic->size);
01981 
01982     p = pdic->namedic[hash];
01983 
01984     if (!p) return NULL;
01985     for (; *p; p++) {
01986        psym = *p;
01987        if ((psym->namelen == len)
01988            && (memcmp(name, psym->name, len) == 0))
01989            return psym;
01990     }
01991 
01992     return NULL;
01993 }
01994 
01995 static EIMIL_symbol*
01996 lookup_predefined_symbol(
01997     unsigned char *name
01998 )
01999 {
02000     return lookup_symbol(pdic_internal, name);
02001 }
02002 
02003 static int
02004 register_symbol_id(
02005     EIMIL_dictionary *pdic,
02006     EIMIL_symbol *psym
02007 )
02008 {
02009     int i;
02010     int id = psym->symbolid;
02011     int idx = id % pdic->size;
02012     EIMIL_symbol **p;
02013 
02014     if (!pdic->iddic) return 1;
02015 
02016     p = pdic->iddic[idx];
02017     if (!p) {
02018         /* create iddic[idx] */
02019         p = (EIMIL_symbol**) calloc(sizeof(EIMIL_symbol *), EIMIL_DICTIONARY_SUBSLOT_UNIT);
02020        if (!p) return 0;
02021        pdic->iddic[idx] = p;
02022         p[0] = psym;
02023        return 1;
02024     }
02025 
02026     for (i = 1;; i++, p++) {
02027        if (!*p) {
02028            if ((i % EIMIL_DICTIONARY_SUBSLOT_UNIT) == 0) {
02029                 /* ID dictionary is fulled with EIMIL_symbol. grow this dictionary. */
02030               p = (EIMIL_symbol**) realloc(pdic->iddic[idx],
02031                                         (i + EIMIL_DICTIONARY_SUBSLOT_UNIT)
02032                                         * sizeof(EIMIL_symbol*));
02033               if (!p) return 0;
02034               pdic->iddic[idx] = p;
02035               p = p + i - 1;
02036                 memset(p, 0, EIMIL_DICTIONARY_SUBSLOT_UNIT * sizeof(EIMIL_symbol *));
02037            }
02038            p[0] = psym;
02039            p[1] = NULL;
02040            return 1;
02041        }
02042     }
02043     /* notreached */
02044     abort();
02045     return 0;
02046 }
02047 
02048 static EIMIL_symbol*
02049 register_symbol(
02050     EIMIL_dictionary *pdic,
02051     unsigned char *name,
02052     enum EIMIL_CATEGORY cat,
02053     int id
02054 )
02055 {
02056     int i;
02057     EIMIL_symbol **p;
02058     EIMIL_symbol *psym;
02059     int len = strlen(name);
02060     int hash = hash_function_string(name, pdic->size);
02061     int id_req_p = pdic->iddic ? 1 : 0;
02062 
02063     if (lookup_predefined_symbol(name)) return NULL;
02064 
02065     p = pdic->namedic[hash];
02066     if (!p) {
02067         p = (EIMIL_symbol**) calloc(EIMIL_DICTIONARY_SUBSLOT_UNIT, sizeof(EIMIL_symbol*));
02068        if (!p) return NULL;
02069        pdic->namedic[hash] = p;
02070        psym = EIMIL_make_symbol(name, len, cat);
02071        psym->symbolid = id;
02072        if (!psym) return NULL;
02073         /* register psym to id dictionary */
02074         /* FIXME: may cause memory leaks if failed */
02075        if (!register_symbol_id(pdic, psym)) return NULL;
02076         p[0] = psym;
02077        return psym;
02078     }
02079     for (i = 1; ; i++, p++) {
02080        if (!*p) {
02081            psym = EIMIL_make_symbol(name, len, cat);
02082            psym->symbolid = id;
02083            if (!psym) return NULL;
02084             /* register psym to id dictionary */
02085             /* FIXME: may cause memory leaks if failed */
02086            if (!register_symbol_id(pdic, psym)) return NULL;
02087            if ((i % EIMIL_DICTIONARY_SUBSLOT_UNIT) == 0) {
02088                 /* Named dictionary is fulled with psym, grow it */
02089               p = (EIMIL_symbol**) realloc(pdic->namedic[hash],
02090                                         (i + EIMIL_DICTIONARY_SUBSLOT_UNIT)
02091                                         * sizeof(EIMIL_symbol*));
02092               pdic->namedic[hash] = p;
02093               p = p + i - 1;
02094                 memset(p, 0, sizeof(EIMIL_DICTIONARY_SUBSLOT_UNIT) * sizeof(EIMIL_symbol*));
02095            }
02096            p[0] = psym;
02097            p[1] = NULL;
02098            return psym;
02099        }
02100        psym = *p;
02101         /* check whether name is already registerd */
02102        if ((psym->namelen == len)
02103            && (memcmp(name, psym->name, len) == 0))
02104            return NULL;
02105     }
02106 
02107     return NULL;
02108 
02109 }
02110 
02111 static int
02112 re_register_symbol_internal(
02113     EIMIL_dictionary *pdic,
02114     EIMIL_symbol *psym
02115 )
02116 {
02117     int i;
02118     int id = psym->symbolid;
02119     int idx = id % pdic->size;
02120     EIMIL_symbol **p;
02121 
02122     if (!pdic->iddic) return 1;
02123 
02124     p = pdic->iddic[idx];
02125     if (!p) return 0;
02126 
02127     for (i = 1; *p; i++, p++) {
02128        if ((*p)->symbolid == psym->symbolid) {
02129            *p = psym;
02130            return 1;
02131        }
02132     }
02133     /* notreached */
02134     abort();
02135     return 0;
02136 }
02137 
02138 EIMIL_symbol*
02139 EIMIL_register_symbol(
02140     EIMIL_data *ped,
02141     EIMIL_dictionary *pdic,
02142     unsigned char *name,
02143     enum EIMIL_CATEGORY cat,
02144     enum EIMIL_TYPE type
02145 )
02146 {
02147     int id;
02148     int id_req_p = pdic->iddic ? 1 : 0;
02149 
02150     if (id_req_p) id = EIMIL_generate_symbolid(ped, cat, type);
02151     else id = 0;
02152 
02153     return register_symbol(pdic, name, cat, id);
02154 }
02155 
02156 EIMIL_symbol*
02157 EIMIL_intern_soft(
02158     EIMIL_dictionary *pdic,
02159     unsigned char *name
02160 )
02161 {
02162     EIMIL_symbol *psym;
02163     if ((psym = lookup_predefined_symbol(name)) != NULL) return psym;
02164 
02165     return lookup_symbol(pdic, name);
02166 }
02167 
02168 EIMIL_symbol*
02169 EIMIL_lookup_symbol_internal(
02170     EIMIL_dictionary *pdic,
02171     CARD32BIT id
02172 )
02173 {
02174     int idx;
02175     EIMIL_symbol **p, *psym;
02176 
02177     switch (id) {
02178       case EIMIL_SYMBOL_ID_NIL:
02179        return pEIMIL_nil_sym;
02180       case EIMIL_SYMBOL_ID_T:
02181        return pEIMIL_t_sym;
02182       case EIMIL_SYMBOL_ID_FEEDBACK:
02183        return pEIMIL_feedback_sym;
02184       case EIMIL_SYMBOL_ID_CANDIDATES:
02185        return pEIMIL_candidates_sym;
02186       default:
02187        if (!pdic->iddic) return NULL;
02188        idx = id % pdic->size;
02189        p = pdic->iddic[idx];
02190        if (!p) return NULL;
02191        
02192        for (; *p; p++) {
02193           psym = *p;
02194           if (psym->symbolid == id) return psym;
02195        }
02196     }
02197 
02198     return NULL;
02199 }
02200 
02201 void
02202 EIMIL_destruct_symbol(
02203     EIMIL_symbol *psym
02204 )
02205 {
02206 
02207     if (!psym) return;
02208 
02209     if (psym->name) free(psym->name);
02210     switch(psym->cat) {
02211       case EIMIL_CAT_VARIABLE:
02212        if (psym->obj.v.pv) {
02213          if (!psym->obj.v.constp)
02214              EIMIL_RMREF(*psym->obj.v.pv);
02215        }
02216        break;
02217       case EIMIL_CAT_EXCEPTION:
02218       {
02219          if (psym->obj.e.msgs) {
02220              EIMIL_message *msgs;
02221              for (msgs = psym->obj.e.msgs;msgs->lang;msgs++) {
02222                 free(msgs->lang);
02223                 free(msgs->msg);
02224              }
02225              free(psym->obj.e.msgs);
02226          }
02227       }
02228       case EIMIL_CAT_OPERATION:
02229       {
02230          int i, n;
02231          EIMIL_dependency *pdeps;
02232          EIMIL_symbol **pps;
02233 
02234          n = psym->obj.o.numdepends;
02235          pdeps = psym->obj.o.pdeps;
02236          for (i = 0;i < n;i++, pdeps++) {
02237              pps = pdeps->depends;
02238              if (pps) free(pps);
02239              pps = pdeps->affects;
02240              if (pps) free(pps);
02241          }
02242          free(pdeps);
02243          break;
02244       }
02245       case EIMIL_CAT_FUNCTION:
02246        /* TODO */
02247        break;
02248       default:
02249        break;
02250     }
02251 
02252     free(psym);
02253 }
02254 
02255 static EIMIL_symbol*
02256 copy_symbol(
02257     EIMIL_symbol *psym
02258 )
02259 {
02260     EIMIL_symbol *p;
02261 
02262     p = (EIMIL_symbol*) malloc(sizeof(EIMIL_symbol));
02263     if (!p) return NULL;
02264     *p = *psym;
02265 
02266     p->name = (char*) malloc(sizeof(char) * (psym->namelen + 1));
02267     if (!p->name) {
02268        free(p);
02269        return NULL;
02270     }
02271     p->namelen = psym->namelen;
02272     memcpy(p->name, psym->name, p->namelen + 1);
02273 
02274     return p;
02275 }
02276 
02277 static EIMIL_symbol*
02278 duplicate_variable_symbol(
02279     EIMIL_symbol *psym
02280 )
02281 {
02282     EIMIL_value *pvs, *pvd;
02283     EIMIL_symbol *p;
02284 
02285     ASSERT(psym->cat == EIMIL_CAT_VARIABLE);
02286 
02287     p = copy_symbol(psym);
02288     if (!p) return NULL;
02289 
02290     p->obj.v.pv = NULL;
02291     pvs = psym->obj.v.pv;
02292     if (!pvs) return p;
02293     pvd = EIMIL_copy_value(pvs);
02294     if (!pvd) {
02295        EIMIL_destruct_symbol(p);
02296        return NULL;
02297     }
02298     EIMIL_ADDREF(*pvd);
02299     p->obj.v.pv = pvd;
02300 
02301     return p;
02302 }
02303 
02304 static EIMIL_symbol*
02305 rebuild_operation_symbol(
02306     EIMIL_dictionary *pdic,
02307     EIMIL_symbol *psym
02308 )
02309 {
02310     int i, j, n;
02311     EIMIL_operation *pop, *popd;
02312     EIMIL_dependency *pdeps_s, *pdeps_d;
02313     EIMIL_symbol *p, *psymt;
02314     EIMIL_symbol **pps_s, **pps_d;
02315     ASSERT(psym->cat == EIMIL_CAT_OPERATION);
02316 
02317     p = copy_symbol(psym);
02318     if (!p) return NULL;
02319     pop = &psym->obj.o;
02320     popd = &p->obj.o;
02321 
02322     popd->pdeps = NULL;
02323     if (pop->numdepends > 0) {
02324        pdeps_d = (EIMIL_dependency*) malloc(sizeof(EIMIL_dependency)
02325                                         * pop->numdepends);
02326        if (!pdeps_d) {
02327            EIMIL_destruct_symbol(p);
02328            return NULL;
02329        }
02330        memset(pdeps_d, 0, sizeof(EIMIL_dependency) * pop->numdepends);
02331     } else {
02332        pdeps_d = NULL;
02333     }
02334     popd->pdeps = pdeps_d;
02335     popd->numdepends = pop->numdepends;
02336     pdeps_s = pop->pdeps;
02337     for (i = 0; i < pop->numdepends;
02338         i++, pdeps_s++, pdeps_d++) {
02339        if (pdeps_s->numdepends > 0) {
02340            n = pdeps_s->numdepends;
02341            pps_s = pdeps_s->depends;
02342            pps_d = (EIMIL_symbol**) malloc(sizeof(EIMIL_symbol*) * n);
02343            if (!pps_d) {
02344               EIMIL_destruct_symbol(p);
02345               return NULL;
02346            }
02347            pdeps_d->numdepends = n;
02348            pdeps_d->depends = pps_d;
02349            for (j = 0; j < n; j++, pps_s++, pps_d++) {
02350               psymt = EIMIL_lookup_symbol_internal(pdic, (*pps_s)->symbolid);
02351               ASSERT(psymt);
02352               ASSERT(psymt->cat == EIMIL_CAT_VARIABLE);
02353               *pps_d = psymt;
02354            }
02355        }
02356        if (pdeps_s->numaffects > 0) {
02357            n = pdeps_s->numaffects;
02358            pps_s = pdeps_s->affects;
02359            pps_d = (EIMIL_symbol**) malloc(sizeof(EIMIL_symbol*) * n);
02360            if (!pps_d) {
02361               EIMIL_destruct_symbol(p);
02362               return NULL;
02363            }
02364            pdeps_d->numaffects = n;
02365            pdeps_d->affects = pps_d;
02366            for (j = 0; j < n; j++, pps_s++, pps_d++) {
02367               psymt = EIMIL_lookup_symbol_internal(pdic, (*pps_s)->symbolid);
02368               ASSERT(psymt);
02369               ASSERT(psymt->cat == EIMIL_CAT_VARIABLE);
02370               *pps_d = psymt;
02371            }
02372        }
02373     }
02374 
02375     return p;
02376 }
02377 
02378 EIMIL_dictionary*
02379 EIMIL_duplicate_dictionary(
02380     EIMIL_dictionary *psdic
02381 )
02382 {
02383     int i, j, n, size;
02384     EIMIL_symbol **ppss, **ppsd, **ppsdh;
02385     EIMIL_symbol *psym;
02386     EIMIL_dictionary *pddic;
02387 
02388     pddic = EIMIL_new_dictionary(psdic->size, (psdic->iddic != NULL));
02389     if (!pddic) return NULL;
02390 
02391     /* STEP1: shallow copy */
02392     for (i = 0; i < psdic->size; i++) {
02393        ppss = psdic->namedic[i];
02394        if (!ppss) continue;
02395        for (n = 0; *ppss; ppss++, n++);
02396        ppss = psdic->namedic[i];
02397        size = (((n / EIMIL_DICTIONARY_SUBSLOT_UNIT) + 1)
02398               * EIMIL_DICTIONARY_SUBSLOT_UNIT);
02399        ppsdh = (EIMIL_symbol**) malloc(sizeof(EIMIL_symbol*) * size);
02400        if (!ppsdh) return NULL;
02401        ppsd = ppsdh;
02402        ppsd[n] = NULL;
02403        for (j = 0; j < n; j++, ppss++, ppsd++) {
02404            *ppsd = *ppss;
02405            register_symbol_id(pddic, *ppsd);
02406        }
02407        pddic->namedic[i] = ppsd;
02408     }
02409     /* STEP2: variable duplication. */
02410     for (i = 0; i < psdic->size; i++) {
02411        ppss = psdic->namedic[i];
02412        if (!ppss) continue;
02413        ppsd = pddic->namedic[i];
02414        for (; *ppss; ppss++, ppsd++) {
02415            if (ppss[0]->cat == EIMIL_CAT_VARIABLE) {
02416               psym = duplicate_variable_symbol(*ppss);
02417               if (!psym) return NULL;
02418               *ppsd = psym;
02419               re_register_symbol_internal(pddic, psym);
02420            }
02421        }
02422     }
02423     /* STEP3: rebuild operation symbol.  */
02424     for (i = 0; i < psdic->size; i++) {
02425        ppss = psdic->namedic[i];
02426        if (!ppss) continue;
02427        ppsd = pddic->namedic[i];
02428        for (; *ppss; ppss++, ppsd++) {
02429            if (ppss[0]->cat == EIMIL_CAT_OPERATION) {
02430               psym = rebuild_operation_symbol(pddic, *ppss);
02431               if (!psym) return NULL;
02432               *ppsd = psym;
02433               re_register_symbol_internal(pddic, psym);
02434            }
02435        }
02436     }
02437 
02438     return pddic;
02439 }
02440 
02441 /********************************************************************************
02442                      EIMIL document definition.
02443 *********************************************************************************/
02444 
02445 /***************************************
02446              IDP parser
02447 ***************************************/
02448 
02449 /*
02450   function declaration.
02451 */
02452 static int
02453 EIMIL_message_element_parser(
02454     EIMIL_data *ped,
02455     EIMIL_attrs *patr,
02456     enum EIMIL_TAG_TYPE type,
02457     UTF8 *pchars,
02458     void **pprivate
02459 );
02460 static int
02461 EIMIL_dependency_element_parser(
02462     EIMIL_data *ped,
02463     EIMIL_attrs *patr,
02464     enum EIMIL_TAG_TYPE type,
02465     UTF8 *pchars,
02466     void **pprivate
02467 );
02468 static int
02469 EIMIL_decldata_element_parser(
02470     EIMIL_data *ped,
02471     EIMIL_attrs *patr,
02472     enum EIMIL_TAG_TYPE type,
02473     UTF8 *pchars,
02474     void **pprivate
02475 );
02476 static int
02477 EIMIL_declprop_element_parser(
02478     EIMIL_data *ped,
02479     EIMIL_attrs *patr,
02480     enum EIMIL_TAG_TYPE type,
02481     UTF8 *pchars,
02482     void **pprivate
02483 );
02484 static int
02485 EIMIL_declop_element_parser(
02486     EIMIL_data *ped,
02487     EIMIL_attrs *patr,
02488     enum EIMIL_TAG_TYPE type,
02489     UTF8 *pchars,
02490     void **pprivate
02491 );
02492 static int
02493 EIMIL_commitnotify_element_parser(
02494     EIMIL_data *ped,
02495     EIMIL_attrs *patr,
02496     enum EIMIL_TAG_TYPE type,
02497     UTF8 *pchars,
02498     void **pprivate
02499 );
02500 static int
02501 EIMIL_declexception_element_parser(
02502     EIMIL_data *ped,
02503     EIMIL_attrs *patr,
02504     enum EIMIL_TAG_TYPE type,
02505     UTF8 *pchars,
02506     void **pprivate
02507 );
02508 static int
02509 EIMIL_UIdata_element_parser(
02510     EIMIL_data *ped,
02511     EIMIL_attrs *patr,
02512     enum EIMIL_TAG_TYPE type,
02513     UTF8 *pchars,
02514     void **pprivate
02515 );
02516 static int
02517 EIMIL_inherit_element_parser(
02518     EIMIL_data *ped,
02519     EIMIL_attrs *patr,
02520     enum EIMIL_TAG_TYPE type,
02521     UTF8 *pchars,
02522     void **pprivate
02523 );
02524 static int
02525 EIMIL_interface_element_parser(
02526     EIMIL_data *ped,
02527     EIMIL_attrs *patr,
02528     enum EIMIL_TAG_TYPE type,
02529     UTF8 *pchars,
02530     void **pprivate
02531 );
02532 static int
02533 EIMIL_engine_element_parser(
02534     EIMIL_data *ped,
02535     EIMIL_attrs *patr,
02536     enum EIMIL_TAG_TYPE type,
02537     UTF8 *pchars,
02538     void **pprivate
02539 );
02540 
02541 /*
02542   IDP document template.
02543  */
02544 
02545 EIMIL_attr_template
02546 EIMIL_attr_langinfo[] = {{"xml:lang", EIMIL_attr_REQUIRED, NULL},
02547                       {NULL, 0, NULL}};
02548 
02549 EIMIL_attr_template
02550 EIMIL_attr_decldata[] = {{"name", EIMIL_attr_REQUIRED, NULL},
02551                       {"type", EIMIL_attr_REQUIRED, NULL},
02552                       {NULL, 0, NULL}};
02553 
02554 EIMIL_attr_template
02555 EIMIL_attr_declprop[] = {{"name", EIMIL_attr_REQUIRED, NULL},
02556                       {"type", EIMIL_attr_REQUIRED, NULL},
02557                       {NULL, 0, NULL}};
02558 
02559 EIMIL_attr_template
02560 EIMIL_attr_declop[] = {{"name", EIMIL_attr_REQUIRED, NULL},
02561                      {NULL, 0, NULL}};
02562 
02563 EIMIL_attr_template
02564 EIMIL_attr_declexception[] = {{"name", EIMIL_attr_REQUIRED, NULL},
02565                            {NULL, 0, NULL}};
02566 
02567 EIMIL_attr_template
02568 EIMIL_attr_commitnotify[] = {{"name", EIMIL_attr_REQUIRED, NULL},
02569                           {NULL, 0, NULL}};
02570 
02571 EIMIL_attr_template
02572 EIMIL_attr_UIdata[] = {{"depend", EIMIL_attr_REQUIRED, NULL},
02573                      {NULL, 0, NULL}};
02574 
02575 EIMIL_attr_template
02576 EIMIL_attr_message[] = {{"xml:lang", EIMIL_attr_IMPLIED, NULL},
02577                      {NULL, 0, NULL}};
02578 
02579 EIMIL_attr_template
02580 EIMIL_attr_dependency[] = {{"depend", EIMIL_attr_REQUIRED, NULL},
02581                         {"affect", EIMIL_attr_REQUIRED, NULL},
02582                         {NULL, 0, NULL}};
02583 
02584 EIMIL_attr_template
02585 EIMIL_attr_EIMIL[] = {{"name", EIMIL_attr_REQUIRED, NULL},
02586                     {"revision", EIMIL_attr_REQUIRED, NULL},
02587                     {"type", EIMIL_attr_NORMAL, "concreate"},
02588                     {NULL, 0, NULL}};
02589 
02590 EIMIL_element_template
02591 EIMIL_declexception_template[] = {{"message", EIMIL_message_element_parser,
02592                                EIMIL_attr_message,
02593                                EIMIL_element_single, NULL, NULL},
02594                               {NULL, NULL, NULL, 0, NULL, NULL}};
02595 
02596 EIMIL_element_template
02597 EIMIL_declop_template[] = {{"dependency", EIMIL_dependency_element_parser,
02598                          EIMIL_attr_dependency,
02599                          EIMIL_element_EMPTY | EIMIL_element_single,
02600                          NULL, NULL},
02601                         {NULL, NULL, NULL, 0, NULL, NULL}};
02602 
02603 EIMIL_element_template
02604 EIMIL_interface_template[] = {{"langinfo", NULL,
02605                             EIMIL_attr_langinfo,
02606                             EIMIL_element_single, NULL, NULL},
02607                            {"decldata", EIMIL_decldata_element_parser,
02608                             EIMIL_attr_decldata,
02609                             EIMIL_element_EMPTY | EIMIL_element_multiple,
02610                             NULL, NULL},
02611                            {"declprop", EIMIL_declprop_element_parser,
02612                             EIMIL_attr_declprop,
02613                             EIMIL_element_EMPTY | EIMIL_element_multiple,
02614                             NULL, NULL},
02615                            {"declop", EIMIL_declop_element_parser,
02616                             EIMIL_attr_declop,
02617                             EIMIL_element_multiple,
02618                             EIMIL_declop_template, NULL},
02619                            {"commitnotify", EIMIL_commitnotify_element_parser,
02620                             EIMIL_attr_commitnotify,
02621                             EIMIL_element_EMPTY | EIMIL_element_0or1,
02622                             NULL, NULL},
02623                            {"declexception", EIMIL_declexception_element_parser,
02624                             EIMIL_attr_declexception,
02625                             EIMIL_element_multiple,
02626                             EIMIL_declexception_template, NULL},
02627                            {"UIdata", EIMIL_UIdata_element_parser,
02628                             EIMIL_attr_UIdata,
02629                             EIMIL_element_EMPTY | EIMIL_element_0or1,
02630                             NULL, NULL},
02631                            {NULL, NULL, NULL, 0, NULL, NULL}};
02632 
02633 
02634 EIMIL_attr_template
02635 EIMIL_attr_inherit[] = {{"src", EIMIL_attr_REQUIRED, NULL},
02636                      {NULL, 0, NULL}};
02637 
02638 EIMIL_attr_template
02639 EIMIL_attr_engine[] = {{"name", EIMIL_attr_REQUIRED, NULL},
02640                      {"class", EIMIL_attr_REQUIRED, NULL},
02641                      {NULL, 0, NULL}};
02642 
02643 EIMIL_element_template
02644 EIMIL_doctemp[] = {{"inherit", EIMIL_inherit_element_parser,
02645                   EIMIL_attr_inherit,
02646                   EIMIL_element_EMPTY | EIMIL_element_multiple,
02647                   NULL, NULL},
02648                  {"interface", EIMIL_interface_element_parser,
02649                   NULL,
02650                   (EIMIL_subelement_ordered | EIMIL_element_single),
02651                   EIMIL_interface_template, NULL},
02652                  {"engine", EIMIL_engine_element_parser,
02653                   EIMIL_attr_engine,
02654                   EIMIL_element_multiple, NULL, NULL},
02655                  {NULL, NULL, NULL, 0, NULL, NULL}};
02656 
02657 EIMIL_element_template
02658 EIMIL_docroot[] = {{"EIMIL", NULL,
02659                   EIMIL_attr_EIMIL,
02660                   (EIMIL_subelement_ordered | EIMIL_element_single),
02661                   EIMIL_doctemp, NULL},
02662                  {NULL, NULL, NULL, 0, NULL, NULL}};
02663 
02664 static int
02665 EIMIL_message_element_parser(
02666     EIMIL_data *ped,
02667     EIMIL_attrs *patr,
02668     enum EIMIL_TAG_TYPE type,
02669     UTF8 *pchars,
02670     void **pprivate
02671 )
02672 {
02673     int n;
02674     EIMIL_parser_state* pps = &ped->pcommon->ps;
02675     EIMIL_message **pmsgs = (EIMIL_message**) *pprivate;
02676     EIMIL_message *msgs = *pmsgs;
02677     UTF8 *lang, *msg;
02678     UTF32 *pu32;
02679 
02680     if (type != EIMIL_END_TAG) return 1;
02681 
02682     if (msgs) {
02683        for (n = 0;msgs->lang;msgs++, n++);
02684        msgs = *pmsgs;
02685     }else{
02686        n = 0;
02687     }
02688 
02689     for (;patr->name;patr++) {
02690        if (strcmp(patr->name, "xml:lang") == 0) {
02691            if (!EIMIL_get_attr_cdata(patr->val, &lang)) {
02692               EIMIL_set_error_pt(ped, NULL, "Invalid cdata in xml:lang");
02693               return 0;
02694            }
02695        } else {
02696            return 0;
02697        }
02698     }
02699     {
02700        Ebyte *s, *e = pps->end;
02701 
02702        for (s = pps->start;(s < e && EIMIL_isspace(*s));s++);
02703        for (;(e > s && EIMIL_isspace(*e));e--);
02704        if ((s >= e)
02705            || (!(msg = EIMIL_resolve_reference(s, e)))) {
02706            EIMIL_set_error_pt(ped, s, "Invalid contents in message element");
02707            free(lang);
02708            return 0;
02709        }
02710     }
02711     n++;
02712     msgs = (EIMIL_message*) realloc(msgs, sizeof(EIMIL_message) * (n + 1));
02713     pu32 = EIMIL_convert_UTF8_to_UTF32(lang);
02714     free(lang);
02715     if (!pu32) return 0;
02716     msgs[n - 1].lang = pu32;
02717     pu32 = EIMIL_convert_UTF8_to_UTF32(msg);
02718     free(msg);
02719     if (!pu32) return 0;
02720     msgs[n - 1].msg = pu32;
02721     msgs[n].lang = NULL;
02722     msgs[n].msg = NULL;
02723     *pmsgs = msgs;
02724 
02725     return 1;
02726 }
02727 
02728 static int
02729 EIMIL_add_symbol_to_slots(
02730     EIMIL_data *ped,
02731     int num, EIMIL_symbol ***pslots,
02732     unsigned char *name,
02733     enum EIMIL_CATEGORY cat
02734 )
02735 {
02736     EIMIL_symbol *psym, **slots;
02737 
02738     slots = *pslots;
02739 
02740     psym = EIMIL_intern_soft(ped->pdic, name);
02741     if (!psym) {
02742        EIMIL_set_error_pt(ped, NULL,
02743                         "%s is not declared by declop.", name);
02744        return 0;
02745     }
02746     if (!((psym->publicp)
02747          && (psym->cat == cat))) {
02748        EIMIL_set_error_pt(ped, NULL,
02749                         "%s is registered, but it's not defined properly.", name);
02750        return 0;
02751     }
02752 
02753     slots = (EIMIL_symbol**) realloc(slots, sizeof(EIMIL_symbol*) * (num + 1));
02754     if (!slots) {
02755        EIMIL_set_out_of_memory(ped);
02756        return 0;
02757     }
02758     slots[num] = psym;
02759     *pslots = slots;
02760 
02761     return 1;
02762 }
02763 
02764 static int
02765 EIMIL_dependency_element_parser(
02766     EIMIL_data *ped,
02767     EIMIL_attrs *patr,
02768     enum EIMIL_TAG_TYPE type,
02769     UTF8 *pchars,
02770     void **pprivate
02771 )
02772 {
02773     UTF8 *name;
02774     EIMIL_dependency *pdep;
02775     EIMIL_operation *pop = (EIMIL_operation*) *pprivate;
02776 
02777     if (type != EIMIL_EMPTY_TAG) return 1;
02778 
02779     pop->pdeps = (EIMIL_dependency*) realloc(pop->pdeps,
02780                                         sizeof(EIMIL_dependency)
02781                                         * (pop->numdepends + 1));
02782     if (!pop->pdeps) return 0;
02783     pdep = pop->pdeps + pop->numdepends;
02784     pop->numdepends++;
02785     memset(pdep, 0, sizeof(EIMIL_dependency));
02786 
02787     for (; patr->name; patr++) {
02788        if (strcmp(patr->name, "depend") == 0) {
02789            Ebyte *c;
02790 
02791            c = patr->val;
02792            while ((c = EIMIL_get_attr_nmtokens(c, &name)) != NULL) {
02793               if (!EIMIL_add_symbol_to_slots(ped,
02794                                           pdep->numdepends,
02795                                           &pdep->depends,
02796                                           name, EIMIL_CAT_VARIABLE)) {
02797                   free(name);
02798                   return 0;
02799               }
02800               free(name);
02801               pdep->numdepends++;
02802            }
02803            if (pdep->numdepends == 0) {
02804               EIMIL_set_error_pt(ped, NULL, "Invalid nmtokens in `depend'");
02805               return 0;
02806            }
02807        } else if (strcmp(patr->name, "affect") == 0) {
02808            Ebyte *c;
02809 
02810            c = patr->val;
02811            while ((c = EIMIL_get_attr_nmtokens(c, &name)) != NULL) {
02812               if (!EIMIL_add_symbol_to_slots(ped,
02813                                           pdep->numaffects,
02814                                           &pdep->affects,
02815                                           name, EIMIL_CAT_VARIABLE)) {
02816                   free(name);
02817                   return 0;
02818               }
02819               free(name);
02820               pdep->numaffects++;
02821            }
02822            if (pdep->numaffects == 0) {
02823               EIMIL_set_error_pt(ped, NULL, "Invalid nmtokens in `depend'");
02824               return 0;
02825            }
02826        }
02827     }
02828     if (type == EIMIL_TYPE_INVALID) {
02829        EIMIL_set_error_pt(ped, NULL,
02830                         "`type' attribute must be `bool', `number', `char', or `mtext'.");
02831     }
02832     return type;
02833 }
02834 
02835 static int
02836 EIMIL_decldata_element_parser(
02837     EIMIL_data *ped,
02838     EIMIL_attrs *patr,
02839     enum EIMIL_TAG_TYPE type,
02840     UTF8 *pchars,
02841     void **pprivate
02842 )
02843 {
02844     enum EIMIL_TYPE etype;
02845     UTF8 *name;
02846     EIMIL_symbol *psym = NULL;
02847 
02848     if (type != EIMIL_EMPTY_TAG) return 1;
02849 
02850     etype = EIMIL_get_type_from_attrs(ped, patr);
02851     if (etype == EIMIL_TYPE_INVALID) {
02852        return 0;
02853     }
02854     for (;patr->name;patr++) {
02855        if (strcmp(patr->name, "name") == 0) {
02856            if (!EIMIL_get_attr_nmtoken(patr->val, &name)) {
02857               EIMIL_set_error_pt(ped, NULL, "Invalid nmtoken in `name'");
02858               return 0;
02859            }
02860            psym = EIMIL_register_symbol(ped, ped->pdic, name,
02861                                     EIMIL_CAT_VARIABLE,
02862                                     etype);
02863            if (!psym) {
02864               EIMIL_set_error_pt(ped, NULL,
02865                                "%s is already registered.", name);
02866               free(name);
02867               return 0;
02868            }
02869            free(name);
02870            psym->publicp = 1;
02871            psym->obj.v.type = etype;
02872            psym->obj.v.pv = NULL;
02873        } else {
02874            return 0;
02875        }
02876     }
02877     ASSERT(psym);
02878     return 1;
02879 }
02880 
02881 static int
02882 EIMIL_declprop_element_parser(
02883     EIMIL_data *ped,
02884     EIMIL_attrs *patr,
02885     enum EIMIL_TAG_TYPE type,
02886     UTF8 *pchars,
02887     void **pprivate
02888 )
02889 {
02890     UTF8 *name;
02891     EIMIL_symbol *psym = NULL;
02892 
02893     if (type != EIMIL_EMPTY_TAG) return 1;
02894 
02895     type = EIMIL_get_type_from_attrs(ped, patr);
02896     if (type == EIMIL_TYPE_INVALID) {
02897        return 0;
02898     }
02899     for (;patr->name;patr++) {
02900        if (strcmp(patr->name, "name") == 0) {
02901            if (!EIMIL_get_attr_nmtoken(patr->val, &name)) {
02902               EIMIL_set_error_pt(ped, NULL, "Invalid nmtoken in `name'");
02903               return 0;
02904            }
02905            psym = EIMIL_register_symbol(ped, ped->pdic, name,
02906                                     EIMIL_CAT_PROPERTY,
02907                                     type);
02908            if (!psym) {
02909               EIMIL_set_error_pt(ped, NULL,
02910                                "%s is already registered.",
02911                                name);
02912               free(name);
02913               return 0;
02914            }
02915            free(name);
02916            psym->publicp = 1;
02917            psym->obj.p.type = type;
02918        } else {
02919            return 0;
02920        }
02921     }
02922     ASSERT(psym);
02923     return 1;
02924 }
02925 
02926 static int
02927 EIMIL_declop_element_parser(
02928     EIMIL_data *ped,
02929     EIMIL_attrs *patr,
02930     enum EIMIL_TAG_TYPE type,
02931     UTF8 *pchars,
02932     void **pprivate
02933 )
02934 {
02935     UTF8 *name;
02936     EIMIL_symbol *psym = NULL;
02937 
02938     if (type != EIMIL_START_TAG) return 1;
02939 
02940     for (; patr->name; patr++) {
02941        if (strcmp(patr->name, "name") == 0) {
02942            if (!EIMIL_get_attr_nmtoken(patr->val, &name)) {
02943               EIMIL_set_error_pt(ped, NULL, "Invalid nmtoken in `name'");
02944               return 0;
02945            }
02946            psym = EIMIL_register_symbol(ped, ped->pdic, name,
02947                                     EIMIL_CAT_OPERATION,
02948                                     EIMIL_TYPE_INVALID);
02949            if (!psym) {
02950               EIMIL_set_error_pt(ped, NULL,
02951                                "%s is already registered.");
02952               return 0;
02953            }
02954            free(name);
02955            psym->publicp = 1;
02956            psym->obj.o.commitnotifyp = 0;
02957            psym->obj.o.numdepends = 0;
02958            psym->obj.o.pdeps = NULL;
02959        } else {
02960            return 0;
02961        }
02962     }
02963     ASSERT(psym);
02964 
02965     *pprivate = &psym->obj.o;
02966 
02967     return 1;
02968 }
02969 
02970 static int
02971 EIMIL_add_commitnotify(
02972     EIMIL_data *ped,
02973     EIMIL_symbol *psym
02974 )
02975 {
02976     int num;
02977     EIMIL_symbol **psyms;
02978 
02979     ASSERT(psym->cat == EIMIL_CAT_OPERATION);
02980 
02981     if (psym->obj.o.commitnotifyp) return 1;
02982 
02983     psyms = ped->commitnotify_ops;
02984     num = ped->commitnotify_numops;
02985     psyms = (EIMIL_symbol**) realloc(psyms, sizeof(EIMIL_symbol*) * (num + 1));
02986     if (!psyms) return 0;
02987     psyms[num] = psym;
02988     ped->commitnotify_ops = psyms;
02989     ped->commitnotify_numops++;
02990     return 1;
02991 }
02992 
02993 static int
02994 EIMIL_del_commitnotify(
02995     EIMIL_data *ped,
02996     EIMIL_symbol *psym
02997 )
02998 {
02999     int i, num;
03000     EIMIL_symbol **psyms;
03001 
03002     ASSERT(psym->cat == EIMIL_CAT_OPERATION);
03003 
03004     if (!psym->obj.o.commitnotifyp) return 1;
03005 
03006     psyms = ped->commitnotify_ops;
03007     num = ped->commitnotify_numops;
03008     for (i = 0; i < num; i++) {
03009        if (psyms[i] == psym) {
03010            if ((num - i - 1) > 0) {
03011               memmove(psyms + i, psyms + i + 1,
03012                      sizeof(EIMIL_symbol*)
03013                      * (num - i - 1));
03014            }
03015            ped->commitnotify_numops--;
03016            return 1;
03017        }
03018     }
03019     /* not reached */
03020     abort();
03021     return 0;
03022 }
03023 
03024 static int
03025 EIMIL_commitnotify_element_parser(
03026     EIMIL_data *ped,
03027     EIMIL_attrs *patr,
03028     enum EIMIL_TAG_TYPE type,
03029     UTF8 *pchars,
03030     void **pprivate
03031 )
03032 {
03033     EIMIL_attrs *patr2;
03034     UTF8 *name;
03035     int flag = -1;
03036     EIMIL_symbol *psym = NULL;
03037 
03038     if (type != EIMIL_EMPTY_TAG) return 1;
03039 
03040     for (patr2 = patr; patr2->name; patr2++) {
03041        if (strcmp(patr->name, "flag") == 0) {
03042            if (!EIMIL_get_attr_nmtoken(patr2->val, &name)) {
03043               flag = -1;
03044               break;
03045            }
03046            if (strcmp(name, "on") == 0) flag = 1;
03047            else if (strcmp(name, "off") == 0) flag = 0;
03048            else flag = -1;
03049            free(name);
03050            break;
03051        }
03052     }
03053     if (flag < 0) {
03054        EIMIL_set_error_pt(ped, NULL, "`flag' attribute must be `on' or `off'.");
03055        return 0;
03056     }
03057     for (; patr->name; patr++) {
03058        if (strcmp(patr->name, "op") == 0) {
03059            Ebyte *c;
03060            int i = 0;
03061 
03062            for (c = patr->val;c;c = EIMIL_get_attr_nmtokens(patr->val, &name)) {
03063               psym = EIMIL_intern_soft(ped->pdic, name);
03064               if (!psym) {
03065                   EIMIL_set_error_pt(ped, NULL,
03066                                    "%s is not declared by declop.");
03067                   return 0;
03068               }
03069               if (!((psym->publicp)
03070                     && (psym->cat == EIMIL_CAT_OPERATION))) {
03071                   EIMIL_set_error_pt(ped, NULL,
03072                                    "%s is registered, but it's not valid operation.");
03073                   return 0;
03074               }
03075               if (flag) {
03076                   EIMIL_add_commitnotify(ped, psym);
03077                   psym->obj.o.commitnotifyp = 1;
03078               } else {
03079                   EIMIL_del_commitnotify(ped, psym);
03080                   psym->obj.o.commitnotifyp = 0;
03081               }
03082               free(name);
03083               i++;
03084            }
03085            if (i == 0) {
03086               EIMIL_set_error_pt(ped, NULL, "Invalid nmtokens in `op'");
03087               return 0;
03088            }
03089        } else {
03090            return 0;
03091        }
03092     }
03093     return 1;
03094 }
03095 
03096 static int
03097 EIMIL_declexception_element_parser(
03098     EIMIL_data *ped,
03099     EIMIL_attrs *patr,
03100     enum EIMIL_TAG_TYPE type,
03101     UTF8 *pchars,
03102     void **pprivate
03103 )
03104 {
03105     UTF8 *name;
03106     EIMIL_symbol *psym = NULL;
03107 
03108     if (type != EIMIL_START_TAG) return 1;
03109 
03110     for (; patr->name; patr++) {
03111        if (strcmp(patr->name, "name") == 0) {
03112            if (!EIMIL_get_attr_nmtoken(patr->val, &name)) {
03113               EIMIL_set_error_pt(ped, NULL, "Invalid nmtoken in `name'");
03114               return 0;
03115            }
03116            psym = EIMIL_register_symbol(ped, ped->pdic, name,
03117                                     EIMIL_CAT_EXCEPTION,
03118                                     EIMIL_TYPE_INVALID);
03119            if (!psym) {
03120               EIMIL_set_error_pt(ped, NULL,
03121                                "%s is already registered.");
03122               return 0;
03123            }
03124            free(name);
03125            psym->publicp = 1;
03126            psym->obj.e.msgs = NULL;
03127        } else {
03128            return 0;
03129        }
03130     }
03131     ASSERT(psym);
03132 
03133     return 1;
03134 }
03135 
03136 static int
03137 EIMIL_UIdata_element_parser(
03138     EIMIL_data *ped,
03139     EIMIL_attrs *patr,
03140     enum EIMIL_TAG_TYPE type,
03141     UTF8 *pchars,
03142     void **pprivate
03143 )
03144 {
03145     UTF8 *name;
03146     EIMIL_symbol *psym;
03147     EIMIL_value *pv;
03148 
03149     if (type != EIMIL_EMPTY_TAG) return 1;
03150 
03151     for (; patr->name; patr++) {
03152        if (strcmp(patr->name, "depend") == 0) {
03153            if (!EIMIL_get_attr_nmtoken(patr->val, &name)) {
03154               EIMIL_set_error_pt(ped, NULL, "Invalid nmtoken in `depend'");
03155               return 0;
03156            }
03157            psym = EIMIL_intern_soft(ped->pdic, name);
03158            if (!psym) {
03159               EIMIL_set_error_pt(ped, NULL,
03160                                "%s is not declared by decldata.");
03161               return 0;
03162            }
03163            if (!((psym->publicp)
03164                 && (psym->cat == EIMIL_CAT_VARIABLE)
03165                 && (psym->obj.v.type == EIMIL_TYPE_MTEXT))) {
03166               EIMIL_set_error_pt(ped, NULL,
03167                                "%s is registered, but it's not valid mtext data.");
03168               return 0;
03169            }
03170            if ((ped->psym_uidata)
03171               && (ped->psym_uidata->obj.v.pv)) {
03172               pv = ped->psym_uidata->obj.v.pv;
03173               ASSERT(pv->type == EIMIL_TYPE_MTEXT);
03174               pv->v.mtext.UIdatap = 0;
03175            }
03176            pv = psym->obj.v.pv;
03177            if (pv) {
03178               ASSERT(pv->type == EIMIL_TYPE_MTEXT);
03179               pv->v.mtext.UIdatap = 1;
03180            }
03181            ped->psym_uidata = psym;
03182            free(name);
03183        } else {
03184            return 0;
03185        }
03186     }
03187     return 1;
03188 }
03189 
03190 static int
03191 EIMIL_inherit_element_parser(
03192     EIMIL_data *ped,
03193     EIMIL_attrs *patr,
03194     enum EIMIL_TAG_TYPE type,
03195     UTF8 *pchars,
03196     void **pprivate
03197 )
03198 {
03199     UTF8 *uaddr;
03200 
03201     if (type != EIMIL_EMPTY_TAG) return 1;
03202 
03203     for (;patr->name;patr++) {
03204        if (strcmp(patr->name, "src") == 0) {
03205            if (!EIMIL_get_attr_cdata(patr->val, &uaddr)) {
03206               EIMIL_set_error_pt(ped, NULL, "Invalid cdata in `src'");
03207               return 0;
03208            }
03209            /* TODO: Load other EIMIL file. */
03210            fprintf(stderr, "Inherit %s\n", uaddr);
03211            free(uaddr);
03212        } else {
03213            return 0;
03214        }
03215     }
03216     return 1;
03217 }
03218 
03219 static int
03220 EIMIL_interface_element_parser(
03221     EIMIL_data *ped,
03222     EIMIL_attrs *patr,
03223     enum EIMIL_TAG_TYPE type,
03224     UTF8 *pchars,
03225     void **pprivate
03226 )
03227 {
03228     /* Do nothing specially. */
03229     return 1;
03230 }
03231 
03232 /***************************************
03233       Engine specific interface
03234 ***************************************/
03235 
03236 static int num_engines;
03237 static EIMIL_engine_table *pengines;
03238 
03239 static void
03240 EIMIL_free_engine()
03241 {
03242     int i;
03243     EIMIL_engine_table *p = pengines;
03244     for (i = 0; ; ++i) {
03245         if (i == num_engines) break;
03246         free (p->classname);
03247         free (p->uri);
03248         ++p;
03249     }
03250 
03251     free (pengines);
03252 
03253     /* reset */
03254     pengines = NULL;
03255     num_engines = 0;
03256 }
03257 
03258 static EIMIL_engine_table*
03259 EIMIL_get_engine(
03260     const UTF8 *classname
03261 )
03262 {
03263     int i;
03264     EIMIL_engine_table *p = pengines;
03265 
03266     for (i = 0;; i++) {
03267        if (i == num_engines) return NULL;
03268        if (strcmp(classname, p->classname) == 0) break;
03269        p++;
03270     }
03271 
03272     return p;
03273 }
03274 
03275 int
03276 EIMIL_register_engine(
03277     const UTF8 *classname,
03278     EIMIL_element_template *pet,
03279     EIMIL_engine_handler handler,
03280     EIMIL_engine_execute_handler execute_handler,
03281     const UTF8 *uri
03282 )
03283 {
03284     EIMIL_engine_table *p;
03285     p = EIMIL_get_engine(classname);
03286     if (!p) {
03287        p = (EIMIL_engine_table*) realloc(pengines,
03288                                      sizeof(EIMIL_engine_table)
03289                                      * (num_engines + 1));
03290        if (!p) return 0;
03291        pengines = p;
03292        p += num_engines;
03293        p->classname = strdup(classname);
03294        if (!p->classname) return 0;
03295        p->uri = strdup(uri);
03296        if (!p->uri) {
03297            free(p->classname);
03298            return 0;
03299        }
03300        num_engines++;
03301     } else {
03302        if (p->uri) free(p->uri);
03303        p->uri = strdup(uri);
03304        if (!p->uri) {
03305            free(p->classname);
03306            return 0;
03307        }
03308     }
03309 
03310     p->execute_handler = execute_handler;
03311     p->handler = handler;
03312     p->pet = pet;
03313 
03314     return 1;
03315 }
03316 
03317 static int
03318 EIMIL_engine_element_parser(
03319     EIMIL_data *ped,
03320     EIMIL_attrs *patr,
03321     enum EIMIL_TAG_TYPE type,
03322     UTF8 *pchars,
03323     void **pprivate
03324 )
03325 {
03326     if (type == EIMIL_START_TAG) {
03327        UTF8 *ustr;
03328        void **pengine_context;
03329        EIMIL_engine_table *pt;
03330        EIMIL_engine *pe;
03331        EIMIL_parser_state* pps = &ped->pcommon->ps;
03332        EIMIL_cdata *pc = ped->pcommon;
03333 
03334        for (;patr->name;patr++) {
03335            if (strcmp(patr->name, "class") == 0) {
03336               if (!EIMIL_get_attr_cdata(patr->val, &ustr)) {
03337                   EIMIL_set_error_pt(ped, NULL, "Invalid class name in `class'");
03338                   return 0;
03339               }
03340               pt = EIMIL_get_engine(ustr);
03341               if (!pt) {
03342                   EIMIL_set_error_pt(ped, NULL,
03343                                    "Class:%s does not exist.",
03344                                    ustr);
03345                   free(ustr);
03346                   return 0;
03347               }
03348               free(ustr);
03349            } else if (strcmp(patr->name, "name") == 0) {
03350               if (!EIMIL_get_attr_cdata(patr->val, &ustr)) {
03351                   EIMIL_set_error_pt(ped, NULL, "Invalid engine name in `name'");
03352                   return 0;
03353               }
03354               pe = (EIMIL_engine*) realloc(pc->pengine,
03355                                         sizeof(EIMIL_engine)
03356                                         * (pc->num_engines + 1));
03357               if (!pe) {
03358                   EIMIL_set_out_of_memory(ped);
03359                   return 0;
03360               }
03361               pc->pengine = pe;
03362               pe += pc->num_engines;
03363               pengine_context = (void**) realloc(ped->pengine_context,
03364                                              sizeof(void*)
03365                                              * (pc->num_engines + 1));
03366               if (!pengine_context) {
03367                   EIMIL_set_out_of_memory(ped);
03368                   return 0;
03369               }
03370               ped->pengine_context = pengine_context;
03371               pengine_context +=  pc->num_engines;
03372               pe->name = ustr;
03373               pe->private = NULL;
03374            } else {
03375               return 0;
03376            }
03377        }
03378 
03379        /* Set up the engine. */
03380        pe->ptable = pt;
03381        pe->private = (*pt->handler)(EIMIL_ENGINE_INSTANCIATE, ped, NULL, NULL);
03382 
03383        if (!pe->private) {
03384            EIMIL_set_out_of_memory(ped);
03385            return 0;
03386        }
03387        *pengine_context = (*pt->handler)(EIMIL_ENGINE_DUPLICATE, ped,
03388                                      pe->private, NULL);
03389        if (!(*pengine_context)) {
03390            EIMIL_set_out_of_memory(ped);
03391            return 0;
03392        }
03393        
03394        pc->num_engines++;
03395        pe->idx = pc->num_engines;
03396        EIMIL_SET_CURRENT_SUBELEMENT_TEMPLATE(pps, pt->pet);
03397        pps->current_uri = pt->uri;
03398        *pprivate = *pengine_context;
03399     }
03400     return 1;
03401 }
03402 
03403 /***************************************
03404          EIMIL handle
03405 ***************************************/
03406 
03407 EIMIL_data*
03408 EIMIL_make_handle_data(
03409     EIMIL_cdata *pbase
03410 )
03411 {
03412     EIMIL_data *ped;
03413     EIMIL_dictionary *pdic;
03414 
03415     ped = (EIMIL_data*) malloc(sizeof(EIMIL_data));
03416     if (!ped) return NULL;
03417     memset(ped, 0, sizeof(EIMIL_data));
03418 
03419     if (!pbase) {
03420        pbase = (EIMIL_cdata*) malloc(sizeof(EIMIL_cdata));
03421        if (!pbase) {
03422            free(ped);
03423            return NULL;
03424        }
03425        memset(pbase, 0, sizeof(EIMIL_cdata));
03426        INIT_SYNC_OBJECT(pbase->sync_object);
03427 
03428        /* 
03429           EIMIL_duplicate_handle() make its own dictionary,
03430           so it must not create a new dictionary here.
03431         */
03432        pdic = EIMIL_new_dictionary(0, 1);
03433        if (!pdic) {
03434            free(ped);
03435            return NULL;
03436        }
03437        ped->pdic = pdic;
03438     } else {
03439        ped->duplicated = 1;
03440     }
03441     ped->pcommon = pbase;
03442 
03443     ped->pcur_ev = ped->pqueue_ev = ped->queueslots;
03444 
03445     return ped;
03446 }
03447 
03448 /***************************************
03449          parser entry.
03450 ***************************************/
03451 
03452 int
03453 EIMIL_parse_start(
03454     EIMIL_data *ped
03455 )
03456 {
03457     ped->pcommon->ps.current_uri = EIMIL_xmlns_uri;
03458     return EIMIL_parse_element(ped, EIMIL_docroot, NULL, NULL, NULL, NULL);
03459 }
03460 
03461 /********************************************************************************
03462                             API
03463  ********************************************************************************/
03464 
03465 EIMIL_symbol*
03466 EIMIL_lookup_symbol(
03467     EIMIL_handle eh,
03468     CARD32BIT id
03469 )
03470 {
03471     EIMIL_data *ped = (EIMIL_data*) eh;
03472     return EIMIL_lookup_symbol_internal(ped->pdic, id);
03473 }
03474 
03475 int
03476 EIMIL_duplicate_handle(
03477     EIMIL_handle *peh,
03478     EIMIL_handle eh
03479 )
03480 {
03481     EIMIL_data *peds, *pedd;
03482     EIMIL_symbol *psym;
03483     EIMIL_dictionary *pdic;
03484     int i, n;
03485 
03486     peds = (EIMIL_data*) eh;
03487     pedd = EIMIL_make_handle_data(peds->pcommon);
03488     if (!pedd) return 0;
03489 
03490     /* copy handle data */
03491     *pedd = *peds;
03492 
03493     /* dupliacte dictionary */
03494     pdic = EIMIL_duplicate_dictionary(peds->pdic);
03495     if (!pdic) return 0;
03496     pedd->pdic = pdic;
03497 
03498     /* engine context */
03499     {
03500        void **pecs, **pecd;
03501        EIMIL_engine *pe;
03502        EIMIL_engine_table *pt;
03503 
03504        n = peds->pcommon->num_engines;
03505        pecs = pedd->pengine_context;
03506        pecd = (void**) malloc(sizeof(void*) * n);
03507        if (!pecd) return 0;
03508        for (i = 0; i < n; i++, pecs++, pecd++) {
03509            if (*pecs) {
03510               pe = peds->pcommon->pengine + i;
03511               pt = pe->ptable;
03512               *pecd = (*pt->handler)(EIMIL_ENGINE_DUPLICATE, peds,
03513                                    pe->private, *pecs);
03514               if (*pecd) return 0;
03515            } else {
03516               *pecd = NULL;
03517            }
03518        }
03519     }
03520 
03521     /* set psym_uidata. */
03522     if (peds->psym_uidata) {
03523        psym = EIMIL_lookup_symbol_internal(pdic, peds->psym_uidata->symbolid);
03524        ASSERT(psym);
03525        pedd->psym_uidata = psym;
03526     }
03527 
03528     /* set commitnotify_ops. */
03529     if (peds->commitnotify_numops > 0) {
03530        EIMIL_symbol **psyms_s, **psyms_d;
03531        psyms_d = (EIMIL_symbol**) malloc(sizeof(EIMIL_symbol*)
03532                                      * peds->commitnotify_numops);
03533        if (!psyms_d) return 0;
03534        pedd->commitnotify_ops = psyms_d;
03535        psyms_s = peds->commitnotify_ops;
03536        for (i = 0;
03537             peds->commitnotify_numops;
03538             i++, psyms_s++, psyms_d++) {
03539            *psyms_d = EIMIL_lookup_symbol_internal(pdic, psyms_s[0]->symbolid);
03540            ASSERT(*psyms_d);
03541        }
03542     }
03543 
03544     /* Reset journal state */
03545     pedd->current_journal_id = 0;
03546     pedd->pjst = NULL;
03547 
03548     /* Success */
03549 
03550     *peh = pedd;
03551                     
03552     return 1;
03553 }
03554 
03555 int
03556 EIMIL_free_handle(
03557     EIMIL_handle eh
03558 )
03559 {
03560     EIMIL_data *ped;
03561 
03562     if (!eh) return 0;
03563     ped = (EIMIL_data*) eh;
03564     EIMIL_journal_free(eh);
03565 
03566     if (!ped->duplicated) {
03567        EIMIL_cdata *pc = ped->pcommon;
03568        if (pc->ps.buf) free(pc->ps.buf);
03569         if (pc->ps.pxmlns) free(pc->ps.pxmlns);
03570        DESTROY_SYNC_OBJECT(pc->sync_object);
03571        free(pc);
03572     }
03573 
03574     EIMIL_free_dictionary(ped->pdic);
03575 
03576     free(ped);
03577 
03578     return 1;
03579 }
03580 
03581 int
03582 EIMIL_get_errormsg(
03583     EIMIL_handle eh,
03584     char **ppmsg
03585 )
03586 {
03587     EIMIL_data *ped;
03588 
03589     if (!eh) return 0;
03590     ped = (EIMIL_data*) eh;
03591 
03592     *ppmsg = ped->errstr;
03593 
03594     return 1;
03595 }
03596 
03597 static int
03598 EIMIL_init_predefined_symbol()
03599 {
03600     EIMIL_symbol *psym;
03601 
03602     pdic_internal = EIMIL_new_dictionary(11, 1);
03603     if (!pdic_internal) return 0;
03604 
03605     psym = register_symbol(pdic_internal, "nil",
03606                         EIMIL_CAT_VARIABLE,
03607                         EIMIL_SYMBOL_ID_NIL);
03608     if (!psym) return 0;
03609     psym->obj.v.type = EIMIL_TYPE_NIL;
03610     psym->obj.v.constp = 1;
03611     psym->obj.v.pv = NULL;
03612     pEIMIL_nil_sym = psym;
03613 
03614     psym = register_symbol(pdic_internal, "t",
03615                         EIMIL_CAT_VARIABLE,
03616                         EIMIL_SYMBOL_ID_T);
03617     if (!psym) return 0;
03618     psym->obj.v.type = EIMIL_TYPE_BOOL;
03619     psym->obj.v.constp = 1;
03620     psym->obj.v.pv = EIMIL_construct_bool(1);
03621     pEIMIL_t_sym = psym;
03622 
03623     psym = register_symbol(pdic_internal, "feedback",
03624                         EIMIL_CAT_PROPERTY,
03625                         EIMIL_SYMBOL_ID_FEEDBACK);
03626     if (!psym) return 0;
03627     psym->obj.p.type = EIMIL_TYPE_NUMBER;
03628     pEIMIL_feedback_sym = psym;
03629 
03630     psym = register_symbol(pdic_internal, "candidates",
03631                         EIMIL_CAT_PROPERTY,
03632                         EIMIL_SYMBOL_ID_CANDIDATES);
03633     psym->obj.p.type = EIMIL_TYPE_MTEXT;
03634     pEIMIL_candidates_sym = psym;
03635 
03636     return 1;
03637 }
03638 
03639 int
03640 EIMIL_initialize()
03641 {
03642 
03643     if (EIMIL_inited) return 1;
03644 
03645     /* initialize internal object */
03646     EIMIL_t_val.refcount = 1;
03647     EIMIL_t_val.type = EIMIL_TYPE_BOOL;
03648     EIMIL_t_val.v.bool_val = 1;
03649 
03650     if (!EIMIL_init_predefined_symbol()) return 0;
03651     if (!EIMILFile_init()) return 0;
03652     if (!PCE_init()) return 0;
03653 
03654     EIMIL_inited = 1;
03655     return 1;
03656 }
03657 
03658 int
03659 EIMIL_finalize()
03660 {
03661     if (!EIMIL_inited) return 1;
03662 
03663     EIMIL_free_dictionary_and_symbol(pdic_internal);
03664 
03665     EIMIL_free_engine(pengines);
03666 
03667     pEIMIL_nil_sym = NULL;
03668     pEIMIL_t_sym = NULL;
03669     pEIMIL_feedback_sym = NULL;
03670     pEIMIL_candidates_sym = NULL;
03671     pdic_internal = NULL;
03672     EIMIL_inited = 0;
03673 
03674     return 1;
03675 }
03676 
03677 void
03678 EIMIL_set_private(
03679     EIMIL_handle eh,
03680     void* private
03681 )
03682 {
03683     EIMIL_data *ped = (EIMIL_data*) eh;
03684     ped->private = private;
03685 }
03686 
03687 void*
03688 EIMIL_get_private(
03689     EIMIL_handle eh,
03690     void* private
03691 )
03692 {
03693     EIMIL_data *ped = (EIMIL_data*) eh;
03694     return ped->private;
03695 }
03696 
03697 /****************************************
03698            EIMIL service IF.
03699  ****************************************/
03700 
03701 int
03702 EIMIL_toggle_preedit(
03703     EIMIL_data *ped,
03704     int flag
03705 )
03706 {
03707     int r;
03708 
03709     if (!ped->pcommon->uiproc) return 0;
03710 
03711     if (flag)
03712        r = (*ped->pcommon->uiproc)(ped, ped->psym_uidata->obj.v.pv,
03713                                 EIMIL_ENABLE_PREEDIT);
03714     else
03715        r = (*ped->pcommon->uiproc)(ped, ped->psym_uidata->obj.v.pv,
03716                                 EIMIL_DISABLE_PREEDIT);
03717 
03718     return r;
03719 }
03720 
03721 int
03722 EIMIL_update_preedit(
03723     EIMIL_data *ped
03724 )
03725 {
03726     return (*ped->pcommon->uiproc)(ped, ped->psym_uidata->obj.v.pv,
03727                                EIMIL_UPDATE_PREEDIT);
03728 }
03729 
03730 int
03731 EIMIL_toggle_lookup_choice(
03732     EIMIL_data *ped,
03733     int flag
03734 )
03735 {
03736     int r;
03737 
03738     if (!ped->pcommon->uiproc) return 0;
03739 
03740     if (flag)
03741        r = (*ped->pcommon->uiproc)(ped, ped->psym_uidata->obj.v.pv,
03742                                 EIMIL_ENABLE_LOOKUP_CHOICE);
03743     else
03744        r = (*ped->pcommon->uiproc)(ped, ped->psym_uidata->obj.v.pv,
03745                                 EIMIL_DISABLE_LOOKUP_CHOICE);
03746 
03747     return r;
03748 }
03749 
03750 int
03751 EIMIL_update_lookup_choice(
03752     EIMIL_data *ped
03753 )
03754 {
03755     if (!ped->pcommon->uiproc) return 0;
03756 
03757     return (*ped->pcommon->uiproc)(ped, ped->psym_uidata->obj.v.pv,
03758                                EIMIL_UPDATE_LOOKUP_CHOICE);
03759 }
03760 
03761 int
03762 EIMIL_reply_event(
03763     EIMIL_data *ped,
03764     EIMIL_value *pv_event
03765 )
03766 {
03767     if (!ped->pcommon->evproc) return 0;
03768 
03769     ASSERT(pv_event->type == EIMIL_TYPE_EVENT);
03770 
03771     return (*ped->pcommon->evproc)(ped, &pv_event->v.event);
03772 }
03773 
03774 int
03775 EIMIL_queue_event(
03776     EIMIL_data *ped,
03777     EIMIL_value *pv_event
03778 )
03779 {
03780     EIMIL_value **pqn;
03781 
03782 
03783     if (ped->pqueue_ev == (ped->queueslots + EIMIL_EVENT_QUEUESIZE - 1))
03784        pqn = ped->queueslots;
03785     else
03786        pqn = ped->pqueue_ev + 1;
03787 
03788     if (pqn == ped->pcur_ev) return 0;
03789 
03790     *ped->pqueue_ev = pv_event;
03791     ped->pqueue_ev = pqn;
03792     EIMIL_ADDREF(*pv_event);
03793 
03794     return 1;
03795 }
03796 
03797 EIMIL_value*
03798 EIMIL_next_event(
03799     EIMIL_data *ped
03800 )
03801 {
03802     EIMIL_value **pqn, *pev;
03803 
03804     if (ped->pcur_ev == ped->pqueue_ev) return NULL;
03805 
03806     if (ped->pcur_ev == (ped->queueslots + EIMIL_EVENT_QUEUESIZE - 1))
03807        pqn = ped->queueslots;
03808     else
03809        pqn = ped->pcur_ev + 1;
03810 
03811     pev = *ped->pcur_ev;
03812     ped->pcur_ev = pqn;
03813 
03814     if (pev) EIMIL_RMREF_WITHOUT_DESTRUCTION(*pev);
03815 
03816     return pev;
03817 }
03818 
03819 /****************************************
03820            EIMIL application IF.
03821  ****************************************/
03822 
03823 int
03824 EIMIL_register_handler(
03825     EIMIL_handle eh,
03826     EIMIL_EVENT_PROC evproc,
03827     EIMIL_UICHANGE_PROC uiproc,
03828     EIMIL_OPISSUE_PROC opproc
03829 )
03830 {
03831     EIMIL_data *ped = (EIMIL_data*) eh;
03832     EIMIL_cdata *pcommon = ped->pcommon;
03833 
03834     pcommon->evproc = evproc;
03835     pcommon->uiproc = uiproc;
03836     pcommon->opproc = opproc;
03837 
03838     return 1;
03839 }
03840 
03841 int
03842 EIMIL_send_event(
03843     EIMIL_handle eh,
03844     EIMIL_value *pv_event
03845 )
03846 {
03847     int i, n;
03848     EIMIL_data *ped = (EIMIL_data*) eh;
03849     EIMIL_cdata *pcommon = ped->pcommon;
03850     EIMIL_engine *pe = pcommon->pengine;
03851     void **pengine_ctx;
03852 
03853     n = pcommon->num_engines;
03854     pengine_ctx = ped->pengine_context;
03855 
03856     /* if event, store event */
03857     if (pv_event) {
03858        ASSERT(pv_event->type == EIMIL_TYPE_EVENT);
03859        EIMIL_queue_event(ped, pv_event);
03860     }
03861 
03862     for (i = 0; i < n; i++) {
03863        if ((*pe->ptable->execute_handler)(*pengine_ctx)
03864            != EIMIL_ENGINE_STATUS_SKIPPED)
03865            break;
03866        pe++;
03867        pengine_ctx++;
03868     }
03869 
03870     if (pv_event) EIMIL_destruct_value(pv_event);
03871     return 1;
03872 }
03873 
03874 /* Local Variables: */
03875 /* c-file-style: "iiim-project" */
03876 /* End: */