MUSASHI C source: csv2xt.c
0001: /*============================================================================*/
0002: /* 変更履歴 */
0003: /*----------------------------------------------------------------------------*/
0004: /* 1.0 : 新しいAPIに対応(2003/06) */
0005: /*============================================================================*/
0006: #include <musashi.h>
0007: #include <stdlib.h>
0008: #include <string.h>
0009:
0010: #include <csv2xtHelp.h>
0011: struct mssComHelp comHelp={
0012: "csv2xt", /* コマンド名 */
0013: "1.0", /* バージョン */
0014: HELPT, /* コマンドタイトル */
0015: HELPS, /* 要約 */
0016: HELPE, /* 利用例 */
0017: HELPR, /* 参照コマンド */
0018: HELPA, /* 作者情報 */
0019: HELPB, /* バグレポート情報 */
0020: HELPH /* ホームページ */
0021: };
0022:
0023: extern struct mssGlobalVariables mssGV;
0024:
0025: char **tokCsvByChr(char *string, char tok, int *cnt){
0026: char *str;
0027: char *pos;
0028: char **list=NULL;
0029: int outQuote;
0030:
0031: *cnt=0;
0032: str=string;
0033:
0034: pos=str;
0035: outQuote=1; /*""の外ならば1、さもなければ-1*/
0036: while(1){
0037: if(*str=='"') outQuote=outQuote*(-1);
0038: if( (outQuote==1 && *str==tok) || *str=='\0'){
0039: list=mssRealloc(list,sizeof(char *)*(*cnt+1),"tokByChr");
0040: *(list+*cnt)=pos;
0041: (*cnt)++;
0042: pos=str+1;
0043: if(*str=='\0') break;
0044: *str='\0';
0045: }
0046: str++;
0047: }
0048: return(list);
0049: }
0050:
0051: char *conv(char *str,char spcChr){
0052: char *start;
0053:
0054: start=str;
0055: if(*str=='"'){
0056: str++;
0057: start++;
0058: }
0059:
0060: while(*str!='\0'){
0061: if(*str=='"'){
0062: *str='\0';
0063: break;
0064: }
0065: if(*str==' '){
0066: *str=spcChr;
0067: }
0068: str++;
0069: }
0070: return(start);
0071: }
0072:
0073:
0074: int main(int argc, char *argv[]){
0075: /*============================================================================*/
0076: /* オプション宣言&定義 */
0077: /*============================================================================*/
0078: /*----------------------------------------------------------------------------*/
0079: /* 一行目を項目名とみなすフラグ */
0080: /*----------------------------------------------------------------------------*/
0081: MssOptFLG optHFD={
0082: OFLG, /* オプションタイプ */
0083: "F", /* キーワード(複数文字は不可) */
0084: 0, /* デフォルト(基本的には0) 常にonにしたいときは1にする */
0085: HFDT, /* このオプションのタイトル(Helpで表示) */
0086: HFDC /* このオプションのコメント(Helpで表示) */
0087: };
0088:
0089: /*----------------------------------------------------------------------------*/
0090: /* 新項目名 */
0091: /*----------------------------------------------------------------------------*/
0092: MssOptSLS optFNM={
0093: OSLS, /* オプションタイプ */
0094: "a", /* キーワード(複数文字は不可) */
0095: 0, /* 0:オプション, 1:必須, 2:XMLtableでのみ必須(txtでは無視) */
0096: NULL, /* デフォルト(文字列) */
0097: MssFieldMaxCnt, /* カンマで区切られる要素数の最大値 */
0098: 1, /* 各要素の文字列長の最小値 */
0099: MssFieldNameMaxLen,/* 各要素の文字列長の最大値 */
0100: 0, /* 1:要素にコロンを指定できる,0:不可 ex) aaaa:xxxxx */
0101: FNMT, /* このオプションのタイトル(Helpで表示) */
0102: FNMC /* このオプションのコメント(Helpで表示) */
0103: };
0104:
0105: /*----------------------------------------------------------------------------*/
0106: /* タイトル */
0107: /*----------------------------------------------------------------------------*/
0108: MssOptSTR optTIT={
0109: OSTR, /* オプションタイプ */
0110: "l", /* キーワード(複数文字は不可) */
0111: 0, /* 0:オプション, 1:必須, 2:XMLtableでのみ必須(txtでは無視) */
0112: NULL, /* デフォルト */
0113: 0, /* 文字列の最小長 */
0114: MssTitleMaxLen, /* 文字列の最大長 */
0115: TITT, /* このオプションのタイトル(Helpで表示) */
0116: TITC /* このオプションのコメント(Helpで表示) */
0117: };
0118:
0119: /*----------------------------------------------------------------------------*/
0120: /* コメント */
0121: /*----------------------------------------------------------------------------*/
0122: MssOptSTR optCOM={
0123: OSTR, /* オプションタイプ */
0124: "c", /* キーワード(複数文字は不可) */
0125: 0, /* 0:オプション, 1:必須, 2:XMLtableでのみ必須(txtでは無視) */
0126: NULL, /* デフォルト */
0127: 0, /* 文字列の最小長 */
0128: MssCommentMaxLen,/* 文字列の最大長 */
0129: COMT, /* このオプションのタイトル(Helpで表示) */
0130: COMC /* このオプションのコメント(Helpで表示) */
0131: };
0132:
0133: /*----------------------------------------------------------------------------*/
0134: /* spaceを何に変換するか */
0135: /*----------------------------------------------------------------------------*/
0136: MssOptSTR optSPC={
0137: OSTR, /* オプションタイプ */
0138: "S", /* キーワード(複数文字は不可) */
0139: 0, /* 0:オプション, 1:必須, 2:XMLtableでのみ必須(txtでは無視) */
0140: "_", /* デフォルト */
0141: 1, /* 文字列の最小長 */
0142: 1, /* 文字列の最大長 */
0143: SPCT, /* このオプションのタイトル(Helpで表示) */
0144: SPCC /* このオプションのコメント(Helpで表示) */
0145: };
0146:
0147: /*----------------------------------------------------------------------------*/
0148: /* インポートファイル */
0149: /*----------------------------------------------------------------------------*/
0150: MssOptINF optIMP={
0151: OINF, /* オプションタイプ */
0152: "I", /* キーワード(複数文字は不可) */
0153: 0, /* 0:オプション, 1:必須 */
0154: 1, /* 指定可能の最大ファイル数 */
0155: 0, /*1:file not foundのエラーで終了しない 0:する */
0156: IMPT, /* このオプションのタイトル(Helpで表示) */
0157: IMPC /* このオプションのコメント(Helpで表示) */
0158: };
0159:
0160: /*----------------------------------------------------------------------------*/
0161: /* 入力ファイル */
0162: /*----------------------------------------------------------------------------*/
0163: MssOptINF optINF={
0164: OINF, /* オプションタイプ */
0165: "i", /* キーワード(複数文字は不可) */
0166: 0, /* 0:オプション, 1:必須 */
0167: 1, /* 指定可能の最大ファイル数 */
0168: 0, /*1:file not foundのエラーで終了しない 0:する */
0169: INFT, /* このオプションのタイトル(Helpで表示) */
0170: INFC /* このオプションのコメント(Helpで表示) */
0171: };
0172:
0173: /*----------------------------------------------------------------------------*/
0174: /* 出力ファイル */
0175: /*----------------------------------------------------------------------------*/
0176: MssOptOTF optOTF={
0177: OOTF, /* オプションタイプ */
0178: "o", /* キーワード(複数文字は不可) */
0179: 0, /* 0:オプション, 1:必須 */
0180: OTFT, /* このオプションのタイトル(Helpで表示) */
0181: OTFC /* このオプションのコメント(Helpで表示) */
0182: };
0183:
0184: /*----------------------------------------------------------------------------*/
0185: /* 圧縮出力 */
0186: /*----------------------------------------------------------------------------*/
0187: MssOptFLG optZIP={
0188: OFLG, /* オプションタイプ */
0189: "z", /* キーワード(複数文字は不可) */
0190: 0, /* デフォルト(基本的には0) 常にonにしたいときは1にする */
0191: ZIPT, /* このオプションのタイトル(Helpで表示) */
0192: ZIPC /* このオプションのコメント(Helpで表示) */
0193: };
0194:
0195: /*----------------------------------------------------------------------------*/
0196: /* オプションをまとめる */
0197: /*----------------------------------------------------------------------------*/
0198: void *opt[]={&optHFD,&optFNM,&optTIT,&optCOM,&optSPC,&optIMP,
0199: &optINF,&optOTF,&optZIP,NULL};
0200:
0201: /*============================================================================*/
0202: /* 変数宣言&定義 */
0203: /*============================================================================*/
0204: struct mssHeader *hdi; /*テキストファイル用<head>タグ格納構造体*/
0205: struct mssHeader *hdI; /*-I入力ファイル用<head>タグ格納構造体*/
0206: struct mssHeader *hdo; /*出力ファイル用<head>タグ格納構造体*/
0207: struct mssFPR *fpr; /*入力ファイル構造体*/
0208: struct mssFPR *fpr2;/*インポートファイル構造体*/
0209: struct mssFPW *fpw; /*出力ファイル構造体*/
0210: struct mssFldRec *fr; /*項目-行バッファ構造体*/
0211: struct mssRec *rec; /*行バッファ構造体*/
0212:
0213: char **fldLst;
0214: char *str;
0215: int fldCnt;
0216: int i;
0217:
0218: /*----------------------------------------------------------------------------*/
0219: /* 前処理 */
0220: /*----------------------------------------------------------------------------*/
0221: mssInit(argc,argv,&comHelp); /* シグナル処理などの初期化 */
0222: mssHelpDoc(opt,&comHelp,argc,argv); /* ヘルプ */
0223: mssSetOption(opt,argc,argv); /* コマンドオプションの設定 */
0224: fpr=mssOpenFPR(optINF.str,4); /* 入力ファイルオープン */
0225:
0226: /*prnOption(opt);*/
0227: /*prnHeader(hdi);*/
0228:
0229: /*-I,-F,-a,いずれも指定されなかったとき*/
0230: if(!optIMP.set && !optHFD.set && !optFNM.set){
0231: mssShowErrMsg("choose one option in -a,-F,-I");
0232: mssEnd(mssErrorNoDefault);
0233: }
0234:
0235: /*-I,-F,-a,の中で2つ以上指定された*/
0236: if(optIMP.set+optHFD.set+optFNM.set > 1){
0237: mssShowErrMsg("choose one option in -a,-F,-I");
0238: mssEnd(mssErrorNoDefault);
0239: }
0240:
0241: mssGV.txtFlg=1; /* 強制的にon*/
0242: hdi=mssReadHeader(fpr); /* ヘッダの読み込み */
0243: mssGV.txtFlg=0; /* そしてoff*/
0244:
0245: /*----------------------------------------------------------------------------*/
0246: /*出力ヘッダーの作成と出力 */
0247: /*----------------------------------------------------------------------------*/
0248: fr=mssInitFldRec(hdi->flds->cnt);
0249: rec=mssInitRec();
0250:
0251: if(optIMP.set){ /*-Iフラグon (ヘッダーのインポート)*/
0252: fpr2=mssOpenFPR(optIMP.str,4); /*インポートファイルオープン*/
0253: hdI=mssReadHeader(fpr2); /*項目名情報の読み込み*/
0254: hdo=mssInitCpyHeader(hdI); /*出力ヘッダー初期化*/
0255: mssAddFieldsByFields(hdo->flds,hdI->flds); /*hdIヘッダーの項目情報をコピー*/
0256: mssCloseFPR(fpr2); /*インポートファイルクローズ*/
0257: }else{
0258: /*出力ヘッダー初期化*/
0259: hdo=mssInitHeader(optTIT.str,optCOM.str);
0260:
0261: /*項目情報の設定*/
0262:
0263: /*-Fフラグon*/
0264: if(optHFD.set){
0265: if( EOF == mssReadRec(fpr,rec) ){
0266: mssShowErrMsg("can not read input file");
0267: mssEnd(mssErrorNoDefault);
0268: }
0269: fldLst=tokCsvByChr(rec->pnt,',',&fldCnt);
0270: for(i=0; i<fldCnt; i++){
0271: *(fldLst+i)=conv(*(fldLst+i),*optSPC.str);
0272: if(*(fldLst+i)=='\0'){
0273: mssShowErrMsg("detected null in field name");
0274: mssEnd(mssErrorNoDefault);
0275: }
0276: }
0277: mssAddFieldsByStrList(hdo->flds, fldLst, fldCnt);
0278: mssFree(fldLst);
0279: }
0280:
0281: /*-aが指定されたとき*/
0282: if(optFNM.set){
0283: mssAddFieldsByStrList(hdo->flds, optFNM.strList, optFNM.cnt);
0284: }
0285: }
0286:
0287: /*標準出力オープン+ヘッダーの出力*/
0288: fpw=mssOpenFPW(optOTF.str,optZIP.set,0);
0289: mssWriteHeader(hdo,fpw);
0290:
0291: /*----------------------------------------------------------------------------*/
0292: /*メインルーチン */
0293: /*----------------------------------------------------------------------------*/
0294:
0295: while( EOF != mssReadRec(fpr,rec)){
0296: mssGV.inCnt++;
0297: fldLst=tokCsvByChr(rec->pnt,',',&fldCnt);
0298: if(fldCnt!=hdo->flds->cnt) {
0299: mssShowErrMsg("detected different number of fields in line %d(header has %d, but a record has %d)",mssGV.inCnt,hdo->flds->cnt,fldCnt);
0300: mssEnd(mssErrorNoDefault);
0301: }
0302: for(i=0; i<fldCnt; i++){
0303: str=conv(*(fldLst+i),*optSPC.str);
0304: if(*str=='\0'){
0305: mssWriteStr("*",fpw);
0306: if(i==fldCnt-1) mssWriteRet(fpw);
0307: else mssWriteDlm(fpw);
0308: }else{
0309: mssWriteStr(str,fpw);
0310: if(i==fldCnt-1) mssWriteRet(fpw);
0311: else mssWriteDlm(fpw);
0312: }
0313: }
0314: mssFree(fldLst);
0315: mssGV.outCnt++;
0316: }
0317:
0318: mssFreeRec(rec);
0319: mssFreeFldRec(fr);
0320:
0321: /*----------------------------------------------------------------------------*/
0322: /*フッター出力&終了処理 */
0323: /*----------------------------------------------------------------------------*/
0324: mssWriteFooter(fpw); /*フッターの出力*/
0325: mssCloseFPR(fpr); /*入力ファイルのクローズ*/
0326: mssCloseFPW(fpw); /*出力ファイルのクローズ*/
0327: mssFreeHeader(hdi); /*入力ヘッダ領域開放*/
0328: mssFreeHeader(hdo); /*出力ヘッダ領域開放*/
0329: mssFreeOption(opt); /*オプション領域開放*/
0330: mssShowEndMsg(); /*完了メッセージ*/
0331: mssEnd(mssExitSuccess); /*終了*/
0332: return(0); /* to avoid warning message*/
0333: }