00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <ft2build.h>
00020 #include FT_CONFIG_CONFIG_H
00021 #include FT_INTERNAL_DEBUG_H
00022 #include FT_INTERNAL_MEMORY_H
00023 #include FT_SYSTEM_H
00024 #include FT_ERRORS_H
00025 #include FT_TYPES_H
00026
00027
00028 #ifdef FT_DEBUG_MEMORY
00029
00030 #define KEEPALIVE
00031
00032
00033
00034
00035
00036 #include FT_CONFIG_STANDARD_LIBRARY_H
00037
00038 FT_BASE_DEF( const char* ) _ft_debug_file = 0;
00039 FT_BASE_DEF( long ) _ft_debug_lineno = 0;
00040
00041 extern void
00042 FT_DumpMemory( FT_Memory memory );
00043
00044
00045 typedef struct FT_MemSourceRec_* FT_MemSource;
00046 typedef struct FT_MemNodeRec_* FT_MemNode;
00047 typedef struct FT_MemTableRec_* FT_MemTable;
00048
00049
00050 #define FT_MEM_VAL( addr ) ((FT_ULong)(FT_Pointer)( addr ))
00051
00052
00053
00054
00055
00056
00057 typedef struct FT_MemSourceRec_
00058 {
00059 const char* file_name;
00060 long line_no;
00061
00062 FT_Long cur_blocks;
00063 FT_Long max_blocks;
00064 FT_Long all_blocks;
00065
00066 FT_Long cur_size;
00067 FT_Long max_size;
00068 FT_Long all_size;
00069
00070 FT_Long cur_max;
00071
00072 FT_UInt32 hash;
00073 FT_MemSource link;
00074
00075 } FT_MemSourceRec;
00076
00077
00078
00079
00080
00081
00082 #define FT_MEM_SOURCE_BUCKETS 128
00083
00084
00085
00086
00087
00088
00089
00090
00091 typedef struct FT_MemNodeRec_
00092 {
00093 FT_Byte* address;
00094 FT_Long size;
00095
00096 FT_MemSource source;
00097
00098 #ifdef KEEPALIVE
00099 const char* free_file_name;
00100 FT_Long free_line_no;
00101 #endif
00102
00103 FT_MemNode link;
00104
00105 } FT_MemNodeRec;
00106
00107
00108
00109
00110
00111
00112 typedef struct FT_MemTableRec_
00113 {
00114 FT_ULong size;
00115 FT_ULong nodes;
00116 FT_MemNode* buckets;
00117
00118 FT_ULong alloc_total;
00119 FT_ULong alloc_current;
00120 FT_ULong alloc_max;
00121 FT_ULong alloc_count;
00122
00123 FT_Bool bound_total;
00124 FT_ULong alloc_total_max;
00125
00126 FT_Bool bound_count;
00127 FT_ULong alloc_count_max;
00128
00129 FT_MemSource sources[FT_MEM_SOURCE_BUCKETS];
00130
00131 FT_Bool keep_alive;
00132
00133 FT_Memory memory;
00134 FT_Pointer memory_user;
00135 FT_Alloc_Func alloc;
00136 FT_Free_Func free;
00137 FT_Realloc_Func realloc;
00138
00139 } FT_MemTableRec;
00140
00141
00142 #define FT_MEM_SIZE_MIN 7
00143 #define FT_MEM_SIZE_MAX 13845163
00144
00145 #define FT_FILENAME( x ) ((x) ? (x) : "unknown file")
00146
00147
00148
00149
00150
00151
00152 static const FT_UInt ft_mem_primes[] =
00153 {
00154 7,
00155 11,
00156 19,
00157 37,
00158 73,
00159 109,
00160 163,
00161 251,
00162 367,
00163 557,
00164 823,
00165 1237,
00166 1861,
00167 2777,
00168 4177,
00169 6247,
00170 9371,
00171 14057,
00172 21089,
00173 31627,
00174 47431,
00175 71143,
00176 106721,
00177 160073,
00178 240101,
00179 360163,
00180 540217,
00181 810343,
00182 1215497,
00183 1823231,
00184 2734867,
00185 4102283,
00186 6153409,
00187 9230113,
00188 13845163,
00189 };
00190
00191
00192 static FT_ULong
00193 ft_mem_closest_prime( FT_ULong num )
00194 {
00195 FT_UInt i;
00196
00197
00198 for ( i = 0;
00199 i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ )
00200 if ( ft_mem_primes[i] > num )
00201 return ft_mem_primes[i];
00202
00203 return FT_MEM_SIZE_MAX;
00204 }
00205
00206
00207 extern void
00208 ft_mem_debug_panic( const char* fmt,
00209 ... )
00210 {
00211 va_list ap;
00212
00213
00214 printf( "FreeType.Debug: " );
00215
00216 va_start( ap, fmt );
00217 vprintf( fmt, ap );
00218 va_end( ap );
00219
00220 printf( "\n" );
00221 exit( EXIT_FAILURE );
00222 }
00223
00224
00225 static FT_Pointer
00226 ft_mem_table_alloc( FT_MemTable table,
00227 FT_Long size )
00228 {
00229 FT_Memory memory = table->memory;
00230 FT_Pointer block;
00231
00232
00233 memory->user = table->memory_user;
00234 block = table->alloc( memory, size );
00235 memory->user = table;
00236
00237 return block;
00238 }
00239
00240
00241 static void
00242 ft_mem_table_free( FT_MemTable table,
00243 FT_Pointer block )
00244 {
00245 FT_Memory memory = table->memory;
00246
00247
00248 memory->user = table->memory_user;
00249 table->free( memory, block );
00250 memory->user = table;
00251 }
00252
00253
00254 static void
00255 ft_mem_table_resize( FT_MemTable table )
00256 {
00257 FT_ULong new_size;
00258
00259
00260 new_size = ft_mem_closest_prime( table->nodes );
00261 if ( new_size != table->size )
00262 {
00263 FT_MemNode* new_buckets;
00264 FT_ULong i;
00265
00266
00267 new_buckets = (FT_MemNode *)
00268 ft_mem_table_alloc( table,
00269 new_size * sizeof ( FT_MemNode ) );
00270 if ( new_buckets == NULL )
00271 return;
00272
00273 FT_ARRAY_ZERO( new_buckets, new_size );
00274
00275 for ( i = 0; i < table->size; i++ )
00276 {
00277 FT_MemNode node, next, *pnode;
00278 FT_ULong hash;
00279
00280
00281 node = table->buckets[i];
00282 while ( node )
00283 {
00284 next = node->link;
00285 hash = FT_MEM_VAL( node->address ) % new_size;
00286 pnode = new_buckets + hash;
00287
00288 node->link = pnode[0];
00289 pnode[0] = node;
00290
00291 node = next;
00292 }
00293 }
00294
00295 if ( table->buckets )
00296 ft_mem_table_free( table, table->buckets );
00297
00298 table->buckets = new_buckets;
00299 table->size = new_size;
00300 }
00301 }
00302
00303
00304 static FT_MemTable
00305 ft_mem_table_new( FT_Memory memory )
00306 {
00307 FT_MemTable table;
00308
00309
00310 table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) );
00311 if ( table == NULL )
00312 goto Exit;
00313
00314 FT_ZERO( table );
00315
00316 table->size = FT_MEM_SIZE_MIN;
00317 table->nodes = 0;
00318
00319 table->memory = memory;
00320
00321 table->memory_user = memory->user;
00322
00323 table->alloc = memory->alloc;
00324 table->realloc = memory->realloc;
00325 table->free = memory->free;
00326
00327 table->buckets = (FT_MemNode *)
00328 memory->alloc( memory,
00329 table->size * sizeof ( FT_MemNode ) );
00330 if ( table->buckets )
00331 FT_ARRAY_ZERO( table->buckets, table->size );
00332 else
00333 {
00334 memory->free( memory, table );
00335 table = NULL;
00336 }
00337
00338 Exit:
00339 return table;
00340 }
00341
00342
00343 static void
00344 ft_mem_table_destroy( FT_MemTable table )
00345 {
00346 FT_ULong i;
00347
00348
00349 FT_DumpMemory( table->memory );
00350
00351 if ( table )
00352 {
00353 FT_Long leak_count = 0;
00354 FT_ULong leaks = 0;
00355
00356
00357
00358 for ( i = 0; i < table->size; i++ )
00359 {
00360 FT_MemNode *pnode = table->buckets + i, next, node = *pnode;
00361
00362
00363 while ( node )
00364 {
00365 next = node->link;
00366 node->link = 0;
00367
00368 if ( node->size > 0 )
00369 {
00370 printf(
00371 "leaked memory block at address %p, size %8ld in (%s:%ld)\n",
00372 node->address, node->size,
00373 FT_FILENAME( node->source->file_name ),
00374 node->source->line_no );
00375
00376 leak_count++;
00377 leaks += node->size;
00378
00379 ft_mem_table_free( table, node->address );
00380 }
00381
00382 node->address = NULL;
00383 node->size = 0;
00384
00385 ft_mem_table_free( table, node );
00386 node = next;
00387 }
00388 table->buckets[i] = 0;
00389 }
00390
00391 ft_mem_table_free( table, table->buckets );
00392 table->buckets = NULL;
00393
00394 table->size = 0;
00395 table->nodes = 0;
00396
00397
00398 for ( i = 0; i < FT_MEM_SOURCE_BUCKETS; i++ )
00399 {
00400 FT_MemSource source, next;
00401
00402
00403 for ( source = table->sources[i]; source != NULL; source = next )
00404 {
00405 next = source->link;
00406 ft_mem_table_free( table, source );
00407 }
00408
00409 table->sources[i] = NULL;
00410 }
00411
00412 printf(
00413 "FreeType: total memory allocations = %ld\n", table->alloc_total );
00414 printf(
00415 "FreeType: maximum memory footprint = %ld\n", table->alloc_max );
00416
00417 ft_mem_table_free( table, table );
00418
00419 if ( leak_count > 0 )
00420 ft_mem_debug_panic(
00421 "FreeType: %ld bytes of memory leaked in %ld blocks\n",
00422 leaks, leak_count );
00423
00424 printf( "FreeType: no memory leaks detected\n" );
00425 }
00426 }
00427
00428
00429 static FT_MemNode*
00430 ft_mem_table_get_nodep( FT_MemTable table,
00431 FT_Byte* address )
00432 {
00433 FT_ULong hash;
00434 FT_MemNode *pnode, node;
00435
00436
00437 hash = FT_MEM_VAL( address );
00438 pnode = table->buckets + ( hash % table->size );
00439
00440 for (;;)
00441 {
00442 node = pnode[0];
00443 if ( !node )
00444 break;
00445
00446 if ( node->address == address )
00447 break;
00448
00449 pnode = &node->link;
00450 }
00451 return pnode;
00452 }
00453
00454
00455 static FT_MemSource
00456 ft_mem_table_get_source( FT_MemTable table )
00457 {
00458 FT_UInt32 hash;
00459 FT_MemSource node, *pnode;
00460
00461
00462
00463
00464 hash = (FT_UInt32)(FT_PtrDist)(void*)_ft_debug_file +
00465 (FT_UInt32)( 5 * _ft_debug_lineno );
00466 pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS];
00467
00468 for ( ;; )
00469 {
00470 node = *pnode;
00471 if ( node == NULL )
00472 break;
00473
00474 if ( node->file_name == _ft_debug_file &&
00475 node->line_no == _ft_debug_lineno )
00476 goto Exit;
00477
00478 pnode = &node->link;
00479 }
00480
00481 node = (FT_MemSource)ft_mem_table_alloc( table, sizeof ( *node ) );
00482 if ( node == NULL )
00483 ft_mem_debug_panic(
00484 "not enough memory to perform memory debugging\n" );
00485
00486 node->file_name = _ft_debug_file;
00487 node->line_no = _ft_debug_lineno;
00488
00489 node->cur_blocks = 0;
00490 node->max_blocks = 0;
00491 node->all_blocks = 0;
00492
00493 node->cur_size = 0;
00494 node->max_size = 0;
00495 node->all_size = 0;
00496
00497 node->cur_max = 0;
00498
00499 node->link = NULL;
00500 node->hash = hash;
00501 *pnode = node;
00502
00503 Exit:
00504 return node;
00505 }
00506
00507
00508 static void
00509 ft_mem_table_set( FT_MemTable table,
00510 FT_Byte* address,
00511 FT_ULong size,
00512 FT_Long delta )
00513 {
00514 FT_MemNode *pnode, node;
00515
00516
00517 if ( table )
00518 {
00519 FT_MemSource source;
00520
00521
00522 pnode = ft_mem_table_get_nodep( table, address );
00523 node = *pnode;
00524 if ( node )
00525 {
00526 if ( node->size < 0 )
00527 {
00528
00529
00530
00531 ft_mem_debug_panic(
00532 "memory heap corrupted (allocating freed block)" );
00533 }
00534 else
00535 {
00536
00537
00538 ft_mem_debug_panic(
00539 "memory heap corrupted (re-allocating allocated block at"
00540 " %p, of size %ld)\n"
00541 "org=%s:%d new=%s:%d\n",
00542 node->address, node->size,
00543 FT_FILENAME( node->source->file_name ), node->source->line_no,
00544 FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
00545 }
00546 }
00547
00548
00549 node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) );
00550 if ( node == NULL )
00551 ft_mem_debug_panic( "not enough memory to run memory tests" );
00552
00553 node->address = address;
00554 node->size = size;
00555 node->source = source = ft_mem_table_get_source( table );
00556
00557 if ( delta == 0 )
00558 {
00559
00560 source->all_blocks++;
00561 source->cur_blocks++;
00562 if ( source->cur_blocks > source->max_blocks )
00563 source->max_blocks = source->cur_blocks;
00564 }
00565
00566 if ( size > (FT_ULong)source->cur_max )
00567 source->cur_max = size;
00568
00569 if ( delta != 0 )
00570 {
00571
00572 source->cur_size += delta;
00573 table->alloc_current += delta;
00574 }
00575 else
00576 {
00577
00578 source->cur_size += size;
00579 table->alloc_current += size;
00580 }
00581
00582 source->all_size += size;
00583
00584 if ( source->cur_size > source->max_size )
00585 source->max_size = source->cur_size;
00586
00587 node->free_file_name = NULL;
00588 node->free_line_no = 0;
00589
00590 node->link = pnode[0];
00591
00592 pnode[0] = node;
00593 table->nodes++;
00594
00595 table->alloc_total += size;
00596
00597 if ( table->alloc_current > table->alloc_max )
00598 table->alloc_max = table->alloc_current;
00599
00600 if ( table->nodes * 3 < table->size ||
00601 table->size * 3 < table->nodes )
00602 ft_mem_table_resize( table );
00603 }
00604 }
00605
00606
00607 static void
00608 ft_mem_table_remove( FT_MemTable table,
00609 FT_Byte* address,
00610 FT_Long delta )
00611 {
00612 if ( table )
00613 {
00614 FT_MemNode *pnode, node;
00615
00616
00617 pnode = ft_mem_table_get_nodep( table, address );
00618 node = *pnode;
00619 if ( node )
00620 {
00621 FT_MemSource source;
00622
00623
00624 if ( node->size < 0 )
00625 ft_mem_debug_panic(
00626 "freeing memory block at %p more than once at (%s:%ld)\n"
00627 "block allocated at (%s:%ld) and released at (%s:%ld)",
00628 address,
00629 FT_FILENAME( _ft_debug_file ), _ft_debug_lineno,
00630 FT_FILENAME( node->source->file_name ), node->source->line_no,
00631 FT_FILENAME( node->free_file_name ), node->free_line_no );
00632
00633
00634 FT_MEM_SET( address, 0xF3, node->size );
00635
00636 if ( delta == 0 )
00637 {
00638 source = node->source;
00639
00640 source->cur_blocks--;
00641 source->cur_size -= node->size;
00642
00643 table->alloc_current -= node->size;
00644 }
00645
00646 if ( table->keep_alive )
00647 {
00648
00649
00650 node->size = -node->size;
00651 node->free_file_name = _ft_debug_file;
00652 node->free_line_no = _ft_debug_lineno;
00653 }
00654 else
00655 {
00656 table->nodes--;
00657
00658 *pnode = node->link;
00659
00660 node->size = 0;
00661 node->source = NULL;
00662
00663 ft_mem_table_free( table, node );
00664
00665 if ( table->nodes * 3 < table->size ||
00666 table->size * 3 < table->nodes )
00667 ft_mem_table_resize( table );
00668 }
00669 }
00670 else
00671 ft_mem_debug_panic(
00672 "trying to free unknown block at %p in (%s:%ld)\n",
00673 address,
00674 FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
00675 }
00676 }
00677
00678
00679 extern FT_Pointer
00680 ft_mem_debug_alloc( FT_Memory memory,
00681 FT_Long size )
00682 {
00683 FT_MemTable table = (FT_MemTable)memory->user;
00684 FT_Byte* block;
00685
00686
00687 if ( size <= 0 )
00688 ft_mem_debug_panic( "negative block size allocation (%ld)", size );
00689
00690
00691 if ( table->bound_count &&
00692 table->alloc_count >= table->alloc_count_max )
00693 return NULL;
00694
00695
00696 if ( table->bound_total &&
00697 table->alloc_total_max - table->alloc_current > (FT_ULong)size )
00698 return NULL;
00699
00700 block = (FT_Byte *)ft_mem_table_alloc( table, size );
00701 if ( block )
00702 {
00703 ft_mem_table_set( table, block, (FT_ULong)size, 0 );
00704
00705 table->alloc_count++;
00706 }
00707
00708 _ft_debug_file = "<unknown>";
00709 _ft_debug_lineno = 0;
00710
00711 return (FT_Pointer)block;
00712 }
00713
00714
00715 extern void
00716 ft_mem_debug_free( FT_Memory memory,
00717 FT_Pointer block )
00718 {
00719 FT_MemTable table = (FT_MemTable)memory->user;
00720
00721
00722 if ( block == NULL )
00723 ft_mem_debug_panic( "trying to free NULL in (%s:%ld)",
00724 FT_FILENAME( _ft_debug_file ),
00725 _ft_debug_lineno );
00726
00727 ft_mem_table_remove( table, (FT_Byte*)block, 0 );
00728
00729 if ( !table->keep_alive )
00730 ft_mem_table_free( table, block );
00731
00732 table->alloc_count--;
00733
00734 _ft_debug_file = "<unknown>";
00735 _ft_debug_lineno = 0;
00736 }
00737
00738
00739 extern FT_Pointer
00740 ft_mem_debug_realloc( FT_Memory memory,
00741 FT_Long cur_size,
00742 FT_Long new_size,
00743 FT_Pointer block )
00744 {
00745 FT_MemTable table = (FT_MemTable)memory->user;
00746 FT_MemNode node, *pnode;
00747 FT_Pointer new_block;
00748 FT_Long delta;
00749
00750 const char* file_name = FT_FILENAME( _ft_debug_file );
00751 FT_Long line_no = _ft_debug_lineno;
00752
00753
00754
00755 if ( new_size == cur_size )
00756 return block;
00757
00758
00759 #if 0
00760 if ( block == NULL || cur_size == 0 )
00761 ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)",
00762 file_name, line_no );
00763 #endif
00764
00765
00766
00767 if ( new_size <= 0 )
00768 ft_mem_debug_panic(
00769 "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)",
00770 block, cur_size, file_name, line_no );
00771
00772
00773 pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block );
00774 node = *pnode;
00775 if ( !node )
00776 ft_mem_debug_panic(
00777 "trying to reallocate unknown block at %p in (%s:%ld)",
00778 block, file_name, line_no );
00779
00780 if ( node->size <= 0 )
00781 ft_mem_debug_panic(
00782 "trying to reallocate freed block at %p in (%s:%ld)",
00783 block, file_name, line_no );
00784
00785 if ( node->size != cur_size )
00786 ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is "
00787 "%ld instead of %ld in (%s:%ld)",
00788 block, cur_size, node->size, file_name, line_no );
00789
00790
00791 if ( table->bound_count &&
00792 table->alloc_count >= table->alloc_count_max )
00793 return NULL;
00794
00795 delta = (FT_Long)( new_size - cur_size );
00796
00797
00798 if ( delta > 0 &&
00799 table->bound_total &&
00800 table->alloc_current + (FT_ULong)delta > table->alloc_total_max )
00801 return NULL;
00802
00803 new_block = (FT_Byte *)ft_mem_table_alloc( table, new_size );
00804 if ( new_block == NULL )
00805 return NULL;
00806
00807 ft_mem_table_set( table, (FT_Byte*)new_block, new_size, delta );
00808
00809 ft_memcpy( new_block, block, cur_size < new_size ? cur_size : new_size );
00810
00811 ft_mem_table_remove( table, (FT_Byte*)block, delta );
00812
00813 _ft_debug_file = "<unknown>";
00814 _ft_debug_lineno = 0;
00815
00816 if ( !table->keep_alive )
00817 ft_mem_table_free( table, block );
00818
00819 return new_block;
00820 }
00821
00822
00823 extern FT_Int
00824 ft_mem_debug_init( FT_Memory memory )
00825 {
00826 FT_MemTable table;
00827 FT_Int result = 0;
00828
00829
00830 if ( getenv( "FT2_DEBUG_MEMORY" ) )
00831 {
00832 table = ft_mem_table_new( memory );
00833 if ( table )
00834 {
00835 const char* p;
00836
00837
00838 memory->user = table;
00839 memory->alloc = ft_mem_debug_alloc;
00840 memory->realloc = ft_mem_debug_realloc;
00841 memory->free = ft_mem_debug_free;
00842
00843 p = getenv( "FT2_ALLOC_TOTAL_MAX" );
00844 if ( p != NULL )
00845 {
00846 FT_Long total_max = ft_atol( p );
00847
00848
00849 if ( total_max > 0 )
00850 {
00851 table->bound_total = 1;
00852 table->alloc_total_max = (FT_ULong)total_max;
00853 }
00854 }
00855
00856 p = getenv( "FT2_ALLOC_COUNT_MAX" );
00857 if ( p != NULL )
00858 {
00859 FT_Long total_count = ft_atol( p );
00860
00861
00862 if ( total_count > 0 )
00863 {
00864 table->bound_count = 1;
00865 table->alloc_count_max = (FT_ULong)total_count;
00866 }
00867 }
00868
00869 p = getenv( "FT2_KEEP_ALIVE" );
00870 if ( p != NULL )
00871 {
00872 FT_Long keep_alive = ft_atol( p );
00873
00874
00875 if ( keep_alive > 0 )
00876 table->keep_alive = 1;
00877 }
00878
00879 result = 1;
00880 }
00881 }
00882 return result;
00883 }
00884
00885
00886 extern void
00887 ft_mem_debug_done( FT_Memory memory )
00888 {
00889 FT_MemTable table = (FT_MemTable)memory->user;
00890
00891
00892 if ( table )
00893 {
00894 memory->free = table->free;
00895 memory->realloc = table->realloc;
00896 memory->alloc = table->alloc;
00897
00898 ft_mem_table_destroy( table );
00899 memory->user = NULL;
00900 }
00901 }
00902
00903
00904
00905 static int
00906 ft_mem_source_compare( const void* p1,
00907 const void* p2 )
00908 {
00909 FT_MemSource s1 = *(FT_MemSource*)p1;
00910 FT_MemSource s2 = *(FT_MemSource*)p2;
00911
00912
00913 if ( s2->max_size > s1->max_size )
00914 return 1;
00915 else if ( s2->max_size < s1->max_size )
00916 return -1;
00917 else
00918 return 0;
00919 }
00920
00921
00922 extern void
00923 FT_DumpMemory( FT_Memory memory )
00924 {
00925 FT_MemTable table = (FT_MemTable)memory->user;
00926
00927
00928 if ( table )
00929 {
00930 FT_MemSource* bucket = table->sources;
00931 FT_MemSource* limit = bucket + FT_MEM_SOURCE_BUCKETS;
00932 FT_MemSource* sources;
00933 FT_UInt nn, count;
00934 const char* fmt;
00935
00936
00937 count = 0;
00938 for ( ; bucket < limit; bucket++ )
00939 {
00940 FT_MemSource source = *bucket;
00941
00942
00943 for ( ; source; source = source->link )
00944 count++;
00945 }
00946
00947 sources = (FT_MemSource*)ft_mem_table_alloc(
00948 table, sizeof ( *sources ) * count );
00949
00950 count = 0;
00951 for ( bucket = table->sources; bucket < limit; bucket++ )
00952 {
00953 FT_MemSource source = *bucket;
00954
00955
00956 for ( ; source; source = source->link )
00957 sources[count++] = source;
00958 }
00959
00960 ft_qsort( sources, count, sizeof ( *sources ), ft_mem_source_compare );
00961
00962 printf( "FreeType Memory Dump: "
00963 "current=%ld max=%ld total=%ld count=%ld\n",
00964 table->alloc_current, table->alloc_max,
00965 table->alloc_total, table->alloc_count );
00966 printf( " block block sizes sizes sizes source\n" );
00967 printf( " count high sum highsum max location\n" );
00968 printf( "-------------------------------------------------\n" );
00969
00970 fmt = "%6ld %6ld %8ld %8ld %8ld %s:%d\n";
00971
00972 for ( nn = 0; nn < count; nn++ )
00973 {
00974 FT_MemSource source = sources[nn];
00975
00976
00977 printf( fmt,
00978 source->cur_blocks, source->max_blocks,
00979 source->cur_size, source->max_size, source->cur_max,
00980 FT_FILENAME( source->file_name ),
00981 source->line_no );
00982 }
00983 printf( "------------------------------------------------\n" );
00984
00985 ft_mem_table_free( table, sources );
00986 }
00987 }
00988
00989 #else
00990
00991
00992 typedef int _debug_mem_dummy;
00993
00994 #endif
00995
00996
00997