Back to index

im-sdk  12.3.91
EIMILFile.c
Go to the documentation of this file.
00001 /*
00002   EIMILFile.c
00003 */
00004 
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <string.h>
00008 
00009 #include <sys/types.h>
00010 #include <sys/stat.h>
00011 
00012 #include <EIMIL.h>
00013 #include "EIMILint.h"
00014 
00015 #ifndef MAXPATHLEN
00016 #define MAXPATHLEN 1024
00017 #endif
00018 
00019 #define EIMIL_CLASS_SEPARATOR '.'
00020 #define EIMIL_DIR_SEPARATOR '/'
00021 
00022 static char EIMIL_default_filename[] = "default.xml";
00023 
00024 typedef struct EIMIL_class {
00025     unsigned char *classname;
00026     unsigned char *topdir;
00027 } EIMIL_class;
00028 typedef struct EIMIL_classlist {
00029     int num;
00030     EIMIL_class *pclasses;
00031 } EIMIL_classlist;
00032 
00033 typedef struct EIMIL_file {
00034     unsigned char *pathname;
00035     CARD32BIT symbolid;
00036     unsigned char *classname;
00037 } EIMIL_file;
00038 typedef struct EIMIL_filelist {
00039     int num;
00040     EIMIL_file *pfiles;
00041 } EIMIL_filelist;
00042 
00043 static THREAD_SYNC_OBJECT clsstg;
00044 static EIMIL_classlist classlist;
00045 static EIMIL_filelist filelist;
00046 #define LOCK_CLASSLIST LOCK_SYNC_OBJECT(clsstg)
00047 #define UNLOCK_CLASSLIST UNLOCK_SYNC_OBJECT(clsstg)
00048 
00049 static int
00050 normalize_document(
00051     EIMIL_data* ped,
00052     Ebyte *pdoc,
00053     int len
00054 )
00055 {
00056     unsigned char *p, *pcst, *pend;
00057     pend = pdoc + len;
00058 
00059     /* TODO:when code conversion is required,
00060        implement it here. */
00061 
00062     /* strip comment */
00063     for (p = pdoc; p < pend; ) {
00064        if ((p = memchr(p, '<', len))
00065            && ((pend - p) > 4)) {
00066            pcst = p;
00067            p++;
00068            if ((p[0] == '!')
00069               && (p[1] == '-')
00070               && (p[2]== '-')) {
00071               p += 3;
00072               len = pend - p;
00073               for (;;) {
00074                   if ((p = memchr(p, '-', len)) != NULL) {
00075                      p++;
00076                      if (*p != '-') continue;
00077                      p++;
00078                      if (*p != '>') goto comment_error;
00079                      p++;
00080                      /* remove comment */
00081                      while(pcst < p) *pcst++ = ' ';
00082                      break;
00083                   }else{
00084                      goto comment_error;
00085                   }
00086                   len = pend - p;
00087               }
00088            }
00089        }else{
00090            break;
00091        }
00092        len = pend - p;
00093     }
00094 
00095     return 1;
00096 
00097 comment_error:
00098     EIMIL_set_error(ped, "Invalid comment.");
00099     return 0;
00100 }
00101 
00102 static int
00103 load_file(
00104     const char *filename,
00105     EIMIL_data *ped
00106 )
00107 {
00108     EIMIL_parser_state* pps = &ped->pcommon->ps;
00109     int size;
00110     unsigned char *p;
00111     FILE *fp;
00112     struct stat st;
00113 
00114     if (!filename) return 0;
00115     if (stat(filename, &st) != 0) return 0;
00116     size = st.st_size;
00117     p = (unsigned char*) malloc(sizeof(unsigned char) * size);
00118     if (!p) {
00119        EIMIL_set_out_of_memory(ped);
00120        return 0;
00121     }
00122     fp = fopen(filename, "r");
00123     if ((!fp)
00124        || (fread(p, 1, size, fp) != size)) {
00125        EIMIL_set_error(ped, "Fail to read file:%s", filename);
00126        if (fp) fclose(fp);
00127        free(p);
00128        return 0;
00129     }
00130     pps->buf = p;
00131 
00132     normalize_document(ped, p, size);
00133 
00134     pps->start = p;
00135     pps->end = p + size;
00136     pps->current = p; 
00137     pps->lineno = 1;
00138     ped->errstr[0] = '\0';
00139 
00140     fclose(fp);
00141 
00142     return 1;
00143 }
00144 
00145 int
00146 EIMIL_register_class(
00147     unsigned char *classname,
00148     unsigned char *dirname
00149 )
00150 {
00151     int i, n, len;
00152     EIMIL_class *pec;
00153 
00154     LOCK_CLASSLIST;
00155     n = classlist.num;
00156     pec = classlist.pclasses;
00157     for (i = 0; i < n; i++, pec++) {
00158        if (strcmp(pec->classname, classname) == 0) break;
00159     }
00160     if (i == n) {
00161        pec = classlist.pclasses;
00162        pec = (EIMIL_class*) realloc(pec, sizeof(EIMIL_class) * (n + 1));
00163        if (!pec) return 0;
00164        classlist.pclasses = pec;
00165 
00166        /*
00167          longer classname takes higher order.
00168          Should we apply more efficient algorithm?
00169        */
00170        len = strlen(classname);
00171        for (i = 0;i < n;i++) {
00172            if (len > strlen(pec->classname)) break;
00173        }
00174        if (i < n) memmove(pec + 1, pec, sizeof(EIMIL_class));
00175        pec->topdir = NULL;
00176        pec->classname = strdup(classname);
00177        if (!pec->classname) return 0;
00178        classlist.num++;
00179     }
00180     if (pec->topdir) free(pec->topdir);
00181     pec->topdir = strdup(dirname);
00182     if (!pec->topdir) return 0;
00183     UNLOCK_CLASSLIST;
00184 
00185     return 1;
00186 }
00187 
00188 static int match_classname(unsigned char *cst, const unsigned char *csn,
00189                         unsigned char **unmatched)
00190 {
00191        for (;;) {
00192               if (!*cst) {
00193                      *unmatched = (unsigned char*)csn;
00194                      return 1;
00195               }
00196               if (*cst != *csn) {
00197                      *unmatched = NULL;
00198                      return 0;
00199               }
00200               cst++;
00201               csn++;
00202        }
00203        return 0;
00204 }
00205 
00206 static int
00207 find_file(
00208     unsigned char *basedir,
00209     const unsigned char *unmatched,
00210     const unsigned char *name,
00211     unsigned char *buf,
00212     int bufsize
00213 )
00214 {
00215     struct stat st;
00216     unsigned char *p;
00217     int totlen, baselen;
00218 
00219     p = buf;
00220 
00221     baselen = strlen(basedir);
00222     totlen = baselen + 1 + strlen(unmatched) + 1;
00223     if (name)
00224        totlen += strlen(name);
00225     else
00226        totlen += sizeof(EIMIL_default_filename);
00227 
00228     if (totlen > bufsize) return 0;
00229 
00230     strcpy(p, basedir);
00231     p += baselen;
00232     while (*unmatched) {
00233        if (*unmatched == EIMIL_CLASS_SEPARATOR)
00234            *p = EIMIL_DIR_SEPARATOR;
00235        else
00236            *p = *unmatched;
00237        unmatched++;
00238        p++;
00239     }
00240     *p++ = '/';
00241     if (name)
00242        strcpy(p, name);
00243     else
00244        strcpy(p, EIMIL_default_filename);
00245 
00246     if (stat(buf, &st) != 0) return 0;
00247 
00248     return 1;
00249 }
00250 
00251 unsigned char*
00252 EIMIL_find_file(
00253     const unsigned char *classname,
00254     const unsigned char *name
00255 )
00256 {
00257     int i, n;
00258     unsigned char buf[MAXPATHLEN];
00259     unsigned char *unmatched;
00260     EIMIL_class *pec;
00261 
00262     LOCK_CLASSLIST;
00263     n = classlist.num;
00264     pec = classlist.pclasses;
00265     for (i = 0;i < n;i++, pec++) {
00266        if ((match_classname(pec->classname, classname, &unmatched))
00267            && (find_file(pec->topdir, unmatched, name, buf, sizeof(buf)))) {
00268            UNLOCK_CLASSLIST;
00269            return strdup(buf);
00270        }
00271     }
00272     UNLOCK_CLASSLIST;
00273 
00274     return NULL;
00275 }
00276 
00277 int
00278 EIMIL_enumerate_class(
00279     unsigned char *classname
00280 )
00281 {
00282     return -1;
00283 }
00284 
00285 int
00286 EIMIL_file_symbolid(
00287     unsigned char *classname,
00288     unsigned char *name
00289 )
00290 {
00291     return -1;
00292 }
00293 
00294 int
00295 EIMIL_parse_file(
00296     EIMIL_handle *peh,
00297     const unsigned char *filename
00298 )
00299 {
00300     int ret;
00301     EIMIL_data *ped;
00302     EIMIL_parser_state *pps;
00303 
00304     ped = EIMIL_make_handle_data(NULL);
00305     if (!ped) return 0;
00306 
00307     pps = &ped->pcommon->ps;
00308 
00309     if (!load_file(filename, ped)) return 0;
00310 
00311     ret = EIMIL_parse_start(ped);
00312 
00313     free(pps->buf);
00314     pps->buf = NULL;
00315 
00316     *peh = ped;
00317 
00318     return ret;
00319 }
00320 
00321 int
00322 EIMILFile_init()
00323 {
00324     INIT_SYNC_OBJECT(clsstg);
00325     return 1;
00326 }
00327 
00328 /* Local Variables: */
00329 /* c-file-style: "iiim-project" */
00330 /* End: */