(linenum→info "unix/slp.c:2238")

anthy/9100e/src-diclib/ruleparser.c

    1: /*
    2:  * 設定ファイルなどのための
    3:  * 汎用のファイル読み込みモジュール
    4:  *
    5:  * Copyright (C) 2000-2006 TABATA Yusuke
    6:  *
    7:  */
    8: /*
    9:   This library is free software; you can redistribute it and/or
   10:   modify it under the terms of the GNU Lesser General Public
   11:   License as published by the Free Software Foundation; either
   12:   version 2 of the License, or (at your option) any later version.
   13: 
   14:   This library is distributed in the hope that it will be useful,
   15:   but WITHOUT ANY WARRANTY; without even the implied warranty of
   16:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   17:   Lesser General Public License for more details.
   18: 
   19:   You should have received a copy of the GNU Lesser General Public
   20:   License along with this library; if not, write to the Free Software
   21:   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
   22:  */
   23: #include <ctype.h>
   24: #include <stdio.h>
   25: #include <string.h>
   26: #include <stdlib.h>
   27: 
   28: #include <anthy/conf.h>
   29: #include <anthy/ruleparser.h>
   30: #include <anthy/logger.h>
   31: 
   32: /* 文法ファイルのパーザ用の定義 */
   33: #define MAX_TOKEN_LEN 256
   34: /* 最大のインクルードの深さ */
   35: #define MAX_INCLUDE_DEPTH 4
   36: 
   37: #define PS_INIT 0
   38: #define PS_TOKEN 1
   39: #define PS_EOF 2
   40: #define PS_RET 3
   41: 
   42: static const char *NL = "NL";
   43: 
   44: static struct parser_stat {
   45:   FILE *fp_stack[MAX_INCLUDE_DEPTH];
   46:   FILE *fp;
   47:   int cur_fpp;/* スタックのインデックス */
   48:   int line_num;
   49:   char **tokens;
   50:   int nr_token;
   51: } g_ps;
   52: 
   53: struct line_stat{
   54:   int stat;
   55:   char buf[MAX_TOKEN_LEN];
   56:   int buf_index;
   57: };
   58: 
   59: static FILE *
   60: open_file_in_confdir(const char *fn)
   61: {
   62:   const char *dn;
   63:   char *full;
   64:   size_t dname_len;
   65: 
   66:   if (!fn) {
   67:     return stdin;
   68:   }
   69: 
   70:   if (fn[0] == '/' ||
   71:       (fn[0] == '.' && fn[1] == '/')) {
   72:     /* 絶対パスもしくはカレントディレクトリなのでそのままfopen */
   73:     return fopen(fn, "r");
   74:   }
   75: 
   76:   dn = anthy_conf_get_str("ANTHYDIR");
   77:   if (!dn) {
   78:     return 0;
   79:   }
   80:   dname_len =  strlen(dn);
   81:   full = alloca(dname_len + strlen(fn) + 2);
   82:   sprintf(full, "%s/%s", dn, fn);
   83: 
   84:   return fopen(full, "r");
   85: }
   86: 
   87: /** バックスラッシュによるエスケープも処理するgetc
   88:  * エスケープされた文字ならば返り値は1になる。
   89:  */
   90: static int
   91: mygetc (int *cc)
   92: {
   93:   *cc = fgetc(g_ps.fp);
   94:   if (*cc == '\\') {
   95:     int c2 = fgetc(g_ps.fp);
   96:     switch(c2) {
   97:     case '\\':
   98:       *cc = '\\';
   99:       return 1;
  100:     case '\n':
  101:       *cc = ' ';
  102:       return 1;
  103:     case '\"':
  104:       *cc = '\"';
  105:       return 1;
  106:     default:;
  107:       /* go through */
  108:     }
  109:   }
  110:   return 0;
  111: }
  112: 
  113: #define myisblank(c)    ((c) == ' ' || (c) == '\t')
  114: 
  115: /* 行に一文字追加する */
  116: static void
  117: pushchar(struct line_stat *ls, int cc)
  118: {
  119:   if (ls->buf_index == MAX_TOKEN_LEN - 1) {
  120:     ls->buf[MAX_TOKEN_LEN - 1] = 0;
  121:   } else {
  122:     ls->buf[ls->buf_index] = cc;
  123:     ls->buf_index ++;
  124:   }
  125: }
  126: 
  127: static const char *
  128: get_token_in(struct line_stat *ls)
  129: {
  130:   int cc, esc;
  131:   int in_quote = 0;
  132:   if (ls->stat == PS_EOF) {
  133:     return NULL;
  134:   }
  135:   if (ls->stat == PS_RET) {
  136:     return NL;
  137:   }
  138:   /* トークンが始まるまで空白を読み飛ばす */
  139:   do {
  140:     esc = mygetc(&cc);
  141:   } while (cc > 0 && myisblank(cc) && esc == 0);
  142:   if (cc == -1) {
  143:     return NULL;
  144:   }
  145:   if (cc == '\n'){
  146:     return NL;
  147:   }
  148: 
  149:   /**/
  150:   if (cc == '\"' && !esc) {
  151:     in_quote = 1;
  152:   }
  153:   /**/
  154:   do {
  155:     pushchar(ls, cc);
  156:     esc = mygetc(&cc);
  157:     if (cc < 0){
  158:       /* EOF */
  159:       pushchar(ls, 0);
  160:       ls->stat = PS_EOF;
  161:       return ls->buf;
  162:     }
  163:     if (cc == '\n' && !esc) {
  164:       /* 改行 */
  165:       pushchar(ls, 0);
  166:       ls->stat = PS_RET;
  167:       return ls->buf;
  168:     }
  169:     if (!in_quote && myisblank(cc)) {
  170:       break;
  171:     }
  172:     if (in_quote && cc == '\"' && !esc) {
  173:       pushchar(ls, '\"');
  174:       break;
  175:     }
  176:   } while (1);
  177:   pushchar(ls, 0);
  178:   return ls->buf;
  179: }
  180: 
  181: /* 一行読む */
  182: static int
  183: get_line_in(void)
  184: {
  185:   const char *t;
  186:   struct line_stat ls;
  187: 
  188:   ls.stat = PS_INIT;
  189:   do{
  190:     ls.buf_index = 0;
  191:     t = get_token_in(&ls);
  192:     if (!t) {
  193:       return -1;
  194:     }
  195:     if (t == NL) {
  196:       return 0;
  197:     }
  198:     g_ps.nr_token++;
  199:     g_ps.tokens = realloc(g_ps.tokens, sizeof(char *)*g_ps.nr_token);
  200:     g_ps.tokens[g_ps.nr_token-1] = strdup(t);
  201:   } while(1);
  202: }
  203: 
  204: static void
  205: proc_include(void)
  206: {
  207:   FILE *fp;
  208:   if (g_ps.nr_token != 2) {
  209:     anthy_log(0, "Syntax error in include directive.\n");
  210:     return ;
  211:   }
  212:   if (g_ps.cur_fpp > MAX_INCLUDE_DEPTH - 1) {
  213:     anthy_log(0, "Too deep include.\n");
  214:     return ;
  215:   }
  216:   fp = open_file_in_confdir(g_ps.tokens[1]);
  217:   if (!fp) {
  218:     anthy_log(0, "Failed to open %s.\n", g_ps.tokens[1]);
  219:     return ;
  220:   }
  221:   g_ps.cur_fpp++;
  222:   g_ps.fp_stack[g_ps.cur_fpp] = fp;
  223:   g_ps.fp = fp;
  224: }
  225: 
  226: /* インクルードのネストを下げる */
  227: static void
  228: pop_file(void)
  229: {
  230:   fclose(g_ps.fp);
  231:   g_ps.cur_fpp --;
  232:   g_ps.fp = g_ps.fp_stack[g_ps.cur_fpp];
  233: }
  234: 
  235: static void
  236: get_line(void)
  237: {
  238:   int r;
  239:   
  240:  again:
  241:   anthy_free_line();
  242:   g_ps.line_num ++;
  243: 
  244:   r = get_line_in();
  245:   if (r == -1){
  246:     /* EOF等でこれ以上読めん */
  247:     if (g_ps.cur_fpp > 0) {
  248:       pop_file();
  249:       goto again;
  250:     }else{
  251:       return ;
  252:     }
  253:   }
  254:   if (!g_ps.nr_token) {
  255:     return ;
  256:   }
  257:   if (!strcmp(g_ps.tokens[0], "\\include")) {
  258:     proc_include();
  259:     goto again;
  260:   }else if (!strcmp(g_ps.tokens[0], "\\eof")) {
  261:     if (g_ps.cur_fpp > 0) {
  262:       pop_file();
  263:       goto again;
  264:     }else{
  265:       anthy_free_line();
  266:       return ;
  267:     }
  268:   }
  269:   if (g_ps.tokens[0][0] == '#'){
  270:     goto again;
  271:   }
  272: }
  273: 
  274: void
  275: anthy_free_line(void)
  276: {
  277:   int i;
  278:   for (i = 0; i < g_ps.nr_token; i++) {
  279:     free(g_ps.tokens[i]);
  280:   }
  281:   free(g_ps.tokens);
  282:   g_ps.tokens = 0;
  283:   g_ps.nr_token = 0;
  284: }
  285: 
  286: int
  287: anthy_open_file(const char *fn)
  288: {
  289:   g_ps.fp_stack[0] = open_file_in_confdir(fn);
  290:   if (!g_ps.fp_stack[0]) {
  291:     return -1;
  292:   }
  293:   /* パーザの状態を初期化する */
  294:   g_ps.cur_fpp = 0;
  295:   g_ps.fp = g_ps.fp_stack[0];
  296:   g_ps.line_num = 0;
  297:   return 0;
  298: }
  299: 
  300: void
  301: anthy_close_file(void)
  302: {
  303:   if (g_ps.fp != stdin) {
  304:     fclose(g_ps.fp);
  305:   }
  306: }
  307: 
  308: int
  309: anthy_read_line(char ***tokens, int *nr)
  310: {
  311:   get_line();
  312:   *tokens = g_ps.tokens;
  313:   *nr = g_ps.nr_token;
  314:   if (!*nr) {
  315:     return -1;
  316:   }
  317:   return 0;
  318: }
  319: 
  320: int
  321: anthy_get_line_number(void)
  322: {
  323:   return g_ps.line_num;
  324: }
Syntax (Markdown)