void case_heap_clear() { struct heap *heap = heap(heap_cmp); int a = 1; assert(heap_push(heap, (void *)&a) == HEAP_OK); assert(heap_len(heap) == 1); assert(heap_cap(heap) == 1); heap_clear(heap); assert(heap_len(heap) == 0); heap_free(heap); }
heap_t heap_init(heap_cmp_fn cmpfn) { struct heap *h = malloc(sizeof *h); if (!h) return NULL; h->cmpfn = cmpfn; h->treesz = 32; h->tree = malloc(h->treesz * sizeof *h->tree); heap_clear(h); return h; }
/* heap_free(): Free a heap block. If necessary, deactivate the heap. */ void heap_free(glui32 addr) { heapblock_t *blo; for (blo = heap_head; blo; blo = blo->next) { if (blo->addr == addr) break; }; if (!blo || blo->isfree) fatalError("Attempt to free unallocated address from heap."); blo->isfree = TRUE; alloc_count--; if (alloc_count <= 0) { heap_clear(); } /* heap_sanity_check(); */ }
git_sint32 restoreFromFile (git_sint32 * base, git_sint32 id, git_uint32 protectPos, git_uint32 protectSize) { git_uint32 protectEnd = protectPos + protectSize; git_uint32 i; strid_t file; glui32 fileSize, fileStart; int gotIdent = 0; int gotMemory = 0; int gotStack = 0; int gotHeap = 0; // Find out what stream they want to use, and make sure it's valid. file = git_find_stream_by_id (id); if (file == 0) return 1; // Read IFF header. if (readWord (file) != read32("FORM")) return 1; // Not an IFF file. fileSize = readWord (file); fileStart = glk_stream_get_position (file); if (readWord (file) != read32("IFZS")) return 1; // Not a Quetzal file. // Discard the current heap. heap_clear(); // Read all the chunks. while (glk_stream_get_position(file) < fileStart + fileSize) { git_uint32 chunkType, chunkSize, chunkStart; chunkType = readWord (file); chunkSize = readWord (file); chunkStart = glk_stream_get_position (file); if (chunkType == read32("IFhd")) { if (gotIdent) return 1; gotIdent = 1; if (chunkSize != 128) return 1; for (i = 0 ; i < 128 ; ++i) { glui32 c = glk_get_char_stream (file); if (gRom [i] != c) return 1; } } else if (chunkType == read32("Stks")) { if (gotStack) return 1; gotStack = 1; if (chunkSize & 3) return 1; gStackPointer = base; for ( ; chunkSize > 0 ; chunkSize -= 4) *gStackPointer++ = readWord(file); } else if (chunkType == read32("CMem")) { git_uint32 bytesRead = 0; if (gotMemory) return 1; gotMemory = 1; if (resizeMemory (readWord(file), 1)) fatalError ("Can't resize memory map"); bytesRead = 4; i = gRamStart; while (i < gExtStart && bytesRead < chunkSize) { int mult = 0; char c = (char) glk_get_char_stream(file); ++bytesRead; if (c == 0) { mult = (unsigned char) glk_get_char_stream(file); ++bytesRead; } for (++mult ; mult > 0 ; --mult, ++i) if (i >= protectEnd || i < protectPos) gRam [i] = gRom [i] ^ c; } while (i < gEndMem && bytesRead < chunkSize) { int mult = 0; char c = (char) glk_get_char_stream(file); ++bytesRead; if (c == 0) { mult = (unsigned char) glk_get_char_stream(file); ++bytesRead; } for (++mult ; mult > 0 ; --mult, ++i) if (i >= protectEnd || i < protectPos) gRam [i] = c; } while (i < gExtStart) if (i >= protectEnd || i < protectPos) gRam [i] = gRom [i], ++i; while (i < gEndMem) if (i >= protectEnd || i < protectPos) gRam [i] = 0, ++i; if (bytesRead != chunkSize) return 1; // Too much data! if (chunkSize & 1) glk_get_char_stream (file); } else if (chunkType == read32("MAll")) { glui32 heapSize = 0; glui32 * heap = 0; if (gotHeap) return 1; gotHeap = 1; if (chunkSize & 3) return 1; if (chunkSize > 0) { heap = malloc (chunkSize); heapSize = chunkSize / 4; for (i = 0 ; i < heapSize ; ++i) heap[i] = readWord(file); /* The summary might have come from any interpreter, so it could be out of order. We'll sort it. */ qsort(heap+2, (heapSize-2)/2, 8, &sort_heap_summary); if (heap_apply_summary (heapSize, heap)) fatalError ("Couldn't apply heap summary"); free (heap); } } else { // Unknown chunk type -- just skip it. glk_stream_set_position (file, (chunkSize + 1) & ~1, seekmode_Current); } } // Make sure we have all the chunks we need. if (!gotIdent) fatalError ("No ident chunk in save file"); if (!gotStack) fatalError ("No stack chunk in save file"); if (!gotMemory) fatalError ("No memory chunk in save file"); // If we reach this point, we restored successfully. return 0; }
int main(int argc, char *argv[]) { register uint i,j; uint ant,n1,n2,n3; uint write_count,update,opt_delete,check2,dupp_keys,found_key; int error; ulong pos; unsigned long key_check; uchar record[128],record2[128],record3[128],key[10]; const char *filename,*filename2; HP_INFO *file,*file2; HP_SHARE *tmp_share; HP_KEYDEF keyinfo[MAX_KEYS]; HA_KEYSEG keyseg[MAX_KEYS*5]; HEAP_PTR UNINIT_VAR(position); HP_CREATE_INFO hp_create_info; CHARSET_INFO *cs= &my_charset_latin1; my_bool unused; MY_INIT(argv[0]); /* init my_sys library & pthreads */ filename= "test2"; filename2= "test2_2"; file=file2=0; get_options(argc,argv); bzero(&hp_create_info, sizeof(hp_create_info)); hp_create_info.max_table_size= 2*1024L*1024L; hp_create_info.keys= keys; hp_create_info.keydef= keyinfo; hp_create_info.reclength= reclength; hp_create_info.max_records= (ulong) flag*100000L; hp_create_info.min_records= (ulong) recant/2; write_count=update=opt_delete=0; key_check=0; keyinfo[0].seg=keyseg; keyinfo[0].keysegs=1; keyinfo[0].flag= 0; keyinfo[0].algorithm= HA_KEY_ALG_HASH; keyinfo[0].seg[0].type=HA_KEYTYPE_BINARY; keyinfo[0].seg[0].start=0; keyinfo[0].seg[0].length=6; keyinfo[0].seg[0].null_bit=0; keyinfo[0].seg[0].charset=cs; keyinfo[1].seg=keyseg+1; keyinfo[1].keysegs=2; keyinfo[1].flag=0; keyinfo[1].algorithm= HA_KEY_ALG_HASH; keyinfo[1].seg[0].type=HA_KEYTYPE_BINARY; keyinfo[1].seg[0].start=7; keyinfo[1].seg[0].length=6; keyinfo[1].seg[0].null_bit=0; keyinfo[1].seg[0].charset=cs; keyinfo[1].seg[1].type=HA_KEYTYPE_TEXT; keyinfo[1].seg[1].start=0; /* key in two parts */ keyinfo[1].seg[1].length=6; keyinfo[1].seg[1].null_bit=0; keyinfo[1].seg[1].charset=cs; keyinfo[2].seg=keyseg+3; keyinfo[2].keysegs=1; keyinfo[2].flag=HA_NOSAME; keyinfo[2].algorithm= HA_KEY_ALG_HASH; keyinfo[2].seg[0].type=HA_KEYTYPE_BINARY; keyinfo[2].seg[0].start=12; keyinfo[2].seg[0].length=8; keyinfo[2].seg[0].null_bit=0; keyinfo[2].seg[0].charset=cs; keyinfo[3].seg=keyseg+4; keyinfo[3].keysegs=1; keyinfo[3].flag=HA_NOSAME; keyinfo[3].algorithm= HA_KEY_ALG_HASH; keyinfo[3].seg[0].type=HA_KEYTYPE_BINARY; keyinfo[3].seg[0].start=37; keyinfo[3].seg[0].length=1; keyinfo[3].seg[0].null_bit=1; keyinfo[3].seg[0].null_pos=38; keyinfo[3].seg[0].charset=cs; bzero((char*) key1,sizeof(key1)); bzero((char*) key3,sizeof(key3)); printf("- Creating heap-file\n"); if (heap_create(filename, &hp_create_info, &tmp_share, &unused) || !(file= heap_open(filename, 2))) goto err; signal(SIGINT,endprog); printf("- Writing records:s\n"); strmov((char*) record," ..... key"); for (i=0 ; i < recant ; i++) { n1=rnd(1000); n2=rnd(100); n3=rnd(MY_MIN(recant*5,MAX_RECORDS)); make_record(record,n1,n2,n3,"Pos",write_count); if (heap_write(file,record)) { if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0) { printf("Error: %d in write at record: %d\n",my_errno,i); goto err; } if (verbose) printf(" Double key: %d\n",n3); } else { if (key3[n3] == 1) { printf("Error: Didn't get error when writing second key: '%8d'\n",n3); goto err; } write_count++; key1[n1]++; key3[n3]=1; key_check+=n1; } if (testflag == 1 && heap_check_heap(file,0)) { puts("Heap keys crashed"); goto err; } } if (testflag == 1) goto end; if (heap_check_heap(file,0)) { puts("Heap keys crashed"); goto err; } printf("- Delete\n"); for (i=0 ; i < write_count/10 ; i++) { for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ; if (j != 0) { sprintf((char*) key,"%6d",j); if (heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT)) { printf("can't find key1: \"%s\"\n",(char*) key); goto err; } if (heap_delete(file,record)) { printf("error: %d; can't delete record: \"%s\"\n", my_errno,(char*) record); goto err; } opt_delete++; key1[atoi((char*) record+keyinfo[0].seg[0].start)]--; key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0; key_check-=atoi((char*) record); if (testflag == 2 && heap_check_heap(file,0)) { puts("Heap keys crashed"); goto err; } } else puts("Warning: Skipping delete test because no dupplicate keys"); } if (testflag==2) goto end; if (heap_check_heap(file,0)) { puts("Heap keys crashed"); goto err; } printf("- Update\n"); for (i=0 ; i < write_count/10 ; i++) { n1=rnd(1000); n2=rnd(100); n3=rnd(MY_MIN(recant*2,MAX_RECORDS)); make_record(record2, n1, n2, n3, "XXX", update); if (rnd(2) == 1) { if (heap_scan_init(file)) goto err; j=rnd(write_count-opt_delete); while ((error=heap_scan(file,record) == HA_ERR_RECORD_DELETED) || (!error && j)) { if (!error) j--; } if (error) goto err; } else { for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ; if (!key1[j]) continue; sprintf((char*) key,"%6d",j); if (heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT)) { printf("can't find key1: \"%s\"\n",(char*) key); goto err; } } if (heap_update(file,record,record2)) { if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0) { printf("error: %d; can't update:\nFrom: \"%s\"\nTo: \"%s\"\n", my_errno,(char*) record, (char*) record2); goto err; } if (verbose) printf("Double key when tried to update:\nFrom: \"%s\"\nTo: \"%s\"\n", (char*) record, (char*) record2); } else { key1[atoi((char*) record+keyinfo[0].seg[0].start)]--; key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0; key1[n1]++; key3[n3]=1; update++; key_check=key_check-atoi((char*) record)+n1; } if (testflag == 3 && heap_check_heap(file,0)) { puts("Heap keys crashed"); goto err; } } if (testflag == 3) goto end; if (heap_check_heap(file,0)) { puts("Heap keys crashed"); goto err; } for (i=999, dupp_keys=found_key=0 ; i>0 ; i--) { if (key1[i] > dupp_keys) { dupp_keys=key1[i]; found_key=i; } sprintf((char*) key,"%6d",found_key); } if (dupp_keys > 3) { if (!silent) printf("- Read first key - next - delete - next -> last\n"); DBUG_PRINT("progpos",("first - next - delete - next -> last")); if (heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT)) goto err; if (heap_rnext(file,record3)) goto err; if (heap_delete(file,record3)) goto err; key_check-=atoi((char*) record3); key1[atoi((char*) record+keyinfo[0].seg[0].start)]--; key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0; opt_delete++; ant=2; while ((error=heap_rnext(file,record3)) == 0 || error == HA_ERR_RECORD_DELETED) if (! error) ant++; if (ant != dupp_keys) { printf("next: I can only find: %d records of %d\n", ant,dupp_keys); goto end; } dupp_keys--; if (heap_check_heap(file,0)) { puts("Heap keys crashed"); goto err; } if (!silent) printf("- Read last key - delete - prev - prev - opt_delete - prev -> first\n"); if (heap_rprev(file,record)) goto err; if (heap_delete(file,record3)) goto err; key_check-=atoi((char*) record3); key1[atoi((char*) record+keyinfo[0].seg[0].start)]--; key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0; opt_delete++; if (heap_rprev(file,record3) || heap_rprev(file,record3)) goto err; if (heap_delete(file,record3)) goto err; key_check-=atoi((char*) record3); key1[atoi((char*) record+keyinfo[0].seg[0].start)]--; key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0; opt_delete++; ant=3; while ((error=heap_rprev(file,record3)) == 0 || error == HA_ERR_RECORD_DELETED) { if (! error) ant++; } if (ant != dupp_keys) { printf("next: I can only find: %d records of %d\n", ant,dupp_keys); goto end; } dupp_keys-=2; if (heap_check_heap(file,0)) { puts("Heap keys crashed"); goto err; } } else puts("Warning: Not enough duplicated keys: Skipping delete key check"); if (!silent) printf("- Read (first) - next - delete - next -> last\n"); DBUG_PRINT("progpos",("first - next - delete - next -> last")); if (heap_scan_init(file)) goto err; while ((error=heap_scan(file,record3) == HA_ERR_RECORD_DELETED)) ; if (error) goto err; if (heap_delete(file,record3)) goto err; key_check-=atoi((char*) record3); opt_delete++; key1[atoi((char*) record+keyinfo[0].seg[0].start)]--; key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0; ant=0; while ((error=heap_scan(file,record3)) == 0 || error == HA_ERR_RECORD_DELETED) if (! error) ant++; if (ant != write_count-opt_delete) { printf("next: Found: %d records of %d\n",ant,write_count-opt_delete); goto end; } if (heap_check_heap(file,0)) { puts("Heap keys crashed"); goto err; } puts("- Test if: Read rrnd - same - rkey - same"); DBUG_PRINT("progpos",("Read rrnd - same")); pos=rnd(write_count-opt_delete-5)+5; heap_scan_init(file); i=5; while ((error=heap_scan(file,record)) == HA_ERR_RECORD_DELETED || (error == 0 && pos)) { if (!error) pos--; if (i-- == 0) { bmove(record3,record,reclength); position=heap_position(file); } } if (error) goto err; bmove(record2,record,reclength); if (heap_rsame(file,record,-1) || heap_rsame(file,record2,2)) goto err; if (memcmp(record2,record,reclength)) { puts("heap_rsame didn't find right record"); goto end; } puts("- Test of read through position"); if (heap_rrnd(file,record,position)) goto err; if (memcmp(record3,record,reclength)) { puts("heap_frnd didn't find right record"); goto end; } printf("- heap_info\n"); { HEAPINFO info; heap_info(file,&info,0); /* We have to test with opt_delete +1 as this may be the case if the last inserted row was a duplicate key */ if (info.records != write_count-opt_delete || (info.deleted != opt_delete && info.deleted != opt_delete+1)) { puts("Wrong info from heap_info"); printf("Got: records: %ld(%d) deleted: %ld(%d)\n", info.records,write_count-opt_delete,info.deleted,opt_delete); } } #ifdef OLD_HEAP_VERSION { uint check; printf("- Read through all records with rnd\n"); if (heap_extra(file,HA_EXTRA_RESET) || heap_extra(file,HA_EXTRA_CACHE)) { puts("got error from heap_extra"); goto end; } ant=check=0; while ((error=heap_rrnd(file,record,(ulong) -1)) != HA_ERR_END_OF_FILE && ant < write_count + 10) { if (!error) { ant++; check+=calc_check(record,reclength); } } if (ant != write_count-opt_delete) { printf("rrnd: I can only find: %d records of %d\n", ant, write_count-opt_delete); goto end; } if (heap_extra(file,HA_EXTRA_NO_CACHE)) { puts("got error from heap_extra(HA_EXTRA_NO_CACHE)"); goto end; } } #endif printf("- Read through all records with scan\n"); if (heap_reset(file) || heap_extra(file,HA_EXTRA_CACHE)) { puts("got error from heap_extra"); goto end; } ant=check2=0; heap_scan_init(file); while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE && ant < write_count + 10) { if (!error) { ant++; check2+=calc_check(record,reclength); } } if (ant != write_count-opt_delete) { printf("scan: I can only find: %d records of %d\n", ant, write_count-opt_delete); goto end; } #ifdef OLD_HEAP_VERSION if (check != check2) { puts("scan: Checksum didn't match reading with rrnd"); goto end; } #endif if (heap_extra(file,HA_EXTRA_NO_CACHE)) { puts("got error from heap_extra(HA_EXTRA_NO_CACHE)"); goto end; } for (i=999, dupp_keys=found_key=0 ; i>0 ; i--) { if (key1[i] > dupp_keys) { dupp_keys=key1[i]; found_key=i; } sprintf((char*) key,"%6d",found_key); } printf("- Read through all keys with first-next-last-prev\n"); ant=0; for (error=heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT); ! error ; error=heap_rnext(file,record)) ant++; if (ant != dupp_keys) { printf("first-next: I can only find: %d records of %d\n", ant, dupp_keys); goto end; } ant=0; for (error=heap_rprev(file,record) ; ! error ; error=heap_rprev(file,record)) { ant++; check2+=calc_check(record,reclength); } if (ant != dupp_keys) { printf("last-prev: I can only find: %d records of %d\n", ant, dupp_keys); goto end; } if (testflag == 4) goto end; printf("- Reading through all rows through keys\n"); if (!(file2=heap_open(filename, 2))) goto err; if (heap_scan_init(file)) goto err; while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE) { if (error == 0) { if (heap_rkey(file2,record2,2,record+keyinfo[2].seg[0].start,8, HA_READ_KEY_EXACT)) { printf("can't find key3: \"%.8s\"\n", record+keyinfo[2].seg[0].start); goto err; } } } heap_close(file2); printf("- Creating output heap-file 2\n"); hp_create_info.keys= 1; hp_create_info.max_records= 0; hp_create_info.min_records= 0; if (heap_create(filename2, &hp_create_info, &tmp_share, &unused) || !(file2= heap_open_from_share_and_register(tmp_share, 2))) goto err; printf("- Copying and removing records\n"); if (heap_scan_init(file)) goto err; while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE) { if (error == 0) { if (heap_write(file2,record)) goto err; key_check-=atoi((char*) record); write_count++; if (heap_delete(file,record)) goto err; opt_delete++; } pos++; } printf("- Checking heap tables\n"); if (heap_check_heap(file,1) || heap_check_heap(file2,1)) { puts("Heap keys crashed"); goto err; } if (my_errno != HA_ERR_END_OF_FILE) printf("error: %d from heap_rrnd\n",my_errno); if (key_check) printf("error: Some read got wrong: check is %ld\n",(long) key_check); end: printf("\nFollowing test have been made:\n"); printf("Write records: %d\nUpdate records: %d\nDelete records: %d\n", write_count,update,opt_delete); heap_clear(file); if (heap_close(file) || (file2 && heap_close(file2))) goto err; heap_delete_table(filename2); hp_panic(HA_PANIC_CLOSE); my_end(MY_GIVE_INFO); return(0); err: printf("Got error: %d when using heap-database\n",my_errno); (void) heap_close(file); return(1); } /* main */
static glui32 read_memstate(dest_t *dest, glui32 chunklen) { glui32 chunkend = dest->pos + chunklen; glui32 newlen; glui32 res, pos; int val; int runlen; unsigned char ch, ch2; #ifdef SERIALIZE_CACHE_RAM glui32 cachepos; #endif /* SERIALIZE_CACHE_RAM */ heap_clear(); res = read_long(dest, &newlen); if (res) return res; res = change_memsize(newlen, FALSE); if (res) return res; runlen = 0; #ifdef SERIALIZE_CACHE_RAM cachepos = 0; #else /* SERIALIZE_CACHE_RAM */ glk_stream_set_position(gamefile, gamefile_start+ramstart, seekmode_Start); #endif /* SERIALIZE_CACHE_RAM */ for (pos=ramstart; pos<endmem; pos++) { if (pos < endgamefile) { #ifdef SERIALIZE_CACHE_RAM val = ramcache[cachepos]; cachepos++; #else /* SERIALIZE_CACHE_RAM */ val = glk_get_char_stream(gamefile); if (val == -1) { fatal_error("The game file ended unexpectedly while restoring."); } #endif /* SERIALIZE_CACHE_RAM */ ch = (unsigned char)val; } else { ch = 0; } if (dest->pos >= chunkend) { /* we're into the final, unstored run. */ } else if (runlen) { runlen--; } else { res = read_byte(dest, &ch2); if (res) return res; if (ch2 == 0) { res = read_byte(dest, &ch2); if (res) return res; runlen = (glui32)ch2; } else { ch ^= ch2; } } if (pos >= protectstart && pos < protectend) continue; MemW1(pos, ch); } return 0; }
int restoreUndo (git_sint32* base, git_uint32 protectPos, git_uint32 protectSize) { if (gUndo == NULL) { // Nothing to undo! return 1; } else { UndoRecord * undo = gUndo; git_uint32 addr = gRamStart; // Address in glulx memory. MemoryMap map = undo->memoryMap; // Glulx memory map. // Restore the size of the memory map heap_clear (); resizeMemory (undo->endMem, 1); // Restore the stack. memcpy (base, undo->stack, undo->stackSize); gStackPointer = base + (undo->stackSize / sizeof(git_sint32)); // Restore the contents of RAM. if (protectSize > 0 && protectPos < gEndMem) { for ( ; addr < (protectPos & ~0xff) ; addr += 256, ++map) memcpy (gMem + addr, *map, 256); memcpy (gMem + addr, *map, protectPos & 0xff); protectSize += protectPos & 0xff; while (protectSize > 256) addr += 256, ++map, protectSize -= 256; if (addr < gEndMem) { memcpy (gMem + addr + protectSize, *map + protectSize, 256 - protectSize); } addr += 256, ++map; } for ( ; addr < gEndMem ; addr += 256, ++map) memcpy (gMem + addr, *map, 256); // Restore the heap. if (heap_apply_summary (undo->heapSize, undo->heap)) fatalError ("Couldn't apply heap summary"); // Delete the undo record. gUndo = undo->prev; deleteRecord (undo); if (gUndo) gUndo->next = NULL; else assert (gUndoSize == 0); // And we're done. return 0; } }