OPD *opdtok(const char *str) { OPD *opd = malloc_chk(sizeof(OPD), "opd"); char *p, *q, *r, *sepp; /* pは文字列全体の先頭位置、qはトークンの先頭位置、rは文字の位置 */ int sepc = ',', rcnt = 0; bool quoting = false; opd->opdc = 0; if(str == NULL) { return opd; } p = q = r = strdup_chk(str, "opdtok.p"); do { /* オペランド数が多すぎる場合はエラー */ if(opd->opdc >= OPDSIZE) { setcerr(117, ""); /* operand is too many */ break; } /* 先頭が等号(=)の場合 */ if(*r == '=') { r++; } /* 「'」の場合 */ if(*r == '\'') { /* 「''」以外の場合はquote値を反転 */ if(*(r+1) != '\'' && !(q < r && *(r-1) == '\'')) { quoting = !quoting; } /* 文字列の長さを数える。「'」の場合は数えない */ if(*(r+1) != '\'') { rcnt++; } } if(quoting == true) { /* 閉じ「'」がないまま文字列が終了した場合 */ if(*r == '\0') { setcerr(123, str); /* unclosed quote */ break; } r++; } else { sepp = r + strcspn(r, ", "); sepc = *sepp; *sepp = '\0'; if(*q == '\0') { setcerr(121, ""); /* cannot get operand token */ break; } if(strlen(q) - rcnt > OPDSIZE) { setcerr(118, ""); /* operand length too long */ break; } opd->opdv[(++opd->opdc)-1] = strdup_chk(q, "opd.opdv[]"); q = r = sepp + 1; rcnt = 0; } } while(sepc == ','); FREE(p); return opd; }
char *strdup_chk(const char *s, const char *tag) { assert(s != NULL); char *t = malloc_chk(strlen(s) + 1, tag); strcpy(t, s); return t; }
void addcerrlist(int cerrc, CERR cerrv[]) { int i; CERRLIST *p = NULL, *q = malloc_chk(sizeof(CERRLIST), "cerrlist"); assert(cerrc > 0 && cerrv != NULL); for(i = 0; i < cerrc; i++) { if(p == NULL) { p = q; } else { p = p->next = malloc_chk(sizeof(CERRLIST), "cerrlist.next"); } p->cerr = &cerrv[i]; p->next = NULL; } p->next = cerrlist; cerrlist = q; }
void setcerr(int num, const char *str) { /* 現在のエラー番号を設定 */ cerr->num = num; /* 現在のエラーメッセージを設定 */ cerr->msg = malloc_chk(CERRMSGSIZE + 1, "cerr.msg"); if(0 < strlen(str) && strlen(str) <= CERRSTRSIZE) { sprintf(cerr->msg, "%s: %s", str, getcerrmsg(cerr->num)); } else { strcpy(cerr->msg, getcerrmsg(cerr->num)); } }
char *strndup_chk(const char *s, size_t len, const char *tag) { assert(s != NULL); char *t = NULL; if(len < strlen(s)) { t = malloc_chk(len + 1, tag); strncpy(t, s, len); t[len] = '\0'; } else { t = strdup_chk(s, tag); } return t; }
int main(){ int i, j; int code[] = { 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 201, 202, 203, 204, 205, 206, 207, 999 }; const char *str[] = {NULL, "foobar"}; addcerrlist(ARRAYSIZE(cerr_utest), cerr_utest); /* エラーの初期化 */ cerr = malloc_chk(sizeof(CERR), "cerr"); for(i = 0; i < ARRAYSIZE(str); i++) { for(j = 0; j < ARRAYSIZE(code); j++) { setcerr(code[j], str[i]); printf("%d: %s - %d\t%s\n", code[j], str[i], cerr->num, cerr->msg); } } freecerr(); return 0; }
void cerr_init() { cerr = malloc_chk(sizeof(CERR), "cerr"); cerr->num = 0; }
errCode genTextures(const char *rootDir, const sFileList *files, sTex ***dynarrTextures){ static const size_t BUFFLEN = 1024; int numTexs=0; int idxFile = files->num; sTex *refTex; if(idxFile <= 0 || rootDir == NULL || rootDir[0] == '\0' || dynarrTextures == NULL) return PROBLEM; size_t lenRootDir = strlen(rootDir); char filePath[BUFFLEN]; FILE *handFile; png_byte header[PNGHEAD_SIZE]; strncpy(filePath, rootDir, 1024); if(lenRootDir>0 && filePath[lenRootDir-1]!='/'){ filePath[lenRootDir] = '/'; lenRootDir += 1; } while(idxFile > 0){ --idxFile; strncpy(&filePath[lenRootDir], files->dynarrFiles[idxFile], 1024 - lenRootDir); handFile = fopen(filePath, "rb"); if(handFile == NULL){ WARN("Can't open file %s", filePath); continue; } if( fread(header, sizeof(png_byte), PNGHEAD_SIZE, handFile) == PNGHEAD_SIZE && png_sig_cmp(header, 0, PNGHEAD_SIZE) == 0 ){ XTRA_LOG("File %s opened as PNG", filePath); }else{ WARN("File %s isn't a PNG", filePath); fclose(handFile); continue; } ++numTexs; (*dynarrTextures) = (sTex**)realloc_chk((*dynarrTextures), (numTexs+1) * sizeof(sTex*)); (*dynarrTextures)[numTexs]=NULL; refTex = (*dynarrTextures)[numTexs-1] = (sTex*)malloc_chk(sizeof(sTex)); memset(refTex, 0, sizeof(sTex)); refTex->pngptrData = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, &myPNGWarnFoo ); if(refTex->pngptrData == NULL){ WARN("Unable to create png struct"); fclose(handFile); continue; } if(setjmp(png_jmpbuf(refTex->pngptrData)) != 0){ /** jumps here on errors. */ cleanupPNGImg( refTex->pngptrData, &refTex->dynarrRows ); png_destroy_read_struct( &(refTex->pngptrData), &(refTex->pngptrInfo), NULL ); refTex->h = refTex->w = 0; }else{ refTex->pngptrInfo = png_create_info_struct( refTex->pngptrData ); if(refTex->pngptrInfo == NULL){ WARN("Unable to create png info struct"); fclose(handFile); continue; } /** setup PNG decode */ png_init_io(refTex->pngptrData, handFile); png_set_sig_bytes(refTex->pngptrData, PNGHEAD_SIZE); png_read_info(refTex->pngptrData, refTex->pngptrInfo); png_byte colorCurrent = png_get_color_type( refTex->pngptrData, refTex->pngptrInfo ); png_set_filler(refTex->pngptrData, 0, PNG_FILLER_AFTER); png_set_packing(refTex->pngptrData); /** if < 8 bits */ { png_color_8p sig_bit; if (png_get_sBIT(refTex->pngptrData, refTex->pngptrInfo, &sig_bit)) png_set_shift(refTex->pngptrData, sig_bit); } switch(colorCurrent){ case PNG_COLOR_TYPE_RGB_ALPHA: /** already good */ break; case PNG_COLOR_TYPE_RGB: png_set_tRNS_to_alpha(refTex->pngptrData); break; case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb( refTex->pngptrData ); png_set_tRNS_to_alpha(refTex->pngptrData); break; case PNG_COLOR_TYPE_GRAY: png_set_expand_gray_1_2_4_to_8( refTex->pngptrData ); png_set_tRNS_to_alpha(refTex->pngptrData); break; default: WARN("unsupported colour"); break; } png_read_update_info(refTex->pngptrData, refTex->pngptrInfo); colorCurrent = png_get_color_type( refTex->pngptrData, refTex->pngptrInfo ); if(colorCurrent != PNG_COLOR_TYPE_RGB_ALPHA){ printf("<warning> %s didn't convert to the right colour type\n", files->dynarrFiles[idxFile]); png_destroy_read_struct(&refTex->pngptrData, &refTex->pngptrInfo, (png_infopp)NULL); fclose(handFile); continue; } refTex->colorType = colorCurrent; const int numPasses = png_set_interlace_handling( refTex->pngptrData ); /** setup other data */ copyString(&refTex->name, files->dynarrFiles[idxFile]); /** setup texture */ unsigned int row; const png_uint_32 sizeRow = png_get_rowbytes( refTex->pngptrData, refTex->pngptrInfo ); refTex->w = png_get_image_width( refTex->pngptrData, refTex->pngptrInfo ); refTex->h = png_get_image_height( refTex->pngptrData, refTex->pngptrInfo ); if(sizeRow/refTex->w != DEFAULT_BYTE_PP){ WARN("%s didn't convert to the right bit depth", refTex->name); png_destroy_read_struct(&refTex->pngptrData, &refTex->pngptrInfo, (png_infopp)NULL); fclose(handFile); continue; } refTex->dynarrRows = calloc_chk((refTex->h +1), sizeof(png_byte*)); refTex->dynarrRows[refTex->h] = NULL; for(row = 0; row < refTex->h; ++row) refTex->dynarrRows[row] = png_malloc(refTex->pngptrData, sizeRow); unsigned int pass; for(pass=0; pass < numPasses; ++pass){ for(row = 0; row < refTex->h; ++row){ png_read_rows( refTex->pngptrData, &refTex->dynarrRows[row], NULL, 1 ); } } png_read_end(refTex->pngptrData, refTex->pngptrInfo); } fclose(handFile); } return NOPROB; }
errCode arrangeTextures( sTex **arrTexs, sSeqList *pSeqs, sStillList *pStills, sFontList *pFonts, sSheetList *pOutSheets, unsigned int maxSquare ){ unsigned int curW, curH; int idxFit; bool makeSheet, freshSheet; unsigned int curSeq, curStill, curFrame, curFont; sTex *curTex; sSheet *curSheet; sTexSeq *refSeq; sSquare *refSqr; sFont *refFnt; unsigned int *dynarrSeqIdxs; unsigned int *dynarrPrevFrame; /** If not -1, we're trying to split an animation over multiple sheets */ unsigned int *dynarrStillIdxs; unsigned int *dynarrFontIdxs; if(pSeqs == NULL || pStills == NULL || pFonts == NULL) return ERROR; /** Arrays used to keep track of things that still need assigning */ if(pSeqs->num > 0){ dynarrSeqIdxs = calloc_chk(pSeqs->num, sizeof(unsigned int)); dynarrPrevFrame = calloc_chk(pSeqs->num, sizeof(unsigned int)); unsigned int i; for(i=0; i < pSeqs->num; ++i){ dynarrSeqIdxs[i] = i; dynarrPrevFrame[i] = (unsigned int)-1; } }else{ dynarrSeqIdxs = NULL; dynarrPrevFrame = NULL; } if(pStills->num > 0){ dynarrStillIdxs = calloc_chk(pStills->num, sizeof(unsigned int)); unsigned int i; for(i=0; i < pStills->num; ++i) dynarrStillIdxs[i] = i; }else{ dynarrStillIdxs = NULL; } if(pFonts->num > 0){ dynarrFontIdxs = calloc_chk(pFonts->num, sizeof(unsigned int)); unsigned int i; for(i=0; i < pFonts->num; ++i) dynarrFontIdxs[i] = 0; }else{ dynarrFontIdxs = NULL; } /** Main arrangement stuff */ do{ sListSquares holes; memset(&holes, 0, sizeof(sListSquares)); ++pOutSheets->num; pOutSheets->dynarrSheets = realloc_chk( pOutSheets->dynarrSheets, pOutSheets->num * sizeof(sSheet*) ); curSheet = malloc_chk(sizeof(sSheet)); memset(curSheet, 0, sizeof(sSheet)); pOutSheets->dynarrSheets[ pOutSheets->num -1 ] = curSheet; makeSheet = FALSE; freshSheet = TRUE; curSeq =curStill =curFont =0; /** retry all the differed stills and sequences*/ curW =curH =0; XTRA_LOG("Making sheet %i", (int)pOutSheets->num); while(makeSheet==FALSE && (dynarrSeqIdxs != NULL || dynarrStillIdxs != NULL || dynarrFontIdxs != NULL) ){ const bool endOfSeqs = (curSeq < pSeqs->num) ? FALSE : TRUE; const bool endOfStills = (curStill < pStills->num) ? FALSE : TRUE; const bool endOfFonts = (curFont < pFonts->num) ? FALSE : TRUE; //consolidate(&holes); /** a bit broken */ if(dynarrSeqIdxs != NULL && endOfSeqs == FALSE){ if(dynarrSeqIdxs[curSeq] != (unsigned int)-1){ refSeq = &(pSeqs->dynarrSeqs[ dynarrSeqIdxs[curSeq] ]); if(refSeq->num > 0){ /** See if the entire sequence can fit first. */ { sListSquares tmpHoles; memset(&tmpHoles, 0, sizeof(sListSquares)); XTRA_LOG("Probing sheet"); copySquares(&tmpHoles, &holes); if(dynarrPrevFrame[curSeq] != (unsigned int)-1) curFrame = dynarrPrevFrame[curSeq]; else curFrame = 0; idxFit = (unsigned int)-1; while(curFrame < refSeq->num){ curTex = arrTexs[ refSeq->dynarrTexIDs[curFrame] ]; if(curTex->w > maxSquare || curTex->h > maxSquare){ /** We can't do much else here besides bomb out, because we can't mark the texture as a dud here. */ ERROR_LOG("arrangeTextures: Texture %s is too large for the max texture size.", curTex->name); cleanupListSquares(&holes); cleanupListSquares(&tmpHoles); goto arrangeTextures_fail; } idxFit = fitNFillSquare(&tmpHoles, curTex->w, curTex->h, maxSquare, maxSquare); if(idxFit < 0) break; ++curFrame; } cleanupListSquares(&tmpHoles); XTRA_LOG("Done with probe"); } if(idxFit >= 0 || freshSheet == TRUE){ refSeq->dynarrSheetIDs = calloc_chk(refSeq->num, sizeof(unsigned int)); if(dynarrPrevFrame[curSeq] != (unsigned int)-1) curFrame = dynarrPrevFrame[curSeq]; else curFrame = 0; while(curFrame < refSeq->num){ curTex = arrTexs[ refSeq->dynarrTexIDs[curFrame] ]; idxFit = fitNFillSquare(&holes, curTex->w, curTex->h, maxSquare, maxSquare); if(idxFit >= 0){ refSqr = &(holes.dynarrSquares[idxFit]); refSeq->dynarrSheetIDs[curFrame] = (unsigned int)(pOutSheets->num -1); curTex->x = refSqr->x; curTex->y = refSqr->y; ++curSheet->num; curSheet->dynarrTexIDs = realloc_chk( curSheet->dynarrTexIDs, curSheet->num *sizeof(unsigned int) ); curSheet->dynarrTexIDs[curSheet->num -1] = refSeq->dynarrTexIDs[curFrame]; freshSheet = FALSE; }else{ /** Try again on a fresh sheet. */ dynarrPrevFrame[curSeq] = curFrame; break; } ++curFrame; } } }else{ curFrame = 0; } if(curFrame == refSeq->num) /** success */ dynarrPrevFrame[curSeq] = dynarrSeqIdxs[curSeq] = (unsigned int)-1; } ++curSeq; }else if(dynarrStillIdxs != NULL && endOfStills == FALSE){ if(dynarrStillIdxs[curStill] != (unsigned int)-1){ curTex = arrTexs[ pStills->dynarrTexIDs[ dynarrStillIdxs[curStill] ] ]; if(pStills->dynarrSheetIDs == NULL) pStills->dynarrSheetIDs = calloc_chk(pStills->num, sizeof(unsigned int)); if(curTex->w > maxSquare || curTex->h > maxSquare){ /** We can't do much else here besides bomb out, because we can't mark the texture as a dud here. */ ERROR_LOG("arrangeTextures: Texture %s is too large for the max texture size.", curTex->name); cleanupListSquares(&holes); goto arrangeTextures_fail; } idxFit = fitNFillSquare(&holes, curTex->w, curTex->h, maxSquare, maxSquare); if(idxFit >= 0){ refSqr = &(holes.dynarrSquares[idxFit]); curTex->x = refSqr->x; curTex->y = refSqr->y; pStills->dynarrSheetIDs[curStill] = (unsigned int)(pOutSheets->num -1); curSheet->dynarrTexIDs = realloc_chk( curSheet->dynarrTexIDs, (curSheet->num +1) * sizeof(unsigned int) ); curSheet->dynarrTexIDs[curSheet->num] = pStills->dynarrTexIDs[ dynarrStillIdxs[curStill] ]; ++curSheet->num; freshSheet = FALSE; dynarrStillIdxs[curStill] = (unsigned int)-1; }else if(freshSheet == TRUE){ ERROR_LOG("Unable to fit still"); goto arrangeTextures_fail; } } ++curStill; }else if(dynarrFontIdxs != NULL && endOfFonts == FALSE){ if(dynarrFontIdxs[curFont] != (unsigned int)-1){ unsigned int idxGlyph; refFnt = pFonts->dynarrFonts[curFont]; idxFit = (unsigned int)-1; { /** probe sheet */ sListSquares tmpHoles; memset(&tmpHoles, 0, sizeof(sListSquares)); XTRA_LOG("Probing sheet"); copySquares(&tmpHoles, &holes); for(idxGlyph= dynarrFontIdxs[curFont]; idxGlyph < refFnt->num; ++idxGlyph){ curTex = arrTexs[ refFnt->dynarrTexIDs[idxGlyph] ]; idxFit = fitNFillSquare(&tmpHoles, curTex->w, curTex->h, maxSquare, maxSquare); if(idxFit < 0) break; } cleanupListSquares(&tmpHoles); XTRA_LOG("Done with probe"); } if(idxFit >= 0 || freshSheet == TRUE){ unsigned int i = dynarrFontIdxs[curFont]; while(dynarrFontIdxs[curFont] < idxGlyph){ curTex = arrTexs[ refFnt->dynarrTexIDs[ dynarrFontIdxs[curFont] ] ]; idxFit = fitNFillSquare(&holes, curTex->w, curTex->h, maxSquare, maxSquare); if(idxFit < 0){ ERROR_LOG("Unable to fit font, somehow?"); goto arrangeTextures_fail; } refSqr = &(holes.dynarrSquares[idxFit]); curTex->x = refSqr->x; curTex->y = refSqr->y; ++dynarrFontIdxs[curFont]; } if(dynarrFontIdxs[curFont] -i > 0){ unsigned int numPrev = curSheet->num; refFnt->dynarrSheetIDs = realloc_chk( refFnt->dynarrSheetIDs, dynarrFontIdxs[curFont] *sizeof(unsigned int) ); unsigned int s; for(s=i; s < dynarrFontIdxs[curFont]; ++s) refFnt->dynarrSheetIDs[s] = (unsigned int)(pOutSheets->num -1); curSheet->num += dynarrFontIdxs[curFont] -i; curSheet->dynarrTexIDs = realloc_chk( curSheet->dynarrTexIDs, curSheet->num *sizeof(unsigned int) ); memcpy( &curSheet->dynarrTexIDs[numPrev], &refFnt->dynarrTexIDs[i], (curSheet->num -numPrev) *sizeof(unsigned int) ); }else{ WARN("fonts not added to sheet"); } if(dynarrFontIdxs[curFont] == refFnt->num) dynarrFontIdxs[curFont] = (unsigned int)-1; freshSheet = FALSE; } } ++curFont; }else{ /** Check if we need to make another sheet, and cleanup any arrays that are finished. */ if(dynarrSeqIdxs != NULL && endOfSeqs == TRUE){ for(curSeq=0; curSeq < pSeqs->num; ++curSeq){ if(dynarrSeqIdxs[curSeq] != (unsigned int)(-1)) break; } if(curSeq == pSeqs->num){ SAFE_DELETE(dynarrSeqIdxs); SAFE_DELETE(dynarrPrevFrame); }else{ makeSheet = TRUE; } } if(dynarrFontIdxs != NULL && endOfFonts == TRUE){ for(curFont=0; curFont < pFonts->num; ++curFont){ if(dynarrFontIdxs[curFont] != (unsigned int)-1) break; } if(curFont == pFonts->num){ SAFE_DELETE(dynarrFontIdxs); }else{ makeSheet = TRUE; } } if(dynarrStillIdxs != NULL && endOfStills == TRUE){ for(curStill=0; curStill < pStills->num; ++curStill){ if(dynarrStillIdxs[curStill] != (unsigned int)(-1)) break; } if(curStill == pStills->num){ SAFE_DELETE(dynarrStillIdxs); }else{ makeSheet = TRUE; } } } /** keep the sheet up to date. */ curSheet->w = holes.boundryW; curSheet->h = holes.boundryH; } cleanupListSquares(&holes); }while(makeSheet==TRUE); if(dynarrStillIdxs != NULL || dynarrSeqIdxs != NULL){ ERROR_LOG("Didn't cleanup memory"); return ERROR; } return NOPROB; arrangeTextures_fail: SAFE_DELETE(dynarrSeqIdxs); SAFE_DELETE(dynarrStillIdxs); SAFE_DELETE(dynarrPrevFrame); return ERROR; }
CMDLINE *linetok(const char *line) { char *tokens, *p, *sepp; bool quoting = false; CMDLINE *cmdl = NULL; if(*line == '\0') { return NULL; } tokens = strdup_chk(line, "tokens"); /* コメントを削除 */ for(p = tokens; *p != '\0'; p++) { /* 「'」で囲まれた文字列の処理。「''」は無視 */ if(*p == '\'' && *(p+1) != '\'' && !(p > tokens && *(p-1) == '\'')) { quoting = !quoting; } else if(quoting == false && *p == ';') { *p = '\0'; break; } } if(*tokens != '\n' && *tokens != '\0') { p = tokens; cmdl = malloc_chk(sizeof(CMDLINE), "cmdl"); cmdl->label = malloc_chk(LABELSIZE + 1, "cmdl.label"); /* ラベルの取得。行の先頭が空白またはタブの場合、ラベルは空 */ if((sepp = p + strcspn(p, " \t\n")) == p){ *(cmdl->label) = '\0'; } else { /* ラベルを取得 */ *sepp = '\0'; /* 文字列が長すぎる場合はエラー */ if(strlen(p) > LABELSIZE) { setcerr(104, p); /* label length is too long */ } else { strcpy(cmdl->label, p); } p = sepp + 1; } /* ラベルと命令の間の空白をスキップ */ while(*p == ' ' || *p == '\t') { p++; } /* 命令とオペランドの取得 */ if(*p == '\n' || *p == '\0') { /* 命令がない場合は、終了 */ if(*(cmdl->label) != '\0') { /* ラベルが定義されていて命令がない場合はエラー */ setcerr(105, ""); /* no command in the line */ } FREE(cmdl->label); FREE(cmdl); } else { /* 命令の取得 */ sepp = p + strcspn(p, " \t\n"); *sepp = '\0'; cmdl->cmd = strdup_chk(p, "cmdl.cmd"); p = sepp + 1; /* 命令とオペランドの間の空白をスキップ */ while(*p == ' ' || *p == '\t') { p++; } /* 改行かタブまでの文字列を取得 */ /* 「'」で囲まれた文字列に含まれる場合があるため、空白は無視 */ if((sepp = p + strcspn(p, "\t\n")) > p) { *sepp = '\0'; cmdl->opd = opdtok(p); } else { cmdl->opd = malloc_chk(sizeof(OPD), "cmdl.opd"); cmdl->opd->opdc = 0; } } } FREE(tokens); return cmdl; }