Back to index

texmacs  1.0.7.15
otl_conf.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/otl_conf.c,v 1.8 2008/05/18 12:05:22 chofchof Exp $
00002     
00003     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
00004 
00005     Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
00006     the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
00007     
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012     
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017     
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00021 */
00022 
00023 #ifdef  _HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif /* _HAVE_CONFIG_H */
00026 
00027 #include "system.h"
00028 #include "error.h"
00029 #include "mem.h"
00030 #include "dpxfile.h"
00031 #include "dpxutil.h"
00032 
00033 #include "pdfobj.h"
00034 #include "pdfparse.h"
00035 
00036 #include "agl.h"
00037 
00038 #include "otl_conf.h"
00039 
00040 #define VERBOSE_LEVEL_MIN 0
00041 static int verbose = 0;
00042 void
00043 otl_conf_set_verbose (void)
00044 {
00045   verbose++;
00046 }
00047 
00048 static pdf_obj *
00049 parse_uc_coverage (pdf_obj *gclass, char **pp, char *endptr)
00050 {
00051   pdf_obj *coverage;
00052   pdf_obj *value;
00053   long     ucv = 0;
00054   char    *glyphname, *glyphclass;
00055 
00056   if (*pp + 1 >= endptr)
00057     return NULL;
00058 
00059   if (**pp == '[')
00060     (*pp)++;
00061 
00062   coverage = pdf_new_array();
00063 
00064   while (*pp < endptr) {
00065     skip_white(pp, endptr);
00066     switch (**pp) {
00067     case ']': case ';':
00068       (*pp)++;
00069       return coverage;
00070       break;
00071     case ',':
00072       (*pp)++;
00073       break;
00074     case '@':
00075       {
00076        pdf_obj *cvalues;
00077        int      i, size;
00078 
00079        (*pp)++;
00080        glyphclass = parse_c_ident(pp, endptr);
00081        cvalues = pdf_lookup_dict(gclass, glyphclass);
00082        if (!cvalues)
00083          ERROR("%s not defined...", glyphclass);
00084        size    = pdf_array_length(cvalues);
00085        for (i = 0; i < size; i++) {
00086          pdf_add_array(coverage,
00087                      pdf_link_obj(pdf_get_array(cvalues, i)));
00088        }
00089       }
00090       break;
00091     default:
00092       glyphname  = parse_c_ident(pp, endptr);
00093       if (!glyphname)
00094        ERROR("Invalid Unicode character specified.");
00095 
00096       skip_white(pp, endptr);
00097       if (*pp + 1 < endptr && **pp == '-') {
00098        value = pdf_new_array();
00099 
00100        if (agl_get_unicodes(glyphname, &ucv, 1) != 1)
00101          ERROR("Invalid Unicode char: %s", glyphname);
00102        pdf_add_array(value, pdf_new_number(ucv));
00103        RELEASE(glyphname);
00104 
00105        (*pp)++; skip_white(pp, endptr);
00106        glyphname = parse_c_ident(pp, endptr);
00107        if (!glyphname)
00108          ERROR("Invalid Unicode char: %s", glyphname);
00109        if (agl_get_unicodes(glyphname, &ucv, 1) != 1)
00110          ERROR("Invalid Unicode char: %s", glyphname);
00111        pdf_add_array(value, pdf_new_number(ucv));
00112        RELEASE(glyphname);
00113 
00114       } else {
00115        if (agl_get_unicodes(glyphname, &ucv, 1) != 1)
00116          ERROR("Invalid Unicode char: %s", glyphname);
00117        value = pdf_new_number(ucv);
00118        RELEASE(glyphname);
00119       }
00120       pdf_add_array(coverage, value);
00121       break;
00122     }
00123     skip_white(pp, endptr);
00124   }
00125 
00126   return coverage;
00127 }
00128 
00129 static pdf_obj *parse_block (pdf_obj *gclass, char **pp, char *endptr);
00130 
00131 static void
00132 add_rule (pdf_obj *rule, pdf_obj *gclass,
00133          char *first, char *second, char *suffix)
00134 {
00135   pdf_obj *glyph1, *glyph2;
00136 #define MAX_UNICODES 16
00137   long     unicodes[MAX_UNICODES];
00138   int      i, n_unicodes;
00139 
00140   if (first[0] == '@') {
00141     glyph1 = pdf_lookup_dict(gclass, &first[1]);
00142     if (!glyph1) {
00143       WARN("No glyph class \"%s\" found.", &first[1]);
00144       return;
00145     }
00146     pdf_link_obj(glyph1);
00147 
00148     if (verbose > VERBOSE_LEVEL_MIN) {
00149       MESG("otl_conf>> Output glyph sequence: %s\n", first);
00150     }
00151 
00152   } else {
00153     n_unicodes = agl_get_unicodes(first, unicodes, MAX_UNICODES);
00154     if (n_unicodes < 1) {
00155       WARN("Failed to convert glyph \"%s\" to Unicode sequence.",
00156           first);
00157       return;
00158     }
00159     glyph1 = pdf_new_array();
00160 
00161     if (verbose > VERBOSE_LEVEL_MIN) {
00162       MESG("otl_conf>> Output glyph sequence: %s ->", first);
00163     }
00164 
00165     for (i = 0; i < n_unicodes; i++) {
00166       pdf_add_array(glyph1, pdf_new_number(unicodes[i]));
00167 
00168       if (verbose > VERBOSE_LEVEL_MIN) {
00169        if (unicodes[i] < 0x10000) {
00170          MESG(" U+%04X", unicodes[i]);
00171        } else {
00172          MESG(" U+%06X", unicodes[i]);
00173        }
00174       }
00175     }
00176 
00177     if (verbose > VERBOSE_LEVEL_MIN) {
00178       MESG("\n");
00179     }
00180   }
00181 
00182   if (second[0] == '@') {
00183     glyph2 = pdf_lookup_dict(gclass, &second[1]);
00184     if (!glyph2) {
00185       WARN("No glyph class \"%s\" found.", &second[1]);
00186       return;
00187     }
00188     pdf_link_obj(glyph2);
00189 
00190     if (verbose > VERBOSE_LEVEL_MIN) {
00191       MESG("otl_conf>> Input glyph sequence: %s (%s)\n", second, suffix);
00192     }
00193 
00194   } else {
00195     n_unicodes = agl_get_unicodes(second, unicodes, 16);
00196     if (n_unicodes < 1) {
00197       WARN("Failed to convert glyph \"%s\" to Unicode sequence.",
00198           second);
00199       return;
00200     }
00201 
00202     if (verbose > VERBOSE_LEVEL_MIN) {
00203       if (suffix)
00204        MESG("otl_conf>> Input glyph sequence: %s.%s ->", second, suffix);
00205       else
00206        MESG("otl_conf>> Input glyph sequence: %s ->", second);
00207     }
00208 
00209     glyph2 = pdf_new_array();
00210     for (i = 0; i < n_unicodes; i++) {
00211       pdf_add_array(glyph2, pdf_new_number(unicodes[i]));
00212 
00213       if (verbose > VERBOSE_LEVEL_MIN) {
00214        if (unicodes[i] < 0x10000) {
00215          MESG(" U+%04X", unicodes[i]);
00216        } else {
00217          MESG(" U+%06X", unicodes[i]);
00218        }
00219       }
00220     }
00221     if (verbose > VERBOSE_LEVEL_MIN) {
00222       MESG(" (%s)\n", suffix);
00223     }
00224   }
00225 
00226   /* OK */
00227   if (suffix) {
00228     pdf_add_array(rule, pdf_new_string(suffix, strlen(suffix)));
00229   } else {
00230     pdf_add_array(rule, pdf_new_null());
00231   }
00232   pdf_add_array(rule, glyph1);
00233   pdf_add_array(rule, glyph2);
00234 }
00235 
00236 static pdf_obj *
00237 parse_substrule (pdf_obj *gclass, char **pp, char *endptr)
00238 {
00239   pdf_obj *substrule;
00240   char    *token;
00241 
00242   skip_white(pp, endptr);
00243   if (*pp < endptr && **pp == '{')
00244     (*pp)++;
00245 
00246   skip_white(pp, endptr);
00247   if (*pp >= endptr)
00248     return NULL;
00249 
00250   substrule = pdf_new_array();
00251   while (*pp < endptr && **pp != '}') {
00252     skip_white(pp, endptr);
00253     if (*pp >= endptr)
00254       break;
00255 
00256     if (**pp == '#') {
00257       while (*pp < endptr) {
00258        if (**pp == '\r' || **pp == '\n') {
00259          (*pp)++;
00260          break;
00261        }
00262        (*pp)++;
00263       }
00264       continue;
00265     } else if (**pp == ';') {
00266       (*pp)++;
00267       continue;
00268     }
00269 
00270     skip_white(pp, endptr);
00271     token = parse_c_ident(pp, endptr);
00272     if (!token)
00273       break;
00274 
00275     if (!strcmp(token, "assign") || !strcmp(token, "substitute")) {
00276       char *tmp, *first, *second, *suffix;
00277 
00278       skip_white(pp, endptr);
00279 
00280       first = parse_c_ident(pp, endptr);
00281       if (!first)
00282        ERROR("Syntax error (1)");
00283 
00284       skip_white(pp, endptr);
00285       tmp = parse_c_ident(pp, endptr);
00286       if (strcmp(tmp, "by") && strcmp(tmp, "to"))
00287        ERROR("Syntax error (2): %s", *pp);
00288 
00289       skip_white(pp, endptr);
00290       second = parse_c_ident(pp, endptr); /* allows @ */
00291       if (!second)
00292        ERROR("Syntax error (3)");
00293 
00294       /* (assign|substitute) tag dst src */
00295       pdf_add_array(substrule, pdf_new_name(token));
00296       if (*pp + 1 < endptr && **pp == '.') {
00297        (*pp)++;
00298        suffix = parse_c_ident(pp, endptr);
00299       } else {
00300        suffix = NULL;
00301       }
00302       add_rule(substrule, gclass, first, second, suffix);
00303 
00304       RELEASE(first);
00305       RELEASE(tmp);
00306       RELEASE(second);
00307       if (suffix)
00308        RELEASE(suffix);
00309     } else {
00310       ERROR("Unkown command %s.", token);
00311     }
00312     RELEASE(token);
00313     skip_white(pp, endptr);
00314   }
00315 
00316   if (*pp < endptr && **pp == '}')
00317     (*pp)++;
00318   return substrule;
00319 }
00320 
00321 static pdf_obj *
00322 parse_block (pdf_obj *gclass, char **pp, char *endptr)
00323 {
00324   pdf_obj *rule;
00325   char    *token, *tmp;
00326 
00327   skip_white(pp, endptr);
00328   if (*pp < endptr && **pp == '{')
00329     (*pp)++;
00330 
00331   skip_white(pp, endptr);
00332   if (*pp >= endptr)
00333     return NULL;
00334 
00335   rule   = pdf_new_dict();
00336   while (*pp < endptr && **pp != '}') {
00337     skip_white(pp, endptr);
00338     if (*pp >= endptr)
00339       break;
00340     if (**pp == '#') {
00341       while (*pp < endptr) {
00342        if (**pp == '\r' || **pp == '\n') {
00343          (*pp)++;
00344          break;
00345        }
00346        (*pp)++;
00347       }
00348       continue;
00349     } else if (**pp == ';') {
00350       (*pp)++;
00351       continue;
00352     }
00353 
00354     skip_white(pp, endptr);
00355     token = parse_c_ident(pp, endptr);
00356     if (!token)
00357       break;
00358 
00359     if (!strcmp(token, "script") ||
00360        !strcmp(token, "language")) {
00361       int  i, len;
00362 
00363       skip_white(pp, endptr);
00364       len = 0;
00365       while (*pp + len < endptr && *(*pp + len) != ';') {
00366        len++;
00367       }
00368       if (len > 0) {
00369        tmp = NEW(len+1, char);
00370        memset(tmp, 0, len+1);
00371        for (i = 0; i < len; i++) {
00372          if (!isspace(**pp))
00373            tmp[i] = **pp;
00374          (*pp)++;
00375        }
00376        pdf_add_dict(rule,
00377                    pdf_new_name(token),
00378                    pdf_new_string(tmp, strlen(tmp)));
00379 
00380        if (verbose > VERBOSE_LEVEL_MIN) {
00381          MESG("otl_conf>> Current %s set to \"%s\"\n", token, tmp);
00382        }
00383 
00384        RELEASE(tmp);
00385       }
00386     } else if (!strcmp(token, "option")) {
00387       pdf_obj *opt_dict, *opt_rule;
00388 
00389       opt_dict = pdf_lookup_dict(rule, "option");
00390       if (!opt_dict) {
00391        opt_dict = pdf_new_dict();
00392        pdf_add_dict(rule,
00393                    pdf_new_name("option"), opt_dict);
00394       }
00395 
00396       skip_white(pp, endptr);
00397       tmp = parse_c_ident(pp, endptr);
00398 
00399       if (verbose > VERBOSE_LEVEL_MIN) {
00400        MESG("otl_conf>> Reading option \"%s\"\n", tmp);
00401       }
00402 
00403       skip_white(pp, endptr);
00404       opt_rule = parse_block(gclass, pp, endptr);
00405       pdf_add_dict(opt_dict, pdf_new_name(tmp), opt_rule);
00406 
00407       RELEASE(tmp);
00408     } else if (!strcmp(token, "prefered") ||
00409               !strcmp(token, "required") ||
00410               !strcmp(token, "optional")) {
00411       pdf_obj *subst, *rule_block;
00412 
00413       if (verbose > VERBOSE_LEVEL_MIN) {
00414        MESG("otl_conf>> Reading block (%s)\n", token);
00415       }
00416 
00417       skip_white(pp, endptr);
00418       if (*pp >= endptr || **pp != '{')
00419        ERROR("Syntax error (1)");
00420 
00421       rule_block = parse_substrule(gclass, pp, endptr);
00422       subst = pdf_lookup_dict(rule, "rule");
00423       if (!subst) {
00424        subst = pdf_new_array();
00425        pdf_add_dict(rule, pdf_new_name("rule"), subst);
00426       }
00427       pdf_add_array(subst, pdf_new_number(token[0]));
00428       pdf_add_array(subst, rule_block);
00429     } else if (token[0] == '@') {
00430       pdf_obj *coverage;
00431 
00432       skip_white(pp, endptr);
00433       (*pp)++; /* = */
00434       skip_white(pp, endptr);
00435 
00436       if (verbose > VERBOSE_LEVEL_MIN) {
00437        MESG("otl_conf>> Glyph class \"%s\"\n", token);
00438       }
00439 
00440       coverage = parse_uc_coverage(gclass, pp, endptr);
00441       if (!coverage)
00442        ERROR("No valid Unicode characters...");
00443 
00444       pdf_add_dict(gclass,
00445                  pdf_new_name(&token[1]), coverage);
00446     }
00447     RELEASE(token);
00448     skip_white(pp, endptr);
00449   }
00450 
00451   if (*pp < endptr && **pp == '}')
00452     (*pp)++;
00453   return rule;
00454 }
00455 
00456 
00457 static pdf_obj *
00458 otl_read_conf (const char *conf_name)
00459 {
00460   pdf_obj *rule;
00461   pdf_obj *gclass;
00462   FILE    *fp;
00463   char    *filename, *wbuf, *p, *endptr;
00464   long     size, len;
00465 
00466   filename = NEW(strlen(conf_name)+strlen(".otl")+1, char);
00467   strcpy(filename, conf_name);
00468   strcat(filename, ".otl");
00469 
00470   fp = DPXFOPEN(filename, DPX_RES_TYPE_TEXT);
00471   if (!fp) {
00472     RELEASE(filename);
00473     return NULL;
00474   }
00475 
00476   size = file_size(fp);
00477   rewind(fp);
00478 
00479   if (verbose > VERBOSE_LEVEL_MIN) {
00480     MESG("\n");
00481     MESG("otl_conf>> Layout config. \"%s\" found: file=\"%s\" (%ld bytes)\n",
00482         conf_name, filename, size);
00483   }
00484   RELEASE(filename);
00485   if (size < 1)
00486     return NULL;
00487 
00488   wbuf = NEW(size, char);
00489   p = wbuf; endptr = p + size;
00490   while (size > 0 && p < endptr) {
00491     len = fread(p, sizeof(char), size, fp);
00492     p    += len;
00493     size -= len;
00494   }
00495   
00496   p      = wbuf;
00497   gclass = pdf_new_dict();
00498   rule   = parse_block(gclass, &p, endptr);
00499   pdf_release_obj(gclass);
00500 
00501   RELEASE(wbuf);
00502 
00503   return rule;
00504 }
00505 
00506 static pdf_obj *otl_confs = NULL;
00507 
00508 pdf_obj *
00509 otl_find_conf (const char *conf_name)
00510 {
00511   pdf_obj *rule;
00512   pdf_obj *script, *language;
00513   pdf_obj *options;
00514 
00515   return  NULL;
00516 
00517   if (otl_confs)
00518     rule = pdf_lookup_dict(otl_confs, conf_name);
00519   else {
00520     otl_confs = pdf_new_dict();
00521     rule = NULL;
00522   }
00523 
00524   if (!rule) {
00525     rule = otl_read_conf(conf_name);
00526     if (rule) {
00527       pdf_add_dict(otl_confs,
00528                  pdf_new_name(conf_name), rule);
00529       script   = pdf_lookup_dict(rule, "script");
00530       language = pdf_lookup_dict(rule, "language");
00531       options  = pdf_lookup_dict(rule, "option");
00532       if (!script) {
00533        script = pdf_new_string("*", 1);
00534        pdf_add_dict(rule,
00535                    pdf_new_name("script"),
00536                    script);
00537        WARN("Script unspecified in \"%s\"...", conf_name);
00538       }
00539       if (!language) {
00540        language = pdf_new_string("dflt", 4);
00541        pdf_add_dict(rule,
00542                    pdf_new_name("language"),
00543                    language);
00544        WARN("Language unspecified in \"%s\"...", conf_name);
00545       }
00546 
00547       if (options) {
00548        pdf_obj *optkeys, *opt, *key;
00549        long     i, num_opts;
00550 
00551        optkeys  = pdf_dict_keys(options);
00552        num_opts = pdf_array_length(optkeys);
00553        for (i = 0; i < num_opts; i++) {
00554          key = pdf_get_array(optkeys, i);
00555          opt = pdf_lookup_dict(options, pdf_name_value(key));
00556          if (!pdf_lookup_dict(opt, "script"))
00557            pdf_add_dict(opt,
00558                       pdf_new_name("script"),
00559                       pdf_link_obj(script));
00560          if (!pdf_lookup_dict(opt, "language"))
00561            pdf_add_dict(opt,
00562                       pdf_new_name("language"),
00563                       pdf_link_obj(language));
00564        }
00565        pdf_release_obj(optkeys);
00566       }
00567 
00568     }
00569   }
00570 
00571   return rule;
00572 }
00573 
00574 
00575 char *
00576 otl_conf_get_script (pdf_obj *conf)
00577 {
00578   pdf_obj *script;
00579 
00580   ASSERT(conf);
00581 
00582   script = pdf_lookup_dict(conf, "script");
00583 
00584   return pdf_string_value(script);
00585 }
00586 
00587 char *
00588 otl_conf_get_language (pdf_obj *conf)
00589 {
00590   pdf_obj *language;
00591 
00592   ASSERT(conf);
00593 
00594   language = pdf_lookup_dict(conf, "language");
00595 
00596   return pdf_string_value(language);
00597 }
00598 
00599 pdf_obj *
00600 otl_conf_get_rule (pdf_obj *conf)
00601 {
00602   ASSERT(conf);
00603   return pdf_lookup_dict(conf, "rule");
00604 }
00605 
00606 pdf_obj *
00607 otl_conf_find_opt (pdf_obj *conf, const char *opt_tag)
00608 {
00609   pdf_obj *opt_conf = NULL;
00610   pdf_obj *options;
00611 
00612   ASSERT(conf);
00613 
00614   options = pdf_lookup_dict(conf, "option");
00615   if (options && opt_tag)
00616     opt_conf = pdf_lookup_dict(options, opt_tag);
00617   else
00618     opt_conf = NULL;
00619 
00620   return opt_conf;
00621 }
00622 
00623 void
00624 otl_init_conf (void)
00625 {
00626   if (otl_confs)
00627     pdf_release_obj(otl_confs);
00628   otl_confs = pdf_new_dict();
00629 
00630   if (verbose > VERBOSE_LEVEL_MIN + 10) {
00631     pdf_release_obj(pdf_ref_obj(otl_confs));
00632   }
00633 }
00634 
00635 void
00636 otl_close_conf (void)
00637 {
00638   pdf_release_obj(otl_confs);
00639   otl_confs = NULL;
00640 }