Back to index

texmacs  1.0.7.15
otl_opt.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/otl_opt.c,v 1.3 2004/08/22 10:26:24 hirata 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 <stdlib.h>
00028 #include <string.h>
00029 #include <ctype.h>
00030 
00031 #include "system.h"
00032 #include "error.h"
00033 #include "mem.h"
00034 #include "mfileio.h"
00035 
00036 #include "otl_opt.h"
00037 
00038 struct bt_node {
00039   int    flag;
00040 
00041   struct bt_node *left;
00042   struct bt_node *right;
00043 
00044   char data[4];
00045 };
00046 
00047 #define FLAG_NOT (1 << 0)
00048 #define FLAG_AND (1 << 1)
00049 
00050 static int match_expr (struct bt_node *expr, const char *key);
00051 static int
00052 match_expr (struct bt_node *expr, const char *key)
00053 {
00054   int retval = 1;
00055   int i;
00056 
00057   if (expr) {
00058     if (!expr->left && !expr->right) {
00059       for (i = 0; i < 4; i++) {
00060        if (expr->data[i] != '?' &&
00061            expr->data[i] != key[i]) {
00062          retval = 0;
00063          break;
00064        }
00065       }
00066     } else {
00067       if (expr->left) {
00068        retval  = match_expr(expr->left, key);
00069       }
00070       if (expr->right) {
00071        if (retval && (expr->flag & FLAG_AND)) /* and */
00072          retval &= match_expr(expr->right, key);
00073        else if (!retval && !(expr->flag & FLAG_AND)) /* or */
00074          retval  = match_expr(expr->right, key);
00075       }
00076     }
00077     if (expr->flag & FLAG_NOT) /* not */
00078       retval = retval ? 0 : 1;
00079 
00080   }
00081 
00082   return retval;
00083 }
00084 
00085 static struct bt_node *
00086 bt_new_tree (void)
00087 {
00088   struct bt_node *expr;
00089 
00090   expr = NEW(1, struct bt_node);
00091   expr->flag  = 0;
00092   expr->left  = NULL;
00093   expr->right = NULL;
00094   memset(expr->data, 0, 4);
00095 
00096   return expr;
00097 }
00098 
00099 static void bt_release_tree (struct bt_node *tree);
00100 
00101 static void
00102 bt_release_tree (struct bt_node *tree)
00103 {
00104   if (tree) {
00105     if (tree->left)
00106       bt_release_tree(tree->left);
00107     if (tree->right)
00108       bt_release_tree(tree->right);
00109     RELEASE(tree);
00110   }
00111 }
00112 
00113 static struct bt_node *
00114 parse_expr (char **pp, char *endptr)
00115 {
00116   struct bt_node *root, *curr;
00117   
00118   if (*pp >= endptr)
00119     return NULL;
00120 
00121   root = curr = bt_new_tree();
00122   while (*pp < endptr) {
00123     switch (**pp) {
00124     case '!':
00125       if (curr->flag & 2)
00126         curr->flag &= ~FLAG_NOT;
00127       else
00128         curr->flag |=  FLAG_NOT;
00129       (*pp)++;
00130       break;
00131     case '(':
00132       (*pp)++;
00133       if (*pp < endptr) {
00134         struct bt_node *expr;
00135 
00136         expr = parse_expr(pp, endptr);
00137         if (!expr) {
00138             WARN("Syntax error: %s\n", *pp);
00139             return NULL;
00140         }
00141         if (**pp != ')') {
00142             WARN("Syntax error: Unbalanced ()\n");
00143             return NULL;
00144            }
00145         curr->left  = expr->left;
00146         curr->right = expr->right;
00147         memcpy(curr->data, expr->data, 4);
00148 
00149         RELEASE(expr);
00150       } else {
00151         WARN("Syntax error: Unbalanced ()\n");
00152         bt_release_tree(root);
00153         return NULL;
00154       }
00155       (*pp)++;
00156       break;
00157     case ')':
00158       return root;
00159       break;
00160     case '|': case '&':
00161       if (*pp >= endptr) {
00162         WARN("Syntax error: %s\n", *pp);
00163         bt_release_tree(root);
00164         return NULL;
00165       } else {
00166         struct bt_node *tmp;
00167 
00168         tmp        = bt_new_tree();
00169         tmp->left  = root;
00170         tmp->right = curr = bt_new_tree();
00171         if (**pp == '&')
00172           tmp->flag = 1;
00173         else
00174           tmp->flag = 0;
00175         root = tmp;
00176       }
00177       (*pp)++;
00178       break;
00179     case '*':
00180       memset(curr->data, '?', 4);
00181       (*pp)++;
00182       break;
00183     default:
00184       if (*pp + 4 <= endptr) {
00185         int i;
00186 
00187         for (i = 0; i < 4; i++) {
00188             if (**pp == ' '   || **pp == '?' ||
00189                 isalpha(**pp) || isdigit(**pp))
00190                 curr->data[i] = **pp;
00191             else if (**pp == '_')
00192                 curr->data[i] = ' ';
00193             else {
00194                 WARN("Invalid char in tag: %c\n", **pp);
00195                 bt_release_tree(root);
00196                 return NULL;
00197             }
00198             (*pp)++;
00199         }
00200       } else {
00201         WARN("Syntax error: %s\n", *pp);
00202         bt_release_tree(root);
00203         return NULL;
00204       }
00205       break;
00206     }
00207   }
00208 
00209   return root;
00210 }
00211 
00212 
00213 struct otl_opt
00214 {
00215   struct bt_node *rule;
00216 };
00217 
00218 otl_opt *
00219 otl_new_opt (void)
00220 {
00221   struct otl_opt *opt;
00222 
00223   opt = NEW(1, struct otl_opt);
00224   opt->rule = NULL;
00225 
00226   return (otl_opt *) opt;
00227 }
00228 
00229 
00230 void
00231 otl_release_opt (otl_opt *opt)
00232 {
00233   if (opt->rule) {
00234     bt_release_tree(opt->rule);
00235   }
00236   opt->rule = NULL;
00237   RELEASE(opt);
00238 }
00239 
00240 #if 0
00241 struct lv_range
00242 {
00243   long start, end;
00244 };
00245 
00246 struct uc_coverage
00247 {
00248   long   count;
00249   struct lv_range *ranges;
00250 };
00251 
00252 static int CDECL
00253 range_cmp (const void *v1, const void *v2)
00254 {
00255   struct lv_range *sv1, *sv2;
00256 
00257   sv1 = (struct lv_range *) v1;
00258   sv2 = (struct lv_range *) v2;
00259 
00260   if (sv1->start < sv2->start)
00261     return -1;
00262   else
00263     return  1;
00264 
00265   return 0;
00266 }
00267 
00268 static int CDECL
00269 range_overlap (const void *v1, const void *v2)
00270 {
00271   struct lv_range *sv1, *sv2;
00272 
00273   sv1 = (struct lv_range *) v1;
00274   sv2 = (struct lv_range *) v2;
00275 
00276   /* Must be first sort in increasing start order */
00277   if (sv1->end  >= sv2->start)
00278     return 0;
00279   else if (sv1->end < sv2->start)
00280     return -1;
00281 
00282   return 1;
00283 }
00284 
00285 static void
00286 check_uc_coverage (struct uc_coverage *coverage)
00287 {
00288   struct lv_range *r1, *r2;
00289   long i;
00290 
00291   for (i = 0; i < coverage->count; i++) {
00292     r1 = &coverage->ranges[i];
00293     r2 = bsearch(r1, coverage->ranges,
00294                  coverage->count, sizeof(struct lv_range),
00295                  range_overlap);
00296     if (r2 && r1 != r2) {
00297       WARN("Overlapping Unicode range found:");
00298       WARN("[%x-%x], [%x-%x] ==> [%x-%x]",
00299            r1->start, r1->end, r2->start, r2->end,
00300           MIN(r1->start, r2->start), MAX(r1->end, r2->end));
00301       r2->start = MIN(r1->start, r2->start);
00302       r2->end   = MAX(r1->end  , r2->end  );
00303       if (i < coverage->count - 1) {
00304         memmove(&coverage->ranges[i], &coverage->ranges[i+1],
00305                 (coverage->count - i - 1) * sizeof(struct lv_range));
00306         coverage->count -= 1;
00307       }
00308     }
00309   }
00310   /* ... */
00311   if (coverage->count == 0) {
00312     RELEASE(coverage->ranges);
00313     coverage->ranges = NULL;
00314   }
00315 }
00316 #endif
00317 
00318 int
00319 otl_parse_optstring (otl_opt *opt, const char *optstr)
00320 {
00321   char  *p, *endptr;
00322 
00323   ASSERT(opt);
00324 
00325   if (optstr) {
00326     p      = (char *) optstr;
00327     endptr = p + strlen(optstr);
00328     opt->rule = parse_expr(&p, endptr);
00329   }
00330 
00331   return 0;
00332 }
00333 
00334 int
00335 otl_match_optrule (otl_opt *opt, const char *tag)
00336 {
00337   ASSERT(tag);
00338 
00339   if (!opt || !opt->rule)
00340     return 1;
00341 
00342   return match_expr(opt->rule, tag);
00343 }