MUSASHI C source: xmlcat.c


0001: /*============================================================================*/ 
0002: /* 変更履歴                                                                   */ 
0003: /*----------------------------------------------------------------------------*/ 
0004: /* 1.0 : 新しいAPIに対応                                                      */ 
0005: /*============================================================================*/ 
0006: #include <musashi.h
0007: #include <stdio.h> 
0008: #include <stdlib.h> 
0009: #include <string.h> 
0010: #include <libxml/parser.h> 
0011: #include <libxml/parserInternals.h> 
0012: #include <libxml/encoding.h> 
0013: #include <iconv.h> 
0014: #include <errno.h> 
0015: #include <glob.h> 
0016:  
0017: #include <xmlcatHelp.h> 
0018: struct mssComHelp comHelp={ 
0019:   "xmlcat",       /* コマンド名       */ 
0020:   "1.0",          /* バージョン       */ 
0021:   HELPT,          /* コマンドタイトル */ 
0022:   HELPS,          /* 要約             */ 
0023:   HELPE,          /* 利用例           */ 
0024:   HELPR,          /* 参照コマンド     */ 
0025:   HELPA,          /* 作者情報         */ 
0026:   HELPB,          /* バグレポート情報 */ 
0027:   HELPH           /* ホームページ     */ 
0028: }; 
0029:  
0030: #define UNDEF 0 
0031: #define MAX_NEST 32 
0032: #define LOCAL_BUF 256 
0033: #define EncMax MssFieldMaxLen  /*iconvで使う出力用文字列長*/ 
0034:  
0035: /*----------------------------------------------------------------------------*/ 
0036: /* グローバル変数                                                             */ 
0037: /*----------------------------------------------------------------------------*/ 
0038: extern xmlParserCtxtPtr ctxt; 
0039: extern struct mssGlobalVariables mssGV; 
0040:  
0041: static struct mssFPW    *fpw; /*出力ファイル構造体*/ 
0042: static iconv_t *icid; 
0043: static char *inEnc1=NULL; /*一つ目のファイルのエンコーディング*/ 
0044: static char *inVer1=NULL; /*一つ目のファイルのバージョン*/ 
0045: static char *inEncN=NULL; /*二つ目以降のファイルのエンコーディング*/ 
0046: static char *inVerN=NULL; /*二つ目以降のファイルのバージョン*/ 
0047: static int  procFileNo=-1;/*現在処理中のファイル番号(一つ目のファイルを認識するため)*/ 
0048: static struct mssXmlTag *rootTag; 
0049:  
0050: /*----------------------------------------------------------------------------*/ 
0051: /* ルートタグ名                                                               */ 
0052: /*----------------------------------------------------------------------------*/ 
0053:   MssOptSTR optRTG={ 
0054:     OSTR,   /* オプションタイプ                                             */ 
0055:     "R",    /* キーワード(複数文字は不可)                                   */ 
0056:     0,      /* 0:オプション, 1:必須, 2:XMLtableでのみ必須(txtでは無視)      */ 
0057:     NULL  , /* デフォルト                                                   */ 
0058:     1,      /* 文字列の最小長                                               */ 
0059:     256,    /* 文字列の最大長                                               */ 
0060:     RTGT,   /* このオプションのタイトル(Helpで表示)                         */ 
0061:     RTGC    /* このオプションのコメント(Helpで表示)                         */ 
0062:   }; 
0063:  
0064: /*----------------------------------------------------------------------------*/ 
0065: /* 入力ファイル                                                               */ 
0066: /*----------------------------------------------------------------------------*/ 
0067:   MssOptINF optINF={ 
0068:     OINF,   /* オプションタイプ                                             */ 
0069:     "i",    /* キーワード(複数文字は不可)                                   */ 
0070:     0,      /* 0:オプション, 1:必須                                         */ 
0071:     256,    /* 指定可能の最大ファイル数                                     */ 
0072:     1,      /*1:file not foundのエラーで終了しない 0:する                   */ 
0073:     INFT,   /* このオプションのタイトル(Helpで表示)                         */ 
0074:     INFC    /* このオプションのコメント(Helpで表示)                         */ 
0075:   }; 
0076:  
0077: /*----------------------------------------------------------------------------*/ 
0078: /* 出力ファイル                                                               */ 
0079: /*----------------------------------------------------------------------------*/ 
0080:   MssOptOTF optOTF={ 
0081:     OOTF,   /* オプションタイプ                                             */ 
0082:     "o",    /* キーワード(複数文字は不可)                                   */ 
0083:     0,      /* 0:オプション, 1:必須                                         */ 
0084:     OTFT,   /* このオプションのタイトル(Helpで表示)                         */ 
0085:     OTFC    /* このオプションのコメント(Helpで表示)                         */ 
0086:   }; 
0087:  
0088: /*----------------------------------------------------------------------------*/ 
0089: /* 圧縮出力                                                                   */ 
0090: /*----------------------------------------------------------------------------*/ 
0091:   MssOptFLG optZIP={ 
0092:     OFLG,   /* オプションタイプ                                             */ 
0093:     "z",    /* キーワード(複数文字は不可)                                   */ 
0094:     0,      /* デフォルト(基本的には0) 常にonにしたいときは1にする          */ 
0095:     ZIPT,   /* このオプションのタイトル(Helpで表示)                         */ 
0096:     ZIPC    /* このオプションのコメント(Helpで表示)                         */ 
0097:   }; 
0098:  
0099: /*----------------------------------------------------------------------------*/ 
0100: /* オプションをまとめる                                                       */ 
0101: /*----------------------------------------------------------------------------*/ 
0102: void *opt[]={&optRTG,&optINF,&optOTF,&optZIP,NULL}; 
0103:  
0104: /*----------------------------------------------------------------------------*/ 
0105: /* 構造体                                                                     */ 
0106: /*----------------------------------------------------------------------------*/ 
0107: /* -f 項目名構造体 */ 
0108: /* ex) -f rec@id:recID */ 
0109: struct XmlFld { 
0110:   int   cnt;               /*項目数         */ 
0111:   char *eleNamOrg[MssFieldMaxCnt]; /*要素名 (rec)   */ 
0112:   char *attNamOrg[MssFieldMaxCnt]; /*属性名 (id)    */ 
0113:   char *newNamOrg[MssFieldMaxCnt]; /*新項目名(recID)*/ 
0114:   char *eleNam[MssFieldMaxCnt];    /*要素名UTF8     */ 
0115:   char *attNam[MssFieldMaxCnt];    /*属性名UTF8     */ 
0116:   char *newNam[MssFieldMaxCnt];    /*新項目名UTF8   */ 
0117:   int   keyNum[MssFieldMaxCnt];    /*-kでも指定されていれば、その番号*/ 
0118: }; 
0119:  
0120: struct XmlKey { 
0121:   char *namOrg[MssFieldMaxCnt]; 
0122:   char *nam[MssFieldMaxCnt]; 
0123:   int   on[MssFieldMaxCnt]; 
0124:   int   allKeyIsOn; 
0125:   int   cnt; 
0126: }; 
0127:  
0128: typedef struct _XmlState { 
0129:   int level; 
0130:   int crFlg; 
0131: } XmlState; 
0132:  
0133: /*----------------------------------------------------------------------------*/ 
0134: /* SAX ハンドラー                                                             */ 
0135: /*----------------------------------------------------------------------------*/ 
0136: void start_doc(XmlState *state){ 
0137:  
0138:   procFileNo++; /*処理中のファイル番号をUP*/ 
0139:  
0140:   /*一つ目のファイルのXML宣言を獲得し出力*/ 
0141:   if(procFileNo==0){ 
0142:     inEnc1=mssStrdup((char *)ctxt->input->encoding); 
0143:     inVer1=mssStrdup((char *)ctxt->version); 
0144:     mssWriteXmlDeclaration( inVer1, inEnc1, fpw ); 
0145:     if(inEnc1==NULL) inEnc1=mssStrdup("UTF-8"); 
0146:  
0147:     /*出力のiconvオープン*/ 
0148:     icid=iconv_open(inEnc1,"UTF-8"); 
0149:     if((int)icid==-1){ 
0150:       mssShowErrMsg("encoding type error in iconv_open"); 
0151:       mssEnd(mssErrorNoDefault); 
0152:     } 
0153:  
0154:   /*二つ目以降のファイルのXML宣言を獲得し一つ目と比較*/ 
0155:   }else{ 
0156:     mssFree(inEncN); 
0157:     mssFree(inVerN); 
0158:     inEncN=mssStrdup((char *)ctxt->input->encoding); 
0159:     inVerN=mssStrdup((char *)ctxt->version); 
0160:     if(inEncN==NULL) inEncN=mssStrdup("UTF-8"); 
0161:     if( 0!=strcmp(inVer1,inVerN) ){ 
0162:       mssShowErrMsg("different xml version on %s",ctxt->input->filename); 
0163:       mssEnd(mssErrorNoDefault); 
0164:     } 
0165:     if( 0!=strcmp(inEnc1,inEncN) ){ 
0166:       mssShowErrMsg("different xml encoding on %s",ctxt->input->filename); 
0167:       mssEnd(mssErrorNoDefault); 
0168:     } 
0169:     /*出力のiconvオープン*/ 
0170:     icid=iconv_open(inEncN,"UTF-8"); 
0171:     if((int)icid==-1){ 
0172:       mssShowErrMsg("encoding type error in iconv_open"); 
0173:       mssEnd(mssErrorNoDefault); 
0174:     } 
0175:   } 
0176: } 
0177:  
0178: void end_doc(XmlState *state){ 
0179:   if(icid!=NULL) iconv_close(icid); 
0180: } 
0181:  
0182: /*エレメント start */ 
0183: void start_element(XmlState *state, char *fullname, char **atts){ 
0184:  
0185:   struct mssXmlTag *xmlTag; 
0186:   int i; 
0187:  
0188:   mssGV.inCnt++; 
0189:  
0190:   if(state->level==0){ 
0191:     if(!optRTG.set){ 
0192:       if(!procFileNo==0){ 
0193:         if(0!=strcmp(rootTag->element,fullname)){ 
0194:           mssShowErrMsg("different root tag [%s] in %s", 
0195:                                               fullname,ctxt->input->filename ); 
0196:           mssEnd(mssErrorNoDefault); 
0197:         } 
0198:         state->level++; 
0199:         return; 
0200:       }else{ 
0201:         rootTag=mssInitXmlTag(fullname,NULL); 
0202:       } 
0203:  
0204:     /*ルートタグが指定されている*/ 
0205:     }else{ 
0206:       if(procFileNo==0){ 
0207:         mssWriteXmlStartTag(rootTag,icid,fpw); 
0208:         mssGV.outCnt++; 
0209:         state->crFlg=1; 
0210:         state->level++; 
0211:       } 
0212:     } 
0213:   } 
0214:  
0215:   if(state->crFlg){ 
0216:     mssWriteRet(fpw); 
0217:     state->crFlg=0; 
0218:   } 
0219:   mssWriteXmlIndent(state->level,fpw); 
0220:  
0221:   xmlTag=mssInitXmlTag(fullname,NULL); 
0222:   if(atts!=NULL){ 
0223:     for(i=0;;i++){ 
0224:       if(*(atts+2*i+0)==NULL) break; 
0225:       if(*(atts+2*i+1)==NULL) break; 
0226:       mssAddXmlTagAttributeStr(xmlTag,*(atts+2*i),*(atts+2*i+1),NULL); 
0227:     } 
0228:   } 
0229:   mssWriteXmlStartTag(xmlTag,icid,fpw); 
0230:   mssFreeXmlTag(xmlTag); 
0231:  
0232:   mssGV.outCnt++; 
0233:   state->level++; 
0234: } 
0235:  
0236: /*エレメント end */ 
0237: void end_element(XmlState *state, char *fullname, char **atts){ 
0238:  
0239:   struct mssXmlTag *xmlTag; 
0240:  
0241:   state->level--; 
0242:  
0243:   /* ルートタグ & add型 & 最後のファイルでない */ 
0244:   if(state->level==0){ 
0245:     if(!optRTG.set){ 
0246:       if(procFileNo!=optINF.cnt-1){ 
0247:         return; 
0248:       } 
0249:     } 
0250:   } 
0251:  
0252:   if(state->crFlg){ 
0253:     mssWriteRet(fpw); 
0254:     mssWriteXmlIndent(state->level,fpw); 
0255:     state->crFlg=0; 
0256:   } 
0257:   xmlTag=mssInitXmlTag(fullname,NULL); 
0258:   mssWriteXmlEndTag(xmlTag,icid,fpw); 
0259:   mssFreeXmlTag(xmlTag); 
0260:  
0261:   if(optRTG.set){ 
0262:     if(state->level==1){ 
0263:       mssWriteRet(fpw); 
0264:       if(procFileNo==optINF.cnt-1){ 
0265:         mssWriteXmlEndTag(rootTag,icid,fpw); 
0266:         mssWriteRet(fpw); 
0267:         state->level--; 
0268:       } 
0269:     } 
0270:   }else{ 
0271:     if(state->level==0){ 
0272:       mssWriteRet(fpw); 
0273:     } 
0274:   } 
0275: } 
0276:  
0277: void start_characters(XmlState *state, xmlChar *chars, int len){ 
0278:   char *tmp; 
0279:  
0280:   switch(*chars){ 
0281:   case '\n': 
0282:     state->crFlg=1; break; 
0283:   case '&': 
0284:     mssWriteStr("&amp;",fpw); break; 
0285:   case '>': 
0286:     mssWriteStr("&gt;",fpw); break; 
0287:   case '<': 
0288:     mssWriteStr("&lt;",fpw); break; 
0289:   case '\'': 
0290:     mssWriteStr("&apos;",fpw); break; 
0291:   case '"': 
0292:     mssWriteStr("&quot;",fpw); break; 
0293:   default: 
0294:     tmp=mssNencoding(chars,len,icid); 
0295:     mssWriteStr(tmp,fpw); 
0296:     mssFree(tmp); 
0297:   } 
0298: } 
0299:  
0300: void start_cdata(XmlState *state, xmlChar *chars, int len){ 
0301:   char *tmp; 
0302:  
0303:   mssWriteStr("<![CDATA[",fpw); 
0304:   tmp=mssNencoding(chars,len,icid); 
0305:   mssWriteStr(tmp,fpw); 
0306:   mssFree(tmp); 
0307:   mssWriteStr("]]>",fpw); 
0308: } 
0309:  
0310: static xmlEntityPtr get_entity( XmlState *ctx, xmlChar *name){ 
0311:   return xmlGetPredefinedEntity(name); 
0312: } 
0313:  
0314: /*sax error handler*/ 
0315: #include "saxerror.h" 
0316:  
0317: static xmlSAXHandler SAXFunctions = { 
0318:     NULL, /* internalSubset */ 
0319:     NULL, /* isStandalone */ 
0320:     NULL, /* hasInternalSubset */ 
0321:     NULL, /* hasExternalSubset */ 
0322:     NULL, /* resolveEntity */ 
0323:     (getEntitySAXFunc) get_entity, /* getEntity */ 
0324:     NULL, /* entityDecl */ 
0325:     NULL, /* notationDecl */ 
0326:     NULL, /* attributeDecl */ 
0327:     NULL, /* elementDecl */ 
0328:     NULL, /* unparsedEntityDecl */ 
0329:     NULL, /* setDocumentLocator */ 
0330:     (startDocumentSAXFunc)start_doc, /* startDocument */ 
0331:     (endDocumentSAXFunc)end_doc, /* endDocument */ 
0332:     (startElementSAXFunc)start_element, /* startElement */ 
0333:     (endElementSAXFunc)end_element, /* endElement */ 
0334:     NULL, /* reference */ 
0335:     (charactersSAXFunc) start_characters, /* characters */ 
0336:     NULL, /* ignorableWhitespace */ 
0337:     NULL, /* processingInstruction */ 
0338:     NULL, /* comment */ 
0339:     (warningSAXFunc) xmlSaxErrEnd, /* xmlParserWarning */ 
0340:     (errorSAXFunc) xmlSaxErrEnd, /* xmlParserError */ 
0341:     (fatalErrorSAXFunc) xmlSaxErrEnd, /* xmlParserError */ 
0342:     NULL, /* getParameterEntity */ 
0343:     (cdataBlockSAXFunc)start_cdata, 
0344: }; 
0345:  
0346: int main(int argc, char *argv[]){ 
0347:  
0348:   XmlState         *state; 
0349:   int i; 
0350:  
0351: /*----------------------------------------------------------------------------*/ 
0352: /* 前処理                                                                     */ 
0353: /*----------------------------------------------------------------------------*/ 
0354:   mssInit(argc,argv,&comHelp);        /* シグナル処理などの初期化     */ 
0355:   mssHelpDoc(opt,&comHelp,argc,argv); /* ヘルプ                       */ 
0356:   mssSetOption(opt,argc,argv);        /* コマンドオプションの設定     */ 
0357:  
0358:   /*引数のタグ名、属性名をUTF-8に変換して格納*/ 
0359:   if(optRTG.set){ 
0360:     icid=iconv_open("UTF-8",MssXmlDefEnc); 
0361:     if((int)icid==-1) { 
0362:       mssShowErrMsg("encoding type error in -E"); 
0363:       mssEnd(mssErrorNoDefault); 
0364:     } 
0365:  
0366:     rootTag=mssOpt2XmlTag(optRTG.str,icid); 
0367:     //rootTag=mssOpt2XmlTag(optRTG.str,NULL); 
0368:  
0369:     if(icid!=NULL) iconv_close(icid); 
0370:   } 
0371:  
0372:   /*標準出力オープン*/ 
0373:   fpw=mssOpenFPW(optOTF.str,optZIP.set,0); 
0374: //mssWriteXmlStartTag(rootTag,NULL,fpw); 
0375:  
0376: /*----------------------------------------------------------------------------*/ 
0377: /*メインルーチン                                                              */ 
0378: /*----------------------------------------------------------------------------*/ 
0379:  
0380:   state=mssCalloc(sizeof(XmlState),"xml2xt"); 
0381:   for(i=0; i<optINF.cnt; i++){ 
0382:  
0383:     ctxt=(xmlParserCtxtPtr)xmlCreateFileParserCtxt(*(optINF.strList+i)); 
0384:     if(!ctxt){ 
0385:       mssShowErrMsg("not xml file"); 
0386:       mssEnd(mssErrorNoDefault); 
0387:     } 
0388:     ctxt->sax=&SAXFunctions; 
0389:  
0390:     ctxt->userData=state; 
0391:     xmlParseDocument(ctxt); 
0392:     ctxt->sax=NULL; 
0393:     xmlFreeParserCtxt(ctxt); 
0394:   } 
0395:  
0396:   mssFree(inEnc1); 
0397:   mssFree(inVer1); 
0398:   mssFree(inEncN); 
0399:   mssFree(inVerN); 
0400:   mssFree(state); 
0401:   mssFreeXmlTag(rootTag); 
0402:  
0403: /*----------------------------------------------------------------------------*/ 
0404: /*フッター出力&終了処理                                                       */ 
0405: /*----------------------------------------------------------------------------*/ 
0406:   mssCloseFPW(fpw);       /*出力ファイルのクローズ   */ 
0407:   mssFreeOption(opt);     /*オプション領域開放       */ 
0408:   mssShowEndMsg();        /*完了メッセージ           */ 
0409:   mssEnd(mssExitSuccess); /*終了                     */ 
0410:   return(0);              /* to avoid warning message*/ 
0411: }