ODYNARR.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. /*
  2. * Seven Kingdoms: Ancient Adversaries
  3. *
  4. * Copyright 1997,1998 Enlight Software Ltd.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. //Filename :: ODYNARR.CPP
  21. //Description :: Dynamic Array object
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <ODYNARR.h>
  25. //--------- BEGIN OF FUNCTION DynArray Constructor -------//
  26. //
  27. // <int> eleSize = size of each element
  28. // [int] blockNum = number of entity of each block of element
  29. // increased ( default : 30 )
  30. DynArray::DynArray(int eleSize,int blockNum)
  31. {
  32. ele_size = eleSize;
  33. block_num = blockNum;
  34. body_buf = mem_add( ele_size*block_num );
  35. cur_pos=0;
  36. last_ele=0;
  37. ele_num= block_num;
  38. sort_offset = -1;
  39. }
  40. //----------- END OF FUNCTION DynArray Constructor -----//
  41. //--------- BEGIN OF FUNCTION DynArray Destructor ------//
  42. DynArray::~DynArray()
  43. {
  44. mem_del( body_buf );
  45. }
  46. //---------- END OF FUNCTION DynArray Destructor --------//
  47. //--------- BEGIN OF FUNCTION DynArray::resize ---------//
  48. //
  49. // change the size of the storage block - this will always be an increase
  50. //
  51. void DynArray::resize( int newNum )
  52. {
  53. //-------------------------------------------------------//
  54. //
  55. // The Mem::resize() and realloc() may not function properly in
  56. // some case when the memory block has a considerable size.
  57. //
  58. // Calling function resize_keep_data will do additional effort
  59. // to preserve the original data.
  60. //
  61. //-------------------------------------------------------//
  62. body_buf = mem_resize( body_buf, newNum*ele_size ); // give both the original data size and the new data size
  63. ele_num = newNum;
  64. }
  65. //--------- END OF FUNCTION DynArray::resize -----------//
  66. //--------- BEGIN OF FUNCTION DynArray::zap ---------//
  67. //
  68. // Zap the whole dynamic array, clear all elements
  69. //
  70. // [int] resizeFlag - whether resize the array to its initial size
  71. // or keep its current size.
  72. // (default:1)
  73. //
  74. void DynArray::zap(int resizeFlag)
  75. {
  76. if( resizeFlag )
  77. {
  78. if( ele_num != block_num ) // if the current record no. is already block_num, no resizing needed
  79. {
  80. ele_num = block_num;
  81. body_buf = mem_resize(body_buf, ele_size*ele_num );
  82. }
  83. }
  84. cur_pos=0;
  85. last_ele=0;
  86. }
  87. //--------- END OF FUNCTION DynArray::zap -----------//
  88. //---------- BEGIN OF FUNCTION DynArray::linkin -----------//
  89. //
  90. // Link a record at the END of the array
  91. //
  92. // WARNING : After calling linkin() all pointers to the linklist body
  93. // should be updated, because mem_resize() will move the body memory
  94. //
  95. void DynArray::linkin(void* ent)
  96. {
  97. last_ele++;
  98. cur_pos=last_ele;
  99. if ( last_ele > ele_num ) // not enough empty element left to hold the new entity
  100. resize( ele_num + block_num );
  101. if ( ent )
  102. memcpy(body_buf+(cur_pos-1)*ele_size, ent, ele_size );
  103. else
  104. *(body_buf+(cur_pos-1)*ele_size) = NULL;
  105. }
  106. //---------- END OF FUNCTION DynArray::linkin ------------//
  107. //---------- BEGIN OF FUNCTION DynArray::linkin_unique -----------//
  108. //
  109. // Linkin - unique mode. If duplicated, don't link into the array.
  110. //
  111. void DynArray::linkin_unique(void* ent)
  112. {
  113. int i;
  114. for( i=0 ; i<last_ele ; i++ )
  115. {
  116. if( memcmp( body_buf+i*ele_size, ent, ele_size )==0 )
  117. return;
  118. }
  119. linkin(ent);
  120. }
  121. //---------- END OF FUNCTION DynArray::linkin_unique ------------//
  122. //---------- BEGIN OF FUNCTION DynArray::insert -----------//
  123. //
  124. // Link into the position BEFORE the current one
  125. //
  126. // Warning : DynArrayB (version B) can't use this function
  127. //
  128. void DynArray::insert(void* ent)
  129. {
  130. if( size()==0 )
  131. {
  132. linkin(ent);
  133. return;
  134. }
  135. last_ele++;
  136. if ( last_ele > ele_num ) // not enough empty element left to hold the new entity
  137. resize( ele_num + block_num );
  138. memmove( body_buf+cur_pos*ele_size,body_buf+(cur_pos-1)*ele_size, (last_ele-cur_pos)*ele_size );
  139. if ( ent )
  140. memcpy(body_buf+(cur_pos-1)*ele_size, ent, ele_size );
  141. else
  142. *(body_buf+(cur_pos-1)*ele_size) = NULL;
  143. }
  144. //---------- END OF FUNCTION DynArray::insert ------------//
  145. //---------- BEGIN OF FUNCTION DynArray::insert_at -----------//
  146. //
  147. // Link into the position BEFORE the current one
  148. //
  149. // Warning : DynArrayB (version B) can't use this function
  150. //
  151. // <int> insertPos - the recno to insert the new entity.
  152. // <void*> ent - pointer to the record entity. If NULL, blank record.
  153. //
  154. void DynArray::insert_at(int insertPos, void* ent)
  155. {
  156. if( size()==0 || insertPos>last_ele )
  157. {
  158. linkin(ent);
  159. return;
  160. }
  161. err_when( insertPos<1 || insertPos > last_ele );
  162. last_ele++;
  163. if ( last_ele > ele_num ) // not enough empty element left to hold the new entity
  164. resize( ele_num + block_num );
  165. memmove( body_buf+insertPos*ele_size, body_buf+(insertPos-1)*ele_size, (last_ele-insertPos)*ele_size );
  166. if ( ent )
  167. memcpy(body_buf+(insertPos-1)*ele_size, ent, ele_size );
  168. else
  169. *(body_buf+(insertPos-1)*ele_size) = NULL;
  170. }
  171. //---------- END OF FUNCTION DynArray::insert_at ------------//
  172. //----------- BEGIN OF FUNCTION DynArray::linkout ---------//
  173. //
  174. // Linkout the current object and then point to next object
  175. //
  176. // [int] delPos = the position (recno) of the item to be deleted
  177. // ( default : recno() current record no. )
  178. //
  179. void DynArray::linkout(int delPos)
  180. {
  181. if( delPos < 0 )
  182. delPos = cur_pos;
  183. if( delPos == 0 || delPos > last_ele )
  184. return;
  185. if( delPos != last_ele )
  186. memmove( body_buf+(delPos-1)*ele_size, body_buf+delPos*ele_size, (last_ele-delPos)*ele_size );
  187. last_ele--;
  188. if( cur_pos > last_ele )
  189. cur_pos = last_ele;
  190. if ( last_ele < ele_num - block_num*2 ) // shrink the size if two empty block of element are left
  191. resize( ele_num - block_num );
  192. }
  193. //------------ END OF FUNCTION DynArray::linkout ----------//
  194. //---------- BEGIN OF FUNCTION DynArray::update ---------//
  195. //
  196. // <void*> bodyPtr = the pointer to the content body
  197. // [int] recNo = no. of the record to be updated
  198. // ( default : current record no. )
  199. //
  200. void DynArray::update(void* bodyPtr, int recNo)
  201. {
  202. if( recNo < 0 )
  203. recNo = cur_pos;
  204. if( recNo <= 0 )
  205. return;
  206. if( bodyPtr )
  207. memcpy(body_buf+(recNo-1)*ele_size, bodyPtr, ele_size );
  208. else
  209. *(body_buf+(recNo-1)*ele_size) = NULL;
  210. }
  211. //----------- END OF FUNCTION DynArray::update ---------//
  212. //---------- BEGIN OF FUNCTION DynArray::add_blank -----------//
  213. //
  214. // Add a specified number of blank records at the END of the array
  215. //
  216. // <int> blankNum = no. of blank records
  217. //
  218. void DynArray::add_blank(int blankNum)
  219. {
  220. cur_pos=last_ele+1;
  221. last_ele+=blankNum;
  222. if ( last_ele > ele_num ) // not enough empty element left to hold the new entity
  223. resize( last_ele+block_num );
  224. memset( body_buf+(cur_pos-1)*ele_size, 0, blankNum*ele_size );
  225. }
  226. //---------- END OF FUNCTION DynArray::add_blank ------------//
  227. //------ BEGIN OF FUNCTION DynArray::scan_whole ----------//
  228. //
  229. // Description : scan a sorted or unsorted link list for matching
  230. // the Whole Structure
  231. //
  232. // Syntax : scan(<void*>)
  233. //
  234. // <void*> = pointer to the data structure
  235. //
  236. // Return : 0 if not found
  237. // if found, return the position found
  238. //
  239. int DynArray::scan_whole(void* structPtr)
  240. {
  241. for ( cur_pos=1 ; cur_pos<=last_ele ; cur_pos++ )
  242. {
  243. if( memcmp( structPtr, get(), ele_size ) == 0 )
  244. return cur_pos;
  245. }
  246. return 0;
  247. }
  248. //-------- END OF FUNCTION DynArray::scan_whole ----------//
  249. //------ BEGIN OF FUNCTION DynArray::scan ----------//
  250. //
  251. // Description : scan a sorted or unsorted link list for matching
  252. // the specified element in the structure
  253. //
  254. // Syntax : scan(<void*>,<int>,<char>,[int])
  255. //
  256. // <void*> = the data to be scanned for
  257. // <int> = the offset of the structure containing the variable to be compared
  258. // <char> = the type of the variable in the structure
  259. // 'C' = char[]
  260. // 'P' = char*
  261. // 'd' = double
  262. // 'i' = integer
  263. // 'c' = char
  264. // [int] = restore the original position ( default : FALSE )
  265. //
  266. // Return : 0 if not found
  267. // if found, return the position found
  268. //
  269. int DynArray::scan(void* varChar,int varOff,char varType,int restPos)
  270. {
  271. int oldPos,ret;
  272. oldPos = cur_pos;
  273. for ( cur_pos=1 ; cur_pos<=last_ele ; cur_pos++ )
  274. {
  275. if ( compare(varChar,varOff,varType) )
  276. {
  277. ret = cur_pos;
  278. if (restPos)
  279. cur_pos = oldPos;
  280. return ret;
  281. }
  282. }
  283. return 0;
  284. }
  285. //-------- END OF FUNCTION DynArray::scan ----------//
  286. //------- BEGIN OF FUNCTION DynArray::compare --------//
  287. //
  288. // <char*> = the character string to be scanned for
  289. // <int> = the offset of the structure containing the variable to be compared
  290. // <char> = the type of the variable in the structure
  291. // 'C' = char[]
  292. // 'P' = char*
  293. // 'd' = double
  294. // 'i' = integer
  295. // 'c' = char
  296. int DynArray::compare(void* varChar,int varOff,char varType)
  297. {
  298. char *bodyPtr,*bodyStr;
  299. bodyPtr = (char*) get();
  300. switch( varType )
  301. {
  302. case 'C' :
  303. case 'P' :
  304. if ( varType == 'C' )
  305. bodyStr = bodyPtr + varOff;
  306. else
  307. bodyStr = *( (char**)(bodyPtr+varOff) );
  308. if( bodyStr == (char*) varChar ) // the pointer is the same
  309. return 1;
  310. else
  311. return m.str_cmp(bodyStr, (char*) varChar); // m1strcmp with exact set off
  312. case 'c' :
  313. return *(bodyPtr + varOff ) == *((char*)varChar);
  314. case 'i' :
  315. return *((int*)(bodyPtr+varOff)) == *((int*)varChar);
  316. case 'd' :
  317. return *((double*)(bodyPtr+varOff)) == *((double*)varChar);
  318. }
  319. return NULL;
  320. }
  321. //-------- END OF FUNCTION DynArray::compare ----------//
  322. //---------- BEGIN OF FUNCTION DynArray::clean_up --------------//
  323. //
  324. // Description : clear up the whole dynamic array
  325. //
  326. // Syntax : clean_up(<int[]>)
  327. //
  328. // <int[]> = the array of offset of the char*
  329. //
  330. void DynArray::clean_up(int *stringOffset)
  331. {
  332. if ( stringOffset )
  333. {
  334. int i;
  335. for ( i = 0 ; i<last_ele ; i++ )
  336. free_ptr( body_buf+i*ele_size, stringOffset );
  337. }
  338. last_ele=0;
  339. cur_pos =0;
  340. resize( block_num );
  341. }
  342. //---------- END OF FUNCTION DynArray::clean_up ---------//
  343. //------- BEGIN OF FUNCTION DynArray::free_ptr ----------//
  344. void DynArray::free_ptr( void* freebody, int *stringOffset )
  345. {
  346. int i,stringNum;
  347. char** ptrPtr;
  348. char* charPtr;
  349. stringNum = stringOffset[0];
  350. for(i=1 ; i<=stringNum ; i++) // write char* allocated string
  351. {
  352. ptrPtr = (char**) ( (char*)freebody + stringOffset[i] );
  353. charPtr = (char*) *ptrPtr;
  354. if ( charPtr )
  355. mem_del(charPtr);
  356. }
  357. }
  358. //----------- END OF FUNCTION DynArray::free_ptr -------------//
  359. //---------- Begin of function DynArray::quick_sort -------------//
  360. //
  361. // Perform a quick sort on the array.
  362. //
  363. // int(*fcmp)(const void*, const void*) cmpFun = the pointer to the comparsion function
  364. //
  365. void DynArray::quick_sort( int(*cmpFun)(const void*, const void*) )
  366. {
  367. qsort( body_buf, last_ele, ele_size, cmpFun );
  368. }
  369. //------------- End of function DynArray::quick_sort --------------//
  370. //---------- Begin of function DynArray::write_file -------------//
  371. //
  372. // Write current dynamic array into file,
  373. // read_file() can be used to retrieve it.
  374. //
  375. // <File*> writeFile = the pointer to the writing file
  376. //
  377. // Return : 1 - write successfully
  378. // 0 - writing error
  379. //
  380. int DynArray::write_file(File* filePtr)
  381. {
  382. if( !filePtr->file_write( this, sizeof(DynArray) ) )
  383. return 0;
  384. if( last_ele > 0 )
  385. {
  386. if( !filePtr->file_write( body_buf, ele_size*last_ele ) )
  387. return 0;
  388. }
  389. return 1;
  390. }
  391. //------------- End of function DynArray::write_file --------------//
  392. //---------- Begin of function DynArray::read_file -------------//
  393. //
  394. // Read a saved dynamic array from file, it must be saved with write_file()
  395. //
  396. // <File*> readFile = the pointer to the writing file
  397. //
  398. // Return : 1 - read successfully
  399. // 0 - writing error
  400. //
  401. int DynArray::read_file(File* filePtr)
  402. {
  403. char* bodyBuf = body_buf; // preserve body_buf which has been allocated
  404. if( !filePtr->file_read( this, sizeof(DynArray) ) )
  405. return 0;
  406. body_buf = mem_resize( bodyBuf, ele_num*ele_size );
  407. if( last_ele > 0 )
  408. {
  409. if( !filePtr->file_read( body_buf, ele_size*last_ele ) )
  410. return 0;
  411. }
  412. start(); // go top
  413. return 1;
  414. }
  415. //------------- End of function DynArray::read_file --------------//
  416. //--------- Begin of function DynArray::init_sort ---------//
  417. //
  418. // Initialize sorting parameters before using linkin_sort & resort
  419. //
  420. // <int> sortOffset : offset of the sorting variable
  421. // <char> sortType : SORT_CHAR_PTR = <char*>
  422. // SORT_CHAR_STR = <char[]>
  423. // SORT_INT = <int>
  424. // SORT_SHORT = <short>
  425. // SORT_CHAR = <char>
  426. //
  427. void DynArray::init_sort(int sortOffset, char sortType)
  428. {
  429. sort_offset = sortOffset;
  430. sort_type = sortType;
  431. }
  432. //----------- End of function DynArray::init_sort ---------//
  433. //------ BEGIN OF FUNCTION DynArray::linkin_sort_scan_from_bottom ----------//
  434. //
  435. // Description : linkin a entry to a sorted link list
  436. //
  437. // Note : init_sort() must be called first, before using sorting function
  438. // Warning : DynArrayB (version B) can't use this function
  439. //
  440. // Syntax : linkin_sort_scan_from_bottom(<void*>,<int>,<char>)
  441. //
  442. // <void*> = the structure buffer pointer
  443. //
  444. // Note : use DynArray::seek() to search quickly if the whole DynArray is
  445. // built up with linkin_sort_scan_from_bottom()
  446. //
  447. // WARNING : After calling linkin() all pointers to the linklist body
  448. // should be updated, because mem_resize() will move the body memory
  449. //
  450. void DynArray::linkin_sort_scan_from_bottom(void* varPtr)
  451. {
  452. err_when( sort_offset < 0 );
  453. int cmpRet;
  454. char* varData,*bodyChar;
  455. for( int recNo=last_ele ; recNo>0 ; recNo-- )
  456. {
  457. //-------- comparsion ---------//
  458. switch( sort_type )
  459. {
  460. case SORT_INT: // <int>
  461. cmpRet = *((int*)((char*)varPtr+sort_offset)) >
  462. *((int*)((char*)get()+sort_offset));
  463. break;
  464. case SORT_SHORT: // <short>
  465. cmpRet = *((short*)((char*)varPtr+sort_offset)) >
  466. *((short*)((char*)get()+sort_offset));
  467. break;
  468. case SORT_CHAR: // <char>
  469. cmpRet = *((char*)((char*)varPtr+sort_offset)) >
  470. *((char*)((char*)get()+sort_offset));
  471. break;
  472. case SORT_CHAR_PTR: // <char*>
  473. varData = *( (char**)((char*)varPtr + sort_offset) );
  474. bodyChar = *( (char**)((char*)get() + sort_offset) );
  475. err_when( !varData || !bodyChar );
  476. cmpRet = strcmp( varData, bodyChar );
  477. break;
  478. case SORT_CHAR_STR: // <char[]>
  479. varData = (char*)varPtr + sort_offset ;
  480. bodyChar = (char*)get() + sort_offset ;
  481. err_when( !varData || !bodyChar );
  482. cmpRet = strcmp( varData, bodyChar );
  483. break;
  484. }
  485. //---- if equal then linkin -----------//
  486. if( cmpRet >= 0 )
  487. {
  488. insert_at( last_ele+1, varPtr) ;
  489. return;
  490. }
  491. }
  492. insert_at( 1, varPtr); // insert at the top
  493. }
  494. //--------- END OF FUNCTION DynArray::linkin_sort_scan_from_bottom ---------//
  495. /* this function has bugs and is commented out.
  496. //------ BEGIN OF FUNCTION DynArray::linkin_sort ----------//
  497. //
  498. // Description : linkin a entry to a sorted link list
  499. //
  500. // Note : init_sort() must be called first, before using sorting function
  501. // Warning : DynArrayB (version B) can't use this function
  502. //
  503. // Syntax : linkin_sort(<void*>,<int>,<char>)
  504. //
  505. // <void*> = the structure buffer pointer
  506. //
  507. // Note : use DynArray::seek() to search quickly if the whole DynArray is
  508. // built up with linkin_sort()
  509. //
  510. // WARNING : After calling linkin() all pointers to the linklist body
  511. // should be updated, because mem_resize() will move the body memory
  512. //
  513. void DynArray::linkin_sort(void* varPtr)
  514. {
  515. err_when( sort_offset < 0 );
  516. register int jumpStep,cmpRet;
  517. char* lastVar,*lastVar2;
  518. char* varData,*bodyChar;
  519. jumpStep=last_ele/2+1;
  520. go(jumpStep);
  521. lastVar = lastVar2 = NULL;
  522. //------- for binary comparsion linkin_sort -------------//
  523. for (;; )
  524. {
  525. //-------- comparsion ---------//
  526. switch( sort_type )
  527. {
  528. case 'I':
  529. cmpRet = *((int*)((char*)varPtr+sort_offset)) ==
  530. *((int*)((char*)get()+sort_offset));
  531. break;
  532. case 'P': // char*
  533. varData = *( (char**)((char*)varPtr + sort_offset) );
  534. bodyChar = *( (char**)((char*)get() + sort_offset) );
  535. err_when( !varData || !bodyChar );
  536. cmpRet = strcmp( varData, bodyChar );
  537. break;
  538. case 'C':
  539. varData = (char*)varPtr + sort_offset ;
  540. bodyChar = (char*)get() + sort_offset ;
  541. err_when( !varData || !bodyChar );
  542. cmpRet = strcmp( varData, bodyChar );
  543. break;
  544. }
  545. //---- if equal then linkin -----------//
  546. if ( cmpRet ==0 )
  547. {
  548. linkin(varPtr) ;
  549. break;
  550. }
  551. //----- reach the end of the binary tree ----//
  552. if ( lastVar2 == bodyChar )
  553. {
  554. if ( cmpRet < 0 )
  555. bkwd();
  556. linkin(varPtr);
  557. break;
  558. }
  559. //----- search through the binary tree -----//
  560. if ( jumpStep%2 == 1 )
  561. jumpStep=jumpStep/2+1;
  562. else
  563. jumpStep/=2;
  564. if ( jumpStep < 1 )
  565. jumpStep = 1;
  566. if ( cmpRet < 0 )
  567. jump( -jumpStep );
  568. else
  569. jump( jumpStep );
  570. lastVar2 = lastVar;
  571. lastVar = bodyChar;
  572. }
  573. }
  574. //--------- END OF FUNCTION DynArray::linkin_sort ---------//
  575. //---------- Begin of function DynArray::resort -------------//
  576. //
  577. // When the content of a sorted recno is updated,
  578. // call this function for renewing the sorting order
  579. //
  580. // <int> resortRecno = the pointer to the writing file
  581. //
  582. void DynArray::resort(int resortRecno)
  583. {
  584. linkin_sort(get(resortRecno)); // linkin the record for a second time, for sorting
  585. go(resortRecno); // delete the original record
  586. linkout(resortRecno);
  587. }
  588. //------------- End of function DynArray::resort --------------//
  589. */