ref: 516fc276f112baf0bd4508596598aed49929bde9
dir: /src/sbconfig.c/
/* Copyright (C) 1994-1995 Apogee Software, Ltd. Copyright (C) 2002-2015 icculus.org, GNU/Linux port Copyright (C) 2017-2018 Steven LeVesque This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ /* Copyright 1995 Spacetec IMC Corporation */ #if defined(__BORLANDC__) # pragma inline #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <dos.h> typedef long fixed; #include "rt_def.h" #include "develop.h" #include "sbconfig.h" /* ----------------------------------------------------------------------- */ #define DEFAULT_CONFIG_FILENAME "sbconfig.dat" #define NUM_ELEMENTS(x) (sizeof(x)/sizeof(x[0])) #define SIGN(x) ((x<0)?-1:1) /* ----------------------------------------------------------------------- */ #if defined(__BORLANDC__) fixed FIXED_MUL(fixed a, fixed b) { fixed ret_code; asm { mov eax,a mov edx,b imul edx shrd eax,edx,16 mov ret_code,eax } return ret_code; } #elif defined(_MSC_VER) /* Microsoft C7.0 can not be done with inline assembler because it can not handle 32-bit instructions */ fixed FIXED_MUL(fixed a,fixed b) { fixed sgn,ah,al,bh,bl; sgn = (SIGN(a) ^ SIGN(b)) ? -1 : 1 ; ah = (a >> 16) & 0xffff ; al = (a & 0xffff); bh = (b >> 16) & 0xffff ; bl = (b & 0xffff); return sgn * ( ((al*bl)>>16) + (ah*bl) + (al*bh) + ((ah*bh)<<16) ); } #endif /* definition of inline FIXED_MUL */ static fixed StrToFx1616(char *string, char **ret_string) { long whole; long fract; fixed result; int sign; /* Skip whitespace */ while((*string==' ')||(*string=='\t')||(*string=='\n')) string++; /* Accept numbers in the form: [+-]?[0-9]+(.[0-9]*) */ sign=1; if(*string=='-') { string++; sign=-1; } else if(*string=='+') { string++; sign=1; } /* Read in the whole part */ whole=0; while((*string>='0')&&(*string<='9')) whole=whole*10+(*string++)-'0'; /* Read the optional fraction part */ fract=0; if(*string=='.') { long place=1; string++; while((*string>='0')&&(*string<='9')) { fract=fract*10+(*string++)-'0'; place*=10; } /* Convert to fixed point */ fract=(fract<<16)/place; } if(ret_string) *ret_string=string; if(sign==1) result= (whole<<16) + fract; else result=-(whole<<16) + fract; return result; } /* ----------------------------------------------------------------------- */ static char *SbButtonNames[]= { "BUTTON_A", "BUTTON_B", "BUTTON_C", "BUTTON_D", "BUTTON_E", "BUTTON_F" }; static int cfgFileVersion=0; static char cfgButtons[NUM_ELEMENTS(SbButtonNames)][MAX_STRING_LENGTH]; static WarpRecord *pCfgWarps; static int nCfgWarps=0; /*-------------------------------------------------------------------------*/ /* Read a string in the form: "{#, #, #}" * and return a pointer to the character AFTER the '}' * or NULL if error */ static char *GetWarpLevels(char *string, WarpRange *pw) { short value; fixed fxvalue; if((*string++)!='{') return NULL; if(!*string) return NULL; /* Expecting the first number - low */ value=(short)strtol(string, &string, 0); if(pw) pw->low=value; /* Skip any whitespace */ while(isspace(*string)) string++; if(*string++!=',') return NULL; /* Expecting the second number - high */ value=(short)strtol(string, &string, 0); if(pw) pw->high=value; /* Skip any whitespace */ while(isspace(*string)) string++; if(*string++!=',') return NULL; /* Expecting the third number - multiplier */ fxvalue=StrToFx1616(string, &string); if(pw) pw->mult=fxvalue; /* Skip any whitespace */ while(isspace(*string)) string++; if(*string!='}') return NULL; return string+1; } static int GetWarp(char *string, WarpRecord *pRecord) { int nWarp; WarpRange *pWarp; /* Only update the field if we successfully read the entire line */ nWarp=0; pWarp=NULL; /* Skip whitespace */ while(isspace(*string)) string++; if(*string++!='{') return 0; while(string && *string) { switch(*string) { case ' ': case '\t': case '\n': string++; break; case ',': string++; break; case '{': if(nWarp++==0) pWarp=malloc(sizeof(WarpRange)); else pWarp=realloc(pWarp, nWarp*sizeof(WarpRange)); string=GetWarpLevels(string, pWarp+nWarp-1); break; case '}': pRecord->nWarp=nWarp; pRecord->pWarp=pWarp; return 1; } } /* Early EOL (didn't get closing '}') */ if(nWarp) free(pWarp); return 0; } /*-------------------------------------------------------------------------*/ int SbConfigParse(char *_filename) { int i; FILE *file; char *pc; char buffer[128]; char filename[MAX_PATH]; if(!_filename) _filename=DEFAULT_CONFIG_FILENAME; strncpy(filename, _filename, sizeof (filename)); filename[sizeof (filename) - 1] = '\0'; FixFilePath(filename); if(!(file=fopen(filename, "r"))) { printf("Config file: %s, not found\n", filename); return 0; } while(fgets(buffer, sizeof(buffer), file)) { int lineParsed=0; /* each line in config file starts with either a ;, VERSION or an ** element of GameButtonNames or WarpNames */ pc=strtok(buffer, " \t\n,"); if(*pc==';') /* commented out line? */ continue; /* VERSION? The version will be used in the future to allow fx1616 ** values in the config file */ if(!stricmp(pc,"VERSION")) { pc=strtok(NULL, " \t\n,"); cfgFileVersion=atoi(pc); } /* Check if first token is an element of SbButtonNames */ for(i=0; i<NUM_ELEMENTS(SbButtonNames); i++) if(!stricmp(pc, SbButtonNames[i])) { lineParsed=1; /* Save the next token in the appropriate slot */ pc=strtok(NULL," \t\n,"); strncpy(cfgButtons[i], pc, MAX_STRING_LENGTH-1); cfgButtons[i][MAX_STRING_LENGTH-1]=0; } /* If the first token is not from GameButtonNames, ** it must be a WarpName */ if(!lineParsed) { char *name; name=pc; pc=pc+strlen(pc)+1; /* Skip this token */ while(isspace(*pc)) pc++; /* Skip any whitespace */ if(*pc=='{') { WarpRecord warpRec; strcpy(warpRec.name, name); warpRec.pWarp=NULL; warpRec.nWarp=0; if(GetWarp(pc, &warpRec)) { if(nCfgWarps++==0) pCfgWarps=(WarpRecord *)malloc(sizeof(WarpRecord)); else pCfgWarps=(WarpRecord *)realloc(pCfgWarps, nCfgWarps*sizeof(WarpRecord)); pCfgWarps[nCfgWarps-1]=warpRec; } } } } /* end of while getting lines from config file */ fclose(file); return 1; } /*-------------------------------------------------------------------------*/ char *SbConfigGetButton(char *btnName) { int i; for(i=0; i<NUM_ELEMENTS(SbButtonNames); i++) { if(!stricmp(btnName, SbButtonNames[i])) if(cfgButtons[i][0]) return cfgButtons[i]; else return NULL; /* Empty slot */ if(!stricmp(btnName, cfgButtons[i])) return SbButtonNames[i]; } /* Unknown button name */ return NULL; } int SbConfigGetButtonNumber(char *btnName) { int i; for(i=0; i<NUM_ELEMENTS(SbButtonNames); i++) { if(!stricmp(btnName, cfgButtons[i])) return i; } /* Unknown button name */ return -1; } /*-------------------------------------------------------------------------*/ WarpRecord *SbConfigGetWarpRange(char *rngName) { int i; for(i=0; i<nCfgWarps; i++) if(!stricmp(rngName, pCfgWarps[i].name)) return &pCfgWarps[i]; return NULL; } /*-------------------------------------------------------------------------*/ fixed SbFxConfigWarp(WarpRecord *warp, short value) { int i; short absValue; fixed accum; int sign; if(!warp) return INT_TO_FIXED(value); absValue=value; sign=1; if(absValue<0) { absValue= (short)-absValue; sign=-1; } accum=INT_TO_FIXED(0); for(i=0; i<warp->nWarp; i++) { if(absValue<=warp->pWarp[i].low) ; /* Ignore it if below this range (if required, will have ** been caught by the previous warp) */ else if((absValue>warp->pWarp[i].low) && (absValue<=warp->pWarp[i].high)) { fixed diff; fixed partial; diff=INT_TO_FIXED((long)absValue-(long)warp->pWarp[i].low); partial=FIXED_MUL(diff, warp->pWarp[i].mult); accum=FIXED_ADD(accum, partial); break; /* Exit the for loop */ } else /* Accumulate if greater than this range */ { fixed partial; partial=FIXED_MUL(INT_TO_FIXED((long)warp->pWarp[i].high-(long)warp->pWarp[i].low), warp->pWarp[i].mult); accum=FIXED_ADD(accum, partial); } } if(sign==1) return accum; else return -accum; } /*-------------------------------------------------------------------------*/ long SbConfigWarp(WarpRecord *warp, short value) { /* An apparent bug in the msc70 compiler, trashes r if it is on the stack. Leave in unitialized global segment. */ static fixed r; r = SbFxConfigWarp(warp,value); return r >> 16 ; } /*-------------------------------------------------------------------------*/