/* EIMILFile.c */ #include #include #include #include #include #include #include "EIMILint.h" #ifndef MAXPATHLEN #define MAXPATHLEN 1024 #endif #define EIMIL_CLASS_SEPARATOR '.' #define EIMIL_DIR_SEPARATOR '/' static char EIMIL_default_filename[] = "default.xml"; typedef struct EIMIL_class { unsigned char *classname; unsigned char *topdir; } EIMIL_class; typedef struct EIMIL_classlist { int num; EIMIL_class *pclasses; } EIMIL_classlist; typedef struct EIMIL_file { unsigned char *pathname; CARD32BIT symbolid; unsigned char *classname; } EIMIL_file; typedef struct EIMIL_filelist { int num; EIMIL_file *pfiles; } EIMIL_filelist; static THREAD_SYNC_OBJECT clsstg; static EIMIL_classlist classlist; static EIMIL_filelist filelist; #define LOCK_CLASSLIST LOCK_SYNC_OBJECT(clsstg) #define UNLOCK_CLASSLIST UNLOCK_SYNC_OBJECT(clsstg) static int normalize_document( EIMIL_data* ped, Ebyte *pdoc, int len ) { unsigned char *p, *pcst, *pend; pend = pdoc + len; /* TODO:when code conversion is required, implement it here. */ /* strip comment */ for (p = pdoc; p < pend; ) { if ((p = memchr(p, '<', len)) && ((pend - p) > 4)) { pcst = p; p++; if ((p[0] == '!') && (p[1] == '-') && (p[2]== '-')) { p += 3; len = pend - p; for (;;) { if ((p = memchr(p, '-', len)) != NULL) { p++; if (*p != '-') continue; p++; if (*p != '>') goto comment_error; p++; /* remove comment */ while(pcst < p) *pcst++ = ' '; break; }else{ goto comment_error; } len = pend - p; } } }else{ break; } len = pend - p; } return 1; comment_error: EIMIL_set_error(ped, "Invalid comment."); return 0; } static int load_file( const char *filename, EIMIL_data *ped ) { EIMIL_parser_state* pps = &ped->pcommon->ps; int size; unsigned char *p; FILE *fp; struct stat st; if (!filename) return 0; if (stat(filename, &st) != 0) return 0; size = st.st_size; p = (unsigned char*) malloc(sizeof(unsigned char) * size); if (!p) { EIMIL_set_out_of_memory(ped); return 0; } fp = fopen(filename, "r"); if ((!fp) || (fread(p, 1, size, fp) != size)) { EIMIL_set_error(ped, "Fail to read file:%s", filename); if (fp) fclose(fp); free(p); return 0; } pps->buf = p; normalize_document(ped, p, size); pps->start = p; pps->end = p + size; pps->current = p; pps->lineno = 1; ped->errstr[0] = '\0'; fclose(fp); return 1; } int EIMIL_register_class( unsigned char *classname, unsigned char *dirname ) { int i, n, len; EIMIL_class *pec; LOCK_CLASSLIST; n = classlist.num; pec = classlist.pclasses; for (i = 0; i < n; i++, pec++) { if (strcmp(pec->classname, classname) == 0) break; } if (i == n) { pec = classlist.pclasses; pec = (EIMIL_class*) realloc(pec, sizeof(EIMIL_class) * (n + 1)); if (!pec) return 0; classlist.pclasses = pec; /* longer classname takes higher order. Should we apply more efficient algorithm? */ len = strlen(classname); for (i = 0;i < n;i++) { if (len > strlen(pec->classname)) break; } if (i < n) memmove(pec + 1, pec, sizeof(EIMIL_class)); pec->topdir = NULL; pec->classname = strdup(classname); if (!pec->classname) return 0; classlist.num++; } if (pec->topdir) free(pec->topdir); pec->topdir = strdup(dirname); if (!pec->topdir) return 0; UNLOCK_CLASSLIST; return 1; } static int match_classname(unsigned char *cst, const unsigned char *csn, unsigned char **unmatched) { for (;;) { if (!*cst) { *unmatched = (unsigned char*)csn; return 1; } if (*cst != *csn) { *unmatched = NULL; return 0; } cst++; csn++; } return 0; } static int find_file( unsigned char *basedir, const unsigned char *unmatched, const unsigned char *name, unsigned char *buf, int bufsize ) { struct stat st; unsigned char *p; int totlen, baselen; p = buf; baselen = strlen(basedir); totlen = baselen + 1 + strlen(unmatched) + 1; if (name) totlen += strlen(name); else totlen += sizeof(EIMIL_default_filename); if (totlen > bufsize) return 0; strcpy(p, basedir); p += baselen; while (*unmatched) { if (*unmatched == EIMIL_CLASS_SEPARATOR) *p = EIMIL_DIR_SEPARATOR; else *p = *unmatched; unmatched++; p++; } *p++ = '/'; if (name) strcpy(p, name); else strcpy(p, EIMIL_default_filename); if (stat(buf, &st) != 0) return 0; return 1; } unsigned char* EIMIL_find_file( const unsigned char *classname, const unsigned char *name ) { int i, n; unsigned char buf[MAXPATHLEN]; unsigned char *unmatched; EIMIL_class *pec; LOCK_CLASSLIST; n = classlist.num; pec = classlist.pclasses; for (i = 0;i < n;i++, pec++) { if ((match_classname(pec->classname, classname, &unmatched)) && (find_file(pec->topdir, unmatched, name, buf, sizeof(buf)))) { UNLOCK_CLASSLIST; return strdup(buf); } } UNLOCK_CLASSLIST; return NULL; } int EIMIL_enumerate_class( unsigned char *classname ) { return -1; } int EIMIL_file_symbolid( unsigned char *classname, unsigned char *name ) { return -1; } int EIMIL_parse_file( EIMIL_handle *peh, const unsigned char *filename ) { int ret; EIMIL_data *ped; EIMIL_parser_state *pps; ped = EIMIL_make_handle_data(NULL); if (!ped) return 0; pps = &ped->pcommon->ps; if (!load_file(filename, ped)) return 0; ret = EIMIL_parse_start(ped); free(pps->buf); pps->buf = NULL; *peh = ped; return ret; } int EIMILFile_init() { INIT_SYNC_OBJECT(clsstg); return 1; } /* Local Variables: */ /* c-file-style: "iiim-project" */ /* End: */