#include #include #include #include #include #include "et_parser.h" #include "blend.h" /*****************************************************************************/ /* fpが示すストリームから改行までを読み込む。新たにメモリ領域を確保するため、*/ /* 呼び出し成功後は、*rbufが示す領域を解放すること。 */ /* (要するに、長大行にも対応できるよう内部で領域確保するfgets.) */ /* 戻り値: 実際に読み込んだバイト数 (エラー値 -1) */ /*****************************************************************************/ int vfgets(char **rbuf, FILE *fp) { char buf[BUFLEN]; char *bufp = NULL; int len; int total = 0; int size = 0; while (fgets(buf, sizeof(buf), fp)) { len = strlen(buf); if (total + len >= size) { if (total + len - size > HEAPLEN) size = total + len; else size += HEAPLEN; if (bufp == NULL) { bufp = (char *)calloc(size, sizeof(char)); onmemStrings++; } else { bufp = (char *)realloc(bufp, size * sizeof(char)); } if (bufp == NULL) { onmemStrings--; fprintf(stderr, "Cannot alloc memory (%d)\n", size * sizeof(char)); bufp = NULL; total = -1; break; } } strncpy(bufp + total, buf, len); total += len; if (total > 0 && bufp[total - 1] == '\n') { total = strlen(bufp); break; } } *rbuf = bufp; return total; } /*****************************************************************************/ /* EasyTrackの種別(EasyGeneTrack, EasyGraphTrack, EasyColorTrak)を判別する */ /*****************************************************************************/ ET_TYPE identify_line(char *line) { if (line == NULL) return NOTYPE; if (strncmp(line, "geneTrack", 9) == 0) return et_geneTrack; if (strncmp(line, "graphTrack", 10) == 0) return et_graphTrack; if (strncmp(line, "colorTrack", 10) == 0) return et_colorTrack; if (strncmp(line, "gene", 4) == 0) return et_gene; if (strncmp(line, "graph", 5) == 0) return et_graph; if (strncmp(line, "color", 5) == 0) return et_color; return NOTYPE; } /*****************************************************************************/ /* tokenに含まれる'='以降の文字列をmemberにコピーする */ /* [戻り値] 成功:コピー先のアドレス(member) 失敗:NULL */ /* [引数] member: 読み込んだ値(文字列)をコピーする領域。NULLでもOK. */ /* length: コピー先の領域の大きさ。または確保するべき大きさ。 */ /* token: 解釈すべき文字列。"name=string" の形。 */ /*****************************************************************************/ static char *setStrValue(char *member, int length, char *token) { char *p; char *area = NULL; int clen = 0; /* tokenに渡される文字列は、"name=mappedGene" の形を想定 */ if (!token || length <= 0) { fprintf(stderr, "setStrValue: invalid argument.\n"); return NULL; } if (member) { /* コピー先が用意されている場合はその領域を使う */ area = member; } else { /* コピー先が用意されていにない場合は新たに確保する */ area = (char *)malloc(length + 1); if (!area) { fprintf(stderr, "setStrValue: memory allocation error.\n"); return NULL; } onmemStrings++; } p = index(token, '='); if (!p) { fprintf(stderr, "setStrValue: format error. ('=' not found)\n"); if (!member) { free(area); onmemStrings--; /* String */ } return NULL; } p++; /* ダブルクォーテーションで囲まれていない値の場合 */ if (*p != '\"') { clen = strlen(p); if (clen > length) { fprintf(stderr, "setStrValue: copying area is too small.\n"); if (!member) { free(area); onmemStrings--; /* String */ } return NULL; } strcpy(area, p); return area; } /* 値がダブルクォーテーションで囲まれている場合 */ p++; /* '"'の次の位置に移動 */ if (*(p + strlen(p) - 1) == '\"') { /* 間にスペースやタブが無い場合 */ *(p + strlen(p) - 1) = '\0'; clen = strlen(p); if (clen > length) { fprintf(stderr, "setStrValue: copying area is too small.\n"); if (!member) { free(area); onmemStrings--; /* String */ } return NULL; } strcpy(area, p); } else { /* スペースやタブが含まれている場合 */ while (p && *(p + strlen(p) - 1) != '\"') { clen += strlen(p) + 1; if (clen > length) { fprintf(stderr, "setStrValue: copying area is too small.\n"); if (!member) { free(area); onmemStrings--; /* String */ } return NULL; } strcat(area, p); strcat(area, " "); p = strtok(NULL, " \t\n"); } if (!p) { fprintf(stderr, "setStrValue: quotation is not closed.\n"); if (!member) { free(area); onmemStrings--; /* String */ } return NULL; } *(p + strlen(p) - 1) = '\0'; clen += strlen(p); strcat(area, p); } return area; } /*****************************************************************************/ /* tokenに含まれる値を解釈して、浮動少数数値として保持する。 */ /* [戻り値] 成功:値格納アドレス(value) 失敗:NULL */ /* [引数] value: 値を格納するアドレス */ /* token: 解釈すべき文字列。"max=1.0" の形。 */ /*****************************************************************************/ static EG_VALUE *setNumericValue(EG_VALUE *value, char *token) { char *p; if (!token || !value) { fprintf(stderr, "setNumericValue: invalid argument.\n"); return NULL; } p = index(token, '='); if (!p) { fprintf(stderr, "setNumerciValue: format error. ('=' is not found)\n"); return NULL; } *value = atof(p + 1); return value; } /*****************************************************************************/ /* tokenに含まれる値を解釈して、整数値として保持する。 */ /* [戻り値] 成功:値格納アドレス(unit) 失敗:NULL */ /* [引数] unit: 値を格納するアドレス */ /* token: 解釈すべき文字列。"unit=10" の形。 */ /*****************************************************************************/ static off_t *setUnit(off_t *unit, char *token) { char *p; if (!token || !unit) { fprintf(stderr, "setUnit: invalid argument.\n"); return NULL; } p = index(token, '='); if (!p) { fprintf(stderr, "setUnit: format error.('=' is not found)\n"); return NULL; } *unit = atoi(p + 1); return unit; } /*****************************************************************************/ /* tokenに含まれる値を解釈して、2つの整数値として保持する。 */ /* [戻り値] 成功:1 失敗:0 */ /* [引数] first: 1個目の値を格納するアドレス */ /* second: 2個目の値を格納するアドレス */ /* token: 解釈すべき文字列。"range=1,1000" の形。 */ /*****************************************************************************/ static int setRange(off_t *first, off_t *second, char *token) { char *p; char *q; if (!token || !first || !second) { fprintf(stderr, "setRange: invalid argument.\n"); return 0; } p = index(token, '='); if (!p) { fprintf(stderr, "setRange: format error. ('=' is not found)\n"); return 0; } p++; q = index(p, ','); if (q) { *q = '\0'; q++; } *first = (p) ? atoi(p) : 0; *second = (q) ? atoi(q) : 0; return 1; } /*****************************************************************************/ /* tokenに含まれる値を解釈して、ブレンドポリシの値として保持する。 */ /* [戻り値] 成功:値格納アドレス(blend) 失敗:NULL */ /* [引数] blend: 値を格納するアドレス */ /* token: 解釈すべき文字列。"blend=average" の形。 */ /*****************************************************************************/ static BLEND *setBlendValue(BLEND *blend, char *token) { char *p; if (!token || !blend) { fprintf(stderr, "setBlendValue: invalid argument.\n"); return NULL; } p = index(token, '='); if (!p) { fprintf(stderr, "setBlendValue: format error. ('=' is not found)\n"); return NULL; } *blend = resolveBlend(p + 1); return blend; } /*****************************************************************************/ /* tokenに含まれる値を解釈して、カラー値として保持する。 */ /* [戻り値] 成功:1 失敗:0 */ /* [引数] color: 値を格納する領域のアドレス */ /* token: 解釈すべき文字列。"color=255,0,99" の形。 */ /*****************************************************************************/ static int setColorValue(COLOR *color, char *token) { char *red = NULL; char *green = NULL; char *blue = NULL; char *q = NULL; if (!token || !color) { fprintf(stderr, "setColorValue: invalid argument.\n"); return 0; } red = index(token, '='); if (!red) { fprintf(stderr, "setColorValue: format error. ('=' not found)\n"); return 0; } red++; /*******************************************/ q = index(red, ','); /* color=255,0,128 */ if (q) { /* ^ ^ ^ */ *q = '\0'; /* r g b */ green = q + 1; /* */ q = index(green, ','); /* (','は'\0'に置き換える) */ if (q) { /*******************************************/ *q = '\0'; blue = q + 1; } } color->red = (red) ? atoi(red) : 0; color->green = (green) ? atoi(green) : 0; color->blue = (blue) ? atoi(blue) : 0; return 1; } /*****************************************************************************/ /* tokenに含まれる値を解釈して、カラー値の配列として保持する。 */ /* [戻り値] 成功:値格納アドレス(colors) 失敗:NULL */ /* [引数] color: 値を格納する領域のアドレス */ /* token: 解釈すべき文字列。"colors=(255,0,99),(0,100,100)" の形。 */ /*****************************************************************************/ static COLOR *setColorValues(COLOR **colors, int *num, int startpos, int endpos, int unit, char *token) { char *start; char *p; char *q; int tnum = 0; COLOR *area; COLOR *color; char *red = NULL; char *green = NULL; char *blue = NULL; char tmp[128]; int offset; if (!token) { fprintf(stderr, "setColorValues: invalid argument.\n"); return NULL; } /* tokenの内容の例: colors=(255,0,0),(100,100,0),(0,255,100) */ start = index(token, '='); if (!start) { fprintf(stderr, "setColorValues: format error. ('=' not found)\n"); return NULL; } /* 個数の数え上げとメモリ確保 */ p = start + 1; while ((q = index(p, ')')) != NULL) { tnum++; p = q + 1; } area = (COLOR *)calloc(tnum, sizeof(COLOR)); if (!area) { fprintf(stderr, "setColorValues: memory allocation error.\n"); return NULL; } onmemColors++; color = area; offset = startpos; p = start + 1; /* pを最初の左括弧'('の位置にセット */ while (p) { //printf("p={%s}\n", p); q = index(p, ')'); if (!q) { fprintf(stderr, "setColorValues: format error. (breath is not closed)\n"); free(area); onmemStrings--; /* String */ return NULL; } strncpy(tmp, p + 1, q - p - 1); /* 括弧内の部分をコピー */ tmp[q - p - 1] = '\0'; //printf("tmp={%s} q=%p, p=%p\n", tmp, q, p); red = tmp; green = index(tmp, ','); if (!green) { fprintf(stderr, "setColorValues: format error.\n"); free(area); onmemStrings--; /* String */ return NULL; } *green = '\0'; green++; blue = index(green, ','); if (!blue) { fprintf(stderr, "setColorValues: format errorl.\n"); free(area); onmemStrings--; /* String */ return NULL; } *blue = '\0'; blue++; //printf("red:{%s}, green:{%s}, blue:{%s}\n", red, green, blue); color->red = (red) ? atoi(red) : 0; color->green = (green) ? atoi(green) : 0; color->blue = (blue) ? atoi(blue) : 0; color->start = offset; color->end = offset + unit - 1; offset += unit; red = green = blue = NULL; // memset(tmp, 0, 128); color++; p = index(q + 1, '('); } if (offset - 1 != endpos) { fprintf(stderr, "!! There is a mismatch between color unit and start/end.\n"); fprintf(stderr, " ( whole range is [%d,%d], but last color unit is [%d,%d] )\n", startpos, endpos, offset - unit, offset - 1); } *colors = area; *num = tnum; return area; } /*****************************************************************************/ /* tokenに含まれる値を解釈して、グラフ値の配列として保持する。 */ /* [戻り値] 成功:値格納アドレス(*values) 失敗:NULL */ /* [引数] values: 値を格納する配列の先頭を指す変数のアドレス */ /* num: 解釈したグラフ値の個数を格納する領域のアドレス */ /* token: 解釈すべき文字列。"nums=1,1.2,3.14,0,1" の形。 */ /*****************************************************************************/ static EG_VALUE *setGraphValues(EG_VALUE **rvalues, int *num, char *token) { char *start; char *p; char *q; int tnum = 0; EG_VALUE *area; EG_VALUE *vpos; /* char tmp1[16]; char tmp2[16]; int tmplen; */ if (!token) { fprintf(stderr, "setGraphValues: invalid argument.\n"); return NULL; } /* tokenの内容の例: nums=99,9,99.0,999.0 */ start = index(token, '='); if (!start) { fprintf(stderr, "setGraphValues: format error. ('=' not found)\n"); return NULL; } /* 個数の数え上げとメモリ確保 */ /* tmplen = strlen(token); strncpy(tmp1, token, 15); tmp1[15] = '\0'; strncpy(tmp2, token + tmplen - 15, 15); tmp2[15] = '\0'; fprintf(stderr, "@@ token length: %d, [%s ... %s]\n", tmplen, tmp1, tmp2); */ p = start + 1; while ((q = index(p, ',')) != NULL) { tnum++; p = q + 1; } tnum++; area = (EG_VALUE *)calloc(tnum, sizeof(EG_VALUE)); if (!area) { fprintf(stderr, "setGraphValues: memory allocation error.\n"); return NULL; } onmemValues++; vpos = area; p = start + 1; while (p) { q = index(p, ','); if (q) *q = '\0'; *vpos = atof(p); vpos++; p = (q) ? q + 1 : NULL; } *num = tnum; *rvalues = area; //fprintf(stderr, "@@ found %d entries, copied from addr=%p to vpos=%p (%d bytes)\n", tnum, *rvalues, vpos, (vpos - area) * sizeof(EG_VALUE)); return *rvalues; } /*****************************************************************************/ /* tokenに含まれる値を解釈して、追加属性構造体の配列として保持する。 */ /* [戻り値] 成功:値格納アドレス(*optattrs) 失敗:NULL */ /* [引数] optattrs: 追加属性を格納する配列の先頭を指す変数のアドレス */ /* num: 解釈した追加属性の個数を格納する領域のアドレス */ /* size: 追加属性の格納用に確保した領域のサイズ(構造体の個数) */ /* token: 解釈すべき文字列。"name=value" の形。 */ /*****************************************************************************/ static OPTATTR *addOptAttr(OPTATTR **optattrs, int *num, int *size, char *token) { OPTATTR *curopt; char *p; if (!token || !num || !size || !optattrs) { fprintf(stderr, "addOptAttr: invalid argument.\n"); return NULL; } p = index(token, '='); if (!p) { fprintf(stderr, "addOptAttr: format error. ('=' is not found)\n"); return NULL; } if (!*optattrs) { *size = DEFAULT_OPT_ATTR_NUM; *optattrs = (OPTATTR *)calloc(*size, sizeof(OPTATTR)); if (!*optattrs) { fprintf(stderr, "addOptAttr: memory allocation error.\n"); *size = 0; return NULL; } onmemOptAttrs++; } else if (*size == 0 || *size == *num) { *size += DEFAULT_OPT_ATTR_NUM; *optattrs = (OPTATTR *)realloc(*optattrs, *size); if (!*optattrs) { fprintf(stderr, "addOptAttr: memory reallocation error.\n"); *size = 0; return NULL; } onmemOptAttrs++; } curopt = *optattrs; curopt += *num; *p = '\0'; strcpy(curopt->name, token); strcpy(curopt->value, p + 1); (*num)++; return curopt; } /*****************************************************************************/ /* EasyGeneTrackの1行目を解釈して指定の構造体に格納する */ /* [戻り値] 成功: 確保した構造体のアドレス, 失敗: NULL */ /* [引数] line : 行へのポインタ */ /*****************************************************************************/ EasyGeneTrack *parse_geneTrack_line(char *line) { EasyGeneTrack *genetrack; if (line == NULL) { fprintf(stderr, "parse_geneTrack_line: invalid argument.\n"); return NULL; } genetrack = (EasyGeneTrack *)malloc(sizeof(EasyGeneTrack)); if (!genetrack) { fprintf(stderr, "parse_geneTrack_line: memory allocation error.\n"); return NULL; } onmemEGeneTrackNum++; return genetrack; } /*****************************************************************************/ /* EasyGraphTrackの1行目を解釈して指定の構造体に格納する */ /* [戻り値] 成功: 確保した構造体のアドレス, 失敗: NULL */ /* [引数] line : 行へのポインタ */ /*****************************************************************************/ EasyGraphTrack *parse_graphTrack_line(char *line) { EasyGraphTrack *graphtrack; char *p; int attrcheck = 0; /* 1:graphTrack, 2:name, 4:species, 8:revision */ if (line == NULL) { fprintf(stderr, "parse_graphTrack_line: invalid argument.\n"); return NULL; } graphtrack = (EasyGraphTrack *)malloc(sizeof(EasyGraphTrack)); if (!graphtrack) { fprintf(stderr, "parse_graphTrack_line: memory allocation error.\n"); return NULL; } onmemEGraphTrackNum++; // フラグ用 graphtrack->color.red = -1; p = strtok(line, " \t\n"); while (p) { if (*p == '#') { break; } else if (strcmp(p, "graphTrack") == 0) { graphtrack->ettype = et_graphTrack; attrcheck += 1; } else if (strncmp(p, "name=", 5) == 0) { if (setStrValue(graphtrack->name, NAME_MAX_LEN, p)) { attrcheck += 2; } } else if (strncmp(p, "species=", 8) == 0) { if (setStrValue(graphtrack->species, NAME_MAX_LEN, p)) { attrcheck += 4; } } else if (strncmp(p, "revision=", 9) == 0) { if (setStrValue(graphtrack->revision, NAME_MAX_LEN, p)) { attrcheck += 8; } } else if (strncmp(p, "comment=", 8) == 0) { setStrValue(graphtrack->comment, COMMENT_MAX_LEN, p); } else if (strncmp(p, "description_url=", 16) == 0) { setStrValue(graphtrack->desc_url, URL_MAX_LEN, p); } else if (strncmp(p, "color=", 6) == 0) { setColorValue(&graphtrack->color, p); } else if (strncmp(p, "species_url=", 12) == 0) { setStrValue(graphtrack->species_url, URL_MAX_LEN, p); } else if (strncmp(p, "max=", 4) == 0) { setNumericValue(&graphtrack->max, p); } else if (strncmp(p, "min=", 4) == 0) { setNumericValue(&graphtrack->min, p); } else if (strncmp(p, "blend=", 6) == 0) { setBlendValue(&graphtrack->blend, p); } else if (strncmp(p, "date=", 5) == 0) { setStrValue(graphtrack->date, DATE_LEN, p); } else if (strncmp(p, "optattr=", 8) == 0) { setStrValue(graphtrack->optattr, ATTR_VALUE_MAX_LEN, p); } else { p = index(p, '='); } p = strtok(NULL, " \t\n"); } return graphtrack; } /*****************************************************************************/ /* EasyColorTrackの1行目を解釈して指定の構造体に格納する */ /* [戻り値] 成功: 確保した構造体のアドレス, 失敗: NULL */ /* [引数] line : 行へのポインタ */ /*****************************************************************************/ EasyColorTrack *parse_colorTrack_line(char *line) { EasyColorTrack *colortrack; char *p; int attrcheck = 0; /* 1:colorTrack, 2:name, 4:species, 8:revision */ if (line == NULL) { fprintf(stderr, "parse_colorTrack_line: invalid argument.\n"); return NULL; } colortrack = (EasyColorTrack *)malloc(sizeof(EasyColorTrack)); if (!colortrack) { fprintf(stderr, "parse_colorTrack_line: memory allocation error.\n"); return NULL; } onmemEColorTrackNum++; p = strtok(line, " \t\n"); while (p) { if (*p == '#') { break; } else if (strcmp(p, "colorTrack") == 0) { colortrack->ettype = et_colorTrack; attrcheck += 1; } else if (strncmp(p, "name=", 5) == 0) { if (setStrValue(colortrack->name, NAME_MAX_LEN, p)) { attrcheck += 2; } } else if (strncmp(p, "species=", 8) == 0) { if (setStrValue(colortrack->species, NAME_MAX_LEN, p)) { attrcheck += 4; } } else if (strncmp(p, "revision=", 9) == 0) { if (setStrValue(colortrack->revision, NAME_MAX_LEN, p)) { attrcheck += 8; } } else if (strncmp(p, "comment=", 8) == 0) { setStrValue(colortrack->comment, COMMENT_MAX_LEN, p); } else if (strncmp(p, "description_url=", 16) == 0) { setStrValue(colortrack->desc_url, URL_MAX_LEN, p); } else if (strncmp(p, "species_url=", 12) == 0) { setStrValue(colortrack->species_url, URL_MAX_LEN, p); } else if (strncmp(p, "blend=", 6) == 0) { setBlendValue(&colortrack->blend, p); } else if (strncmp(p, "date=", 5) == 0) { setStrValue(colortrack->date, DATE_LEN, p); } else if (strncmp(p, "optattr=", 8) == 0) { setStrValue(colortrack->optattr, ATTR_VALUE_MAX_LEN, p); } else { p = index(p, '='); } p = strtok(NULL, " \t\n"); } return colortrack; } /*****************************************************************************/ /* EasyGeneTrackのgene行目を解釈して指定の構造体に格納する */ /* [戻り値] 成功: 確保した構造体のアドレス, 失敗: NULL */ /* [引数] line : 行へのポインタ */ /*****************************************************************************/ EasyGene *parse_gene_line(char *line) { EasyGene *easygene; easygene = (EasyGene *)malloc(sizeof(EasyGene)); if (!easygene) { fprintf(stderr, "parse_gene_line: memory allocation error.\n"); return NULL; } onmemEGeneNum++; memset(easygene, 0, sizeof(EasyGene)); return easygene; } /*****************************************************************************/ /* EasyGraphTrackのgraph行目を解釈して指定の構造体に格納する */ /* [戻り値] 成功: 確保した構造体のアドレス, 失敗: NULL */ /* [引数] line : 行へのポインタ */ /*****************************************************************************/ EasyGraph *parse_graph_line(char *line) { EasyGraph *easygraph; char *p; easygraph = (EasyGraph *)malloc(sizeof(EasyGraph)); if (!easygraph) { fprintf(stderr, "parse_graph_line: memory allocation error.\n"); return NULL; } onmemEGraphNum++; memset(easygraph, 0, sizeof(EasyGraph)); p = strtok(line, " \t\n"); while (p) { if (*p == '#') { break; } else if (strncmp(p, "graph", 5) == 0) { ; } else if (strncmp(p , "target=", 7) == 0) { setStrValue(easygraph->target, NAME_MAX_LEN, p); } else if (strncmp(p, "range=", 6) == 0) { setRange(&easygraph->start, &easygraph->end, p); } else if (strncmp(p, "unit=", 5) == 0) { setUnit(&easygraph->unit, p); } else if (strncmp(p, "nums=", 5) == 0) { setGraphValues(&easygraph->values, &easygraph->valuenum, p); } else if (strncmp(p, "url=", 4) == 0) { setStrValue(easygraph->url, URL_MAX_LEN, p); } else if (strncmp(p, "color=", 5) == 0) { //setColorValue(&easygraph->color, p); ; } else { //addOptAttr(&easygraph->optattrs, &easygraph->optnum, // &easygraph->optareanum, p); ; } p = strtok(NULL, " \t\n"); } return easygraph; } /*****************************************************************************/ /* EasyColorTrackのcolor行目を解釈して指定の構造体に格納する */ /* [戻り値] 成功: 確保した構造体のアドレス, 失敗: NULL */ /* [引数] line : 行へのポインタ */ /*****************************************************************************/ EasyColor *parse_color_line(char *line) { EasyColor *easycolor; char *p; easycolor = (EasyColor *)malloc(sizeof(EasyColor)); if (!easycolor) { fprintf(stderr, "parse_color_line: memory allocation error.\n"); return NULL; } onmemEColorNum++; memset(easycolor, 0, sizeof(EasyColor)); p = strtok(line, " \t\n"); while (p) { if (*p == '#') { break; } else if (strncmp(p, "target=", 7) == 0) { setStrValue(easycolor->target, NAME_MAX_LEN, p); } else if (strncmp(p, "range=", 6) == 0) { setRange(&easycolor->start, &easycolor->end, p); } else if (strncmp(p, "unit=", 5) == 0) { setUnit(&easycolor->unit, p); } else if (strncmp(p, "colors=", 7) == 0) { setColorValues(&easycolor->colors, &easycolor->colornum, (int)easycolor->start, (int)easycolor->end, (int)easycolor->unit, p); } else if (strncmp(p, "url=", 4) == 0) { setStrValue(easycolor->url, URL_MAX_LEN, p); } else if (strncmp(p, "color", 5) == 0) { ; } else { addOptAttr(&easycolor->optattrs, &easycolor->optnum, &easycolor->optareanum, p); } p = strtok(NULL, " \t\n"); } return easycolor; } /*****************************************************************************/ /* 与えられた文字列が、正しく浮動小数を表しているかチェックする。 */ /* [戻り値] 正常: 1 不正: 0 */ /* 説明: [符号][整数部][.小数部][e[符号][仮数部]] の形なら正常 */ /* 例) 正常: 1, 0.1, -1, .2, 1e-1など 不正: 0x01, a01, abc, 1e0.1など */ /*****************************************************************************/ int isfloat(char *str) { int ret = 1; char *p; char *ep = NULL; /* 'e'の位置を示すポインタ */ char *fp = NULL; /* 最後の符号の位置を示すポインタ */ char *pp = NULL; /* 小数点の位置を示すポインタ */ char *dp = NULL; /* 最後の数字の位置を表すポインタ */ p = str; while (p && *p != '\0') { switch (*p) { case '+': case '-': if (fp && !ep) return 0; /* 実数部の中で2つ目の符号が来た */ if (p != str && p != ep + 1) return 0; /* 先頭か'e'の直後以外に来た */ fp = p; break; case '.': if (pp) return 0; /* 2つ目の小数点 */ if (ep) return 0; /* 仮数部に小数点が来た */ pp = p; break; case 'e': case 'E': if (ep) return 0; /* 2つ目の'e'または'E' */ ep = p; break; default: if (!isdigit(*p)) return 0; /* 数字以外 */ dp = p; } p++; } if (!dp) return 0; /* 数字が1個も無い */ return ret; }