Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

src/util.c

Go to the documentation of this file.
00001 /* {{{
00002  * CalcRogue, a roguelike game for PCs, calculators and PDAs
00003  * Copyright (C) 2003 Jim Babcock
00004  * 
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  * 
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018  * }}} */
00019 // util.c:
00022 
00023 #include "crogue.h"
00024 
00025 //{{{
00030 void catprintf(char *target, const char *format, ...)
00031 {
00032     va_list varargs;
00033     
00034     while(*target) target++;
00035     
00036     va_start(varargs, format);
00037     vsprintf(target, format, varargs);
00038     va_end(varargs);
00039 }
00040 //}}}
00041 //{{{
00047 const char *retprintf(const char *format, ...)
00048 {
00049     va_list varargs;
00050     const char *ret;
00051     va_start(varargs, format);
00052     ret = vretprintf(format, varargs);
00053     va_end(varargs);
00054     return ret;
00055 }
00056 //}}}
00057 //{{{
00060 const char *vretprintf(const char *format, va_list args)
00061 {
00062     static char buf[128];
00063     vsprintf(buf, format, args);
00064     return buf;
00065 }
00066 //}}}
00067 
00068 //{{{
00075 coord trace_path(int x, int y, direction dir, int distance)
00076 {
00077     while(distance)
00078     {
00079         x += dir.x;
00080         y += dir.y;
00081         if( w->t[y][x].flags & TFLAG_OCCUPIED ||
00082             !w->tiledescs[w->t[y][x].type].passable )
00083             break;
00084         distance--;
00085     }
00086     return COORD(x, y);
00087 }
00088 //}}}
00089 
00090 //{{{
00098 const char *pluralize(int num, const char *str)
00099 {
00100 #if TARGET_LANGUAGE==ENGLISH
00101     int i=0, ii=0, xofyform=0;
00102     static char ret[64];
00103     char *lasttoken = ret;
00104     
00105     if(num==1) return str;
00106     
00107     while(str[i] != '\0') {
00108         if( str[i]==' ' && str[i+1]=='o' && str[i+2]=='f' ) {
00109             ret[ii++]='s';
00110             xofyform = 1;
00111         }
00112         if(str[i] == ' ')
00113             lasttoken = ret+i+1;
00114         ret[ii] = str[i];
00115         i++;
00116         ii++;
00117     }
00118     ret[ii]='\0';
00119     if( xofyform )
00120     {
00121         return ret;
00122     }
00123     
00124     if(!strcmp(lasttoken, "tooth"))
00125     {
00126         lasttoken[1] = lasttoken[2] = 'e';
00127         return ret;
00128     }
00129     
00130     ret[ii++]='s';
00131     ret[ii]='\0';
00132     
00133     return ret;
00134 #elif TARGET_LANGUAGE==CZECH
00135     static char ret[64];
00136     
00137     if(num==1)
00138     {
00139         return str;
00140     }
00141     else if(num <= 4)
00142     {
00143         strcpy(ret, str);
00144         strcat(ret, "e");
00145     }
00146     else
00147     {
00148         strcpy(ret, str);
00149         strcat(ret, "u");
00150     }
00151     
00152     return ret;
00153 #else
00154 
00155     return str;
00156 #endif
00157 }
00158 //}}}
00159 //{{{
00166 const char *indefinite_article(const char *noun)
00167 {
00168 #if TARGET_LANGUAGE==ENGLISH
00169     switch(noun[0])
00170     {
00171         case 'a': case 'A':
00172         case 'e': case 'E':
00173         case 'i': case 'I':
00174         case 'o': case 'O':
00175         case 'u': case 'U':
00176             return "an";
00177         default:
00178             return "a";
00179     }
00180 #elif TARGET_LANGUAGE==CZECH
00181     return "";
00182 #else
00183 
00184     return "";
00185 #endif
00186 }
00187 //}}}
00188 //{{{
00190 monstdesc *find_monster_description(int m)
00191 {
00192     return (monstdesc*)deref_file_ptr(w->m[m].type);
00193 }
00194 //}}}
00195 
00196 //{{{
00199 void init_shuffle_tab(void)
00200 {
00201     int i, j, k, pos;
00202     uint temp;
00203     uint *sizes;
00204     
00205     w->shuffletranslation = (uint*)debug_malloc( sizeof(uint) * w->desc.shuffletabsize );
00206     
00207     // Make an identity table
00208     for(i=0; i<w->desc.shuffletabsize; i++)
00209         w->shuffletranslation[i] = i;
00210     
00211     // Shuffle things around
00212     sizes = (uint*)deref_file_ptr(w->desc.stsizes);
00213     pos = 0;
00214     for(i=0; i<w->desc.numshuffletabs; i++)
00215     {
00216         for(j=0; j<sizes[i]; j++)
00217         {
00218             k = pos+RANGE(sizes[i]-1, 0);
00219             
00220             temp = w->shuffletranslation[k];
00221             w->shuffletranslation[k] = w->shuffletranslation[pos+j];
00222             w->shuffletranslation[pos+j] = temp;
00223         }
00224         pos += sizes[i];
00225     }
00226 }
00227 //}}}
00228 
00229 //{{{
00230 typedef struct jumptabentry
00231 {
00232     filelink target;
00233     uint freq;
00234     range condition;
00235 } jumptabentry;
00236 //}}}
00237 //{{{
00238 typedef struct jumptable
00239 {
00240     uint numEntries;
00241     uint condition;
00242     jumptabentry entries[1];
00243 } jumptable;
00244 //}}}
00245 static filelink deref_jump_table(jumptable *table);
00246 
00247 const filelink filelink_null = { 0, 0, 0 };
00248 
00249 //{{{
00257 const void *deref_file_ptr(filelink p)
00258 {
00259     if(isNull(p))
00260         return NULL;
00261     else
00262     {
00263         p = deref_file_ptr_partial(p);
00264         
00265         switch(p.type)
00266         {
00267             default:
00268                 return (char*)(p.offset + (char*)w->constfileoffset);
00269         }
00270     }
00271 }
00272 //}}}
00273 //{{{
00275 filelink deref_file_ptr_partial(filelink p)
00276 {
00277     char *target;
00278     
00279     while(p.type == PTR_JUMPTABLE || p.type == PTR_SHUFFLETAB)
00280     {
00281         target = (char*)((char*)w->constfileoffset + p.offset);
00282         
00283         if(p.type == PTR_JUMPTABLE)
00284             p = deref_jump_table((jumptable*)target);
00285         else
00286             p = w->shuffledata[w->shuffletranslation[p.offset]];
00287     }
00288     
00289     return p;
00290 }
00291 //}}}
00292 //{{{
00293 static filelink deref_jump_table(jumptable *table)
00294 {
00295     const jumptabentry *body = table->entries;
00296     uint low, high, mid, target, conditionresult;
00297     
00298     while(1)
00299     {
00300         // Weighted-pick an entry (binary search)
00301         low = 1;
00302         high = table->numEntries-1;
00303         target = (lrand() % body[high].freq)+1;
00304         
00305         while(1) {
00306             mid = (low+high)/2;
00307             
00308             if(low>=high)
00309                 break;
00310 
00311             if(body[mid].freq >= target) {
00312                 if(body[mid-1].freq < target)
00313                     break;
00314                 else
00315                     high = mid-1;
00316             } else {
00317                 low = mid+1;
00318             }
00319         }
00320         
00321         // Test condition
00322         switch(table->condition)
00323         {
00324             default:
00325             case jt_unconditional:
00326                 conditionresult = 1;
00327                 break;
00328             case jt_playerlevel:
00329                 conditionresult = w->plr.level;
00330                 break;
00331             case jt_dungeonlevel:
00332                 conditionresult = MAPDESC_CURRENT.difficulty;
00333                 break;
00334             case jt_avglevel:
00335                 conditionresult = (MAPDESC_CURRENT.difficulty + w->plr.level)/2;
00336                 break;
00337             case jt_class:
00338                 conditionresult = w->plr.class;
00339                 break;
00340         }
00341         if(conditionresult >= body[mid].condition.min && conditionresult <= body[mid].condition.max)
00342             break;
00343     }
00344     return body[mid].target;
00345 }
00346 //}}}
00347 
00348 #ifdef DEBUG_ALLOCATOR
00349 /*
00350  *  4B size. Gets zeroed on free.
00351  *  60B write-guard. Gets set on creation, and mustn't change value.
00352  *  Data
00353  *  64B write-guard. Gets set on creation, and mustn't change value.
00354  */
00355 #define GUARD_NUM 16
00356 #define GUARD_VAL 0xDEADBEEF
00357 #define GUARD_FREED 0xFEEBDAED
00358 static long *alloced_blocks[32];
00359 static int num_alloced_blocks=0;
00360 //{{{
00361 // Returns: 0 (all is good) or N (a block of size N is corrupt)
00362 int debug_verify_mem(void)
00363 {
00364     int ii, tmp, ret=0;
00365     for(ii=0; ii<num_alloced_blocks; ii++)
00366     {
00367         if((tmp=debug_verify_block(alloced_blocks[ii])))
00368             ret = tmp;
00369     }
00370     return ret;
00371 }
00372 //}}}
00373 //{{{
00374 int debug_verify_block(long *block)
00375 {
00376     long size = *block;
00377     int ii;
00378     
00379     for(ii=1; ii<GUARD_NUM; ii++)
00380     if(block[ii] != GUARD_VAL)
00381     {
00382         panic("Clobbered negative-write guard. Block size %i, write at"
00383               " offset -%i with value %li.",
00384               (int)size, (int)((GUARD_NUM-ii)*sizeof(long)), block[ii]
00385              );
00386         return size;
00387     }
00388     
00389     block += (size>>2) + GUARD_NUM;
00390     for(ii=0; ii<GUARD_NUM; ii++)
00391     if(block[ii] != GUARD_VAL)
00392     {
00393         panic("Clobbered positive write guard. Block size %i, write at"
00394               "%i past the end.", (int)size, (int)(ii*sizeof(long))
00395              );
00396         return size;
00397     }
00398     return 0;
00399 }
00400 //}}}
00401 //{{{
00402 void *debug_malloc(size_t S)
00403 {
00404     long *ret, *pos;
00405     size_t size;
00406     int ii;
00407     
00408     // Check amount already allocated
00409     if(num_alloced_blocks >= 31) {
00410         panic("Runaway allocator!");
00411         return NULL;
00412     }
00413     
00414     // Round size up to longword
00415     size = S+3;
00416     size &= ~0x3;
00417     
00418     // Get space
00419     ret = malloc_throw(size + 2*GUARD_NUM*sizeof(long));
00420     if(ret==NULL)
00421         panic("Out of space!");
00422     
00423     // Write size to first long
00424     *ret = size;
00425     
00426     // Write guards
00427     for(ii=1; ii<GUARD_NUM; ii++)
00428         ret[ii] = GUARD_VAL;
00429     pos = ret+GUARD_NUM+(size>>2);
00430     for(ii=0; ii<GUARD_NUM; ii++)
00431         pos[ii] = GUARD_VAL;
00432     
00433     alloced_blocks[num_alloced_blocks++] = ret;
00434     
00435     return ret+GUARD_NUM;
00436 }
00437 //}}}
00438 //{{{
00439 void debug_free(void *ptr)
00440 {
00441     long *block = ((long*)ptr) - GUARD_NUM;
00442     long size = *block;
00443     int ii;
00444     if(size == GUARD_FREED) {
00445         panic( "Multiply freed block (size %i)", (int)size );
00446         return;
00447     }
00448     
00449     // Delete from the allocated blocks list
00450     for(ii=0; ii<num_alloced_blocks; ii++)
00451     {
00452         if(alloced_blocks[ii] == block) {
00453             alloced_blocks[ii] = alloced_blocks[--num_alloced_blocks];
00454             break;
00455         }
00456     }
00457     
00458     debug_verify_block(block);
00459     *block = GUARD_FREED;
00460     free(block);
00461 }
00462 //}}}
00463 //{{{
00464 void *debug_calloc(size_t N, size_t S)
00465 {
00466     size_t size = N*S;
00467     void *ret = debug_malloc(size);
00468     memset(ret, 0, size);
00469     return ret;
00470 }
00471 //}}}
00472 //{{{
00473 void *debug_realloc(void *ptr, size_t S)
00474 {
00475     void *ret;
00476     long *blockstart, *pos;
00477     size_t size;
00478     int ii;
00479     if(S==0) {
00480         if(ptr!=NULL)
00481             debug_free(ptr);
00482         return NULL;
00483     }
00484     if(ptr==NULL)
00485         return debug_malloc(S);
00486     
00487     blockstart = ((long*)ptr) - GUARD_NUM;
00488     ret = debug_malloc(S);
00489     memcpy(ret, ptr, *blockstart);
00490     debug_free(ptr);
00491     return ret;
00492     
00493 /*  size = S+3;
00494     size &= ~0x3;
00495     blockstart = ((long*)ptr) - GUARD_NUM;
00496     debug_verify_block(blockstart);
00497     ret = realloc(blockstart, size+GUARD_NUM*sizeof(long)*2);
00498     pos = (long*)ret+GUARD_NUM+(size>>2);
00499     for(ii=0; ii<GUARD_NUM; ii++) pos[ii] = GUARD_VAL;
00500     
00501     for(ii=0; ii<num_alloced_blocks; ii++) {
00502         if(alloced_blocks[ii] == blockstart)
00503             alloced_blocks[ii] = ret;
00504     }
00505     return (long*)ret + GUARD_NUM;*/
00506 }
00507 //}}}
00508 #endif
00509 

Generated on Thu May 20 13:12:11 2004 for CalcRogue by doxygen 1.3.6