summaryrefslogtreecommitdiff
path: root/test/spass/memory.c
blob: a785515d302e5d686bc0f384e3195805b18b2057 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *        DYNAMIC MEMORY MANAGEMENT MODULE                * */
/* *                                                        * */
/* *  $Module:   MEMORY                                     * */ 
/* *                                                        * */
/* *  Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001      * */
/* *  MPI fuer Informatik                                   * */
/* *                                                        * */
/* *  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.  See the GNU General Public * */
/* *  License for more details.                             * */
/* *                                                        * */
/* *  You should have received a copy of the GNU General    * */
/* *  Public License along with this program; if not, write * */
/* *  to the Free Software Foundation, Inc., 59 Temple      * */
/* *  Place, Suite 330, Boston, MA  02111-1307  USA         * */
/* *                                                        * */
/* *                                                        * */
/* $Revision: 21527 $                                        * */
/* $State$                                            * */
/* $Date: 2005-04-24 21:10:28 -0700 (Sun, 24 Apr 2005) $                             * */
/* $Author: duraid $                                       * */
/* *                                                        * */
/* *             Contact:                                   * */
/* *             Christoph Weidenbach                       * */
/* *             MPI fuer Informatik                        * */
/* *             Stuhlsatzenhausweg 85                      * */
/* *             66123 Saarbruecken                         * */
/* *             Email: weidenb@mpi-sb.mpg.de               * */
/* *             Germany                                    * */
/* *                                                        * */
/* ********************************************************** */
/**************************************************************/


/* $RCSfile$ */

#include "memory.h"

unsigned int  memory_PAGESIZE;   /* size of a page                            */
long          memory_MAXMEM;     /* amount of memory available for allocation */
static int    memory__EOF = EOF; /* internal "End Of Memory" marker           */
unsigned long memory_NEWBYTES;   /* number of allocated bytes                 */
unsigned long memory_FREEDBYTES; /* number of freed bytes                     */

const unsigned int memory_ALIGN = sizeof(POINTER); 
/* Crucial: hardware must support access to words 
   of size POINTER.
*/

#ifdef CHECK
unsigned int memory_LEFTTAG;     /* size of left debug mark                   */
unsigned int memory_OFFSET;      /* alignment-correct size of left debug mark */
unsigned int memory_MARKSIZE;    /* total size of debug marks                 */

BOOL         memory_MANAGEMENT_INITIALIZED = FALSE;

#else  /* CHECK not defined */
unsigned int memory_MARKSIZE = 0;
unsigned int memory_OFFSET   = 0;
#endif /* CHECK */

const unsigned int memory_MAGICMALLOC = 1; /* "block allocated" marker */
const unsigned int memory_MAGICFREE   = 2; /* "block freed" marker     */

/* Internal array of resources for different block sizes */
/* ... + 1 to support odd values for memory__SHAREDPAGES like 7 */
static MEMORY_RESOURCE memory_PAGES[memory__DYNMAXSIZE/memory__SHAREDPAGES + 1];


/* Resources for all administrated block sizes */
MEMORY_RESOURCE * memory_ARRAY[memory__DYNMAXSIZE];

/* double linked list for administering blocks of memory
   whose size is greater or equal to memory__DYNMAXSIZE.
*/ 
MEMORY_BIGBLOCKHEADER memory_BIGBLOCKS = NULL;

/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *  INITIALIZATION                                        * */
/* *                                                        * */
/* ********************************************************** */
/**************************************************************/

#ifdef CHECK
static BOOL memory_ManagementInitialized(void)
/**********************************************************
   INPUT  : None.
   RETURNS: TRUE if memory management is already initialized,
            else FALSE.
   SUMMARY: Checks if memory_Init was called.
**********************************************************/
{
  return memory_MANAGEMENT_INITIALIZED;
}
#endif /* CHECK */

void memory_Init(long Maxmem)
/*************************************************************
  INPUT  : The maximal amount of memory available in bytes 
           for the memory module; if Maxmem < 0 the module 
           allocates as much memory as available from the 
           system.
  RETURNS: None.
  SUMMARY: Initializes the memory management. It has to be 
           called before you can perform any module operation. 
           This function automatically increases the default 
           page size if it is too small for two objects of 
           size memory__DYNMAXSIZE.
*************************************************************/
{
  int i;
  int extra;             /* size of internally used space on each page  */

  memory_FREEDBYTES = 0; /* set total number of freed bytes to zero     */
  memory_NEWBYTES   = 0; /* set total number of allocated bytes to zero */

  /* set the size of a page we allocate from the operating system */
  memory_PAGESIZE   = memory__DEFAULTPAGESIZE;

#ifdef CHECK

  /* Test if memory management has already been initialized */
 
  if (!memory_ManagementInitialized()) {
    /* if that is not the case, set check variable to TRUE */
    memory_MANAGEMENT_INITIALIZED = TRUE;
  }
  else {
    /* otherwise the user is trying initialize it for a 
       second time, so print an error and exit.
    */
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In memory_Init:");
    misc_UserErrorReport("\n Memory Error.");
    misc_UserErrorReport(" Trying to initialize memory management");
    misc_UserErrorReport(" for a second time.\n");
    misc_FinishUserErrorReport();
  }

  /* Calculate the size of debug marks */
  memory_LEFTTAG  = sizeof(MEMORY_INFONODE) + sizeof(unsigned int);

  if ((sizeof(MEMORY_INFONODE) + sizeof(unsigned int)) % memory_ALIGN == 0) {
    memory_OFFSET   = memory_LEFTTAG;
  }
  else {
    memory_OFFSET   = memory_LEFTTAG + memory_ALIGN 
      - (memory_LEFTTAG % memory_ALIGN);
  }

  if ((sizeof(unsigned int) % memory_ALIGN) == 0) {
    memory_MARKSIZE =  memory_OFFSET + sizeof(unsigned int);
  }
  else {
    memory_MARKSIZE =  memory_OFFSET + sizeof(unsigned int) + memory_ALIGN 
      - (sizeof(unsigned int) % memory_ALIGN);
  }
#endif

  /* Calculate the size of internally used space on each page */
  /* extra: One pointer for chaining pages, one for EOF (+ marksize) */
  extra = 2*sizeof(POINTER) + memory_MARKSIZE; 


  /* Test whether page size is reasonable with respect 
     to dynamic allocation threshold
  */
  while (memory_PAGESIZE < (2*(memory__DYNMAXSIZE + memory_MARKSIZE) + extra)) {
    /* Minimum two objects per allocated page */
    memory_PAGESIZE += memory__DEFAULTPAGESIZE/2;    
  }

  /* Set amount of memory available to the module for allocation */
  if (Maxmem <= 0) {
    /* unlimited (limited only by the operating system) */
    memory_MAXMEM = memory__UNLIMITED;
  }
  else {
    /* Maxmem bytes */
    memory_MAXMEM = Maxmem;
  }

  /* Initialize memory_ARRAY and memory_RESOURCEs */
  for (i=1; i<memory__DYNMAXSIZE; i++) {
    MEMORY_RESOURCE *CurrentResource;
    int             TotalSize;

    /* Map memory_ARRAY[i] to appropriate Resource */
    memory_ARRAY[i]               = &memory_PAGES[(i-1)/memory__SHAREDPAGES];

    CurrentResource = memory_ARRAY[i];

    CurrentResource->free            = &memory__EOF; /* no blocks freed     */
    CurrentResource->next            = &memory__EOF; /* no blocks allocated */
    CurrentResource->end_of_page     = &memory__EOF; /* no (end of) page    */
    CurrentResource->page            = &memory__EOF; /* no page allocated   */

    /* Size of a properly aligned block of requested size i */
    CurrentResource->aligned_size    = memory_CalculateRealBlockSize(i);

    /* Total block size including debug marks */
    CurrentResource->total_size      = memory_MARKSIZE 
      + CurrentResource->aligned_size;

    TotalSize                        = CurrentResource->total_size;

    /* last block´s offset */
    CurrentResource->offset          =
      ((memory_PAGESIZE-extra)/TotalSize)*TotalSize 
      + sizeof(POINTER) + memory_OFFSET;
  }
}


void memory_Restrict(long Maxmem)
/*************************************************************
  INPUT  : The maximal amount of memory available for further 
           allocation (in bytes); if Maxmem < 0 future 
           allocations are unrestricted.
  RETURNS: None.
  SUMMARY: Sets the maximal amount of memory available for 
           future allocations. If the user tries to allocate 
           more memory, the module displays an error message 
           and terminates the program by calling the exit() 
           function.
*************************************************************/
{
  /* Reset the maximum amount of memory available */ 
  if (Maxmem <= 0) {
    /* unlimited */
    memory_MAXMEM = memory__UNLIMITED;
  }
  else {
    /* Maxmem bytes */
    memory_MAXMEM = Maxmem;
  }
}

/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *  CHECK CODE                                            * */
/* *                                                        * */
/* ********************************************************** */
/**************************************************************/

#ifdef CHECK
static void memory_CheckIfModuleIsInitialized(const char * Function,
				       const char * File,
				       unsigned short int Line)
/********************************************************
  INPUT  : The name of the function that requests the
           check, the name of the file and the line, 
	   where the requesting function was called, and
	   the line.
  RETURNS: None.
  SUMMARY: Checks if the memory management module has
           been properly initialized. You need to
	   initialize the module by calling memory_Init
	   before you use any functions from the module.
	   If the check fails, this function prints an
	   error message and exits the application.
*********************************************************/
{
  if (!memory_ManagementInitialized()) {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s:", Function);
    misc_UserErrorReport("\n Memory Error.");
    misc_UserErrorReport(" Memory management is not initialized.");
    misc_UserErrorReport("\n You have to call memory_Init()");
    misc_UserErrorReport(" before you can use memory management functions.\n");
    misc_UserErrorReport("\n Error occurred in %s", Function);
    misc_UserErrorReport(" called from file %s at line %d.\n",
			 File, Line);
    misc_FinishUserErrorReport();
  }
}

static void memory_CheckIfPointerIsAlreadyFreed(POINTER Pointer,
					 const char * Function,
					 const char * File,
					 unsigned short int Line)
/********************************************************
  INPUT  : The pointer to be checked, the name of the
           function that requests the check, the name of
	   the file and the line, where the requesting
	   function was called, and the line.
  RETURNS: None.
  SUMMARY: Checks if the pointer has already been freed.
	   If the check fails, this function prints an
	   error message and exits the application.
*********************************************************/
{
  if ( memory_GetBlockStatus(Pointer) == memory_MAGICFREE) {
    MEMORY_INFO  Info;          /* block´s debug information      */

    Info = (MEMORY_INFO) ((char *) Pointer - memory_OFFSET);

    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In %s:", Function);
    misc_UserErrorReport("\n Memory Error.");
    misc_UserErrorReport(" Pointer %p was allocated in file %s at line %d.",
			 Pointer, Info->mallocInFile, Info->mallocAtLine);
    misc_UserErrorReport("\n It has already been freed in file %s at line %d.",
			 Info->freeInFile, Info->freeAtLine);
    misc_UserErrorReport("\n Size of memory block is %d bytes.",
			 memory_GetBlockSize(Pointer));
    misc_UserErrorReport("\n Error occurred in %s", Function);
    misc_UserErrorReport(" called from file %s at line %d.\n",
			 File, Line);
    misc_FinishUserErrorReport();
  }
}

static void memory_CheckPointer(POINTER Pointer, unsigned int Size) 
/*********************************************************
  INPUT  : A pointer to a block of memory, and its size.
  RETURNS: Nothing.
  SUMMARY: Checks whether a pointer points to a valid
           block of memory.
	    
           This function performs the following tests:

           Is Pointer a NULL pointer?

           Is Size equal to zero?

           Is the Pointer alignment correct?
	
           Did someone write over the memory block 
           boundaries?

           Is Size still correct?

           If Size is greater than memory__DYNMAXSIZE: 
           Is it properly administrated by the module?

           If the memory block was freed: Did someone 
           write to it after deallocation?
*********************************************************/
{

  MEMORY_INFO Info;
  unsigned int BlockSize, RealBlockSize, BlockStatus;

  Info = (MEMORY_INFO) ((char *) Pointer - memory_OFFSET);

  RealBlockSize = memory_LookupRealBlockSize(Size);

  if (Pointer == NULL) {
    /* NULL pointers must not be dereferenced */
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In memory_CheckPointer:");
    misc_UserErrorReport("\n Memory Error. Pointer is a NULL pointer.\n");
    misc_FinishUserErrorReport();
  }


  if (Size == 0) {
    /* We don´t allocate 0 byte sized blocks */
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In memory_CheckPointer:");
    misc_UserErrorReport("\n Memory Error.");
    misc_UserErrorReport(" Pointer %p points to a block of memory", Pointer);
    misc_UserErrorReport(" with size 0.\n"); 
    misc_FinishUserErrorReport();
  }

  if ((unsigned long)Pointer % (unsigned long)memory_ALIGN){
    /* we expect all pointers to be correctly aligned */
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In memory_CheckPointer:");
    misc_UserErrorReport("\n Memory Error.");
    misc_UserErrorReport(" Pointer %p is not a legal pointer.\n", Pointer);
    misc_FinishUserErrorReport();
  }

  /* BlockStatus and BlockSize are initialized after
     we can be sure Pointer is properly aligned.
  */

  BlockStatus   = memory_GetBlockStatus(Pointer);
  BlockSize     = memory_GetBlockSize(Pointer);

  if (BlockStatus != memory_MAGICMALLOC 
      && BlockStatus != memory_MAGICFREE) {

    /* we expect block status to be either 
       memory_MAGICMALLOC or memory_MAGICFREE.
       Other values might result from overwriting,
       trying to return an unallocated block,
       or trying to return a block allocated with
       another allocator.
    */

    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In memory_CheckPointer:");
    misc_UserErrorReport("\n Memory Error.");
    misc_UserErrorReport(" Pointer %p was not (de)allocated by the module,",
			 Pointer);
    misc_UserErrorReport("\n or the memory block was corrupted.\n");
    misc_FinishUserErrorReport();
  }

  if (BlockStatus == memory_MAGICMALLOC) {
    if (BlockSize != Size) {
      
      /* we expect block size in a block´s debug
	 information and given block size to match.
      */

      misc_StartUserErrorReport();
      misc_UserErrorReport("\n In memory_CheckPointer:");
      misc_UserErrorReport("\n Memory Error.");
      misc_UserErrorReport(" Pointer %p was apparently allocated for",
			   Pointer);
      misc_UserErrorReport(" a block of size %d,",
			   BlockSize);
      misc_UserErrorReport("\n but it is expected to be a block of size %d.",
			   Size);
      misc_UserErrorReport("\n Probably the memory block was corrupted.\n");
      misc_FinishUserErrorReport();

      /* since the left dog tag seems to be corrupted we can not safely assume 
	 that our memory info structure is still valid so we can't print it*/
    }

    if ((Size % memory_ALIGN) || (Size % memory__SHAREDPAGES)) {
      /* check the fillbytes between used storage 
	 and dog tag for overwriting */
      char * ptr, * limit;
      
      limit    = (char *)Pointer + RealBlockSize;
      
      for (ptr = (char *)Pointer + Size; ptr < limit; ptr++) {
	if (*ptr != memory__FREESHREDDER) {
	  misc_StartUserErrorReport();
	  misc_UserErrorReport("\n In memory_CheckPointer:");
	  misc_UserErrorReport("\n Memory Error.");
	  misc_UserErrorReport(" Pointer %p was allocated in file %s at line %d,",
			       Pointer, Info->mallocInFile, Info->mallocAtLine);
	  misc_UserErrorReport("\n for a block of size %d.",
			       BlockSize);
	  misc_UserErrorReport("\n The memory block was corrupted.\n");
	  misc_FinishUserErrorReport();
	}
      }
    }
  }

  if (Size >= memory__DYNMAXSIZE) {
    /* we expect big blocks to be correctly linked */
    MEMORY_BIGBLOCKHEADER BigBlockHeader;

    BigBlockHeader = (MEMORY_BIGBLOCKHEADER) ((char *) Pointer - memory_OFFSET 
					      - sizeof(MEMORY_BIGBLOCKHEADERNODE));

    /* this test might crash the program
       if something is wrong with the pointers,
       so you may not get a message every time.
    */
    if (((BigBlockHeader->previous != NULL) 
	 && (BigBlockHeader->previous->next != BigBlockHeader))
	|| ((BigBlockHeader->previous == NULL) 
	    && (memory_BIGBLOCKS != BigBlockHeader))
	|| ((BigBlockHeader->next != NULL) 
	    && (BigBlockHeader->next->previous != BigBlockHeader))) {
      
      misc_StartUserErrorReport();
      misc_UserErrorReport("\n In memory_CheckPointer:");
      misc_UserErrorReport("\n Memory Error.");
      misc_UserErrorReport(" Pointer %p was not allocated by the module,",
			   Pointer);
      misc_UserErrorReport("\n or the memory block was corrupted.\n");
      misc_FinishUserErrorReport();
    }
  }
  
  if (BlockStatus == memory_MAGICFREE) {
    /* test if someone wrote over freed memory */
    char * ptr, * limit;
    
    limit = (char *)Pointer + RealBlockSize;

    for (ptr = (char *)Pointer + sizeof(POINTER); ptr < limit ; ptr++){
      /* first sizeof(POINTER) bytes are reserved for the
	 pointer to the next freed block in the list. All
	 other bytes in the block should still have the value
	 of memory__FREESHREDDER
      */
      if (*ptr != memory__FREESHREDDER) {
	misc_StartUserErrorReport();
	misc_UserErrorReport("\n In memory_CheckPointer:");
	misc_UserErrorReport("\n Memory Error.");
	misc_UserErrorReport(" Pointer %p was allocated in file %s at line %d",
			     Pointer, Info->mallocInFile, Info->mallocAtLine);
	misc_UserErrorReport("\n for a block of size %d",BlockSize);
	misc_UserErrorReport("\n and freed in file %s at line %d.",
			     Info->freeInFile, Info->freeAtLine);
	misc_UserErrorReport("\n The memory block was used after deallocation.\n");
	misc_FinishUserErrorReport();
      }
    }
  }
}

void memory_CheckFree(POINTER Freepointer, unsigned int Size,
		      unsigned int RealBlockSize, const char * File,
		      unsigned short int Line)
/**********************************************************
   INPUT  : The pointer to be freed, the size of the block
            it is supposed to point to, the real size of
	    that block, the file and line where memory_Free
	    was called.
   RETURNS: None.
   SUMMARY: Checks if memory management was initialized,
            the given pointer is legal, and not freed
	    already. It also zeroes the freed memory, and
	    sets the block's debug and administration
	    information.
**********************************************************/
{
  MEMORY_INFO  Info;          /* block´s debug information      */

  /* Check if memory management was initialized */
  memory_CheckIfModuleIsInitialized("memory_Free", File, Line);

  /* Check if given pointer is legal */
  memory_CheckPointer(Freepointer, Size);

  /* Check if current pointer is being freed for a second time */
  memory_CheckIfPointerIsAlreadyFreed(Freepointer, "memory_Free", File, Line);

  /* Set all bytes to zero, so we can detect overwriting of freed memory */
  memset (Freepointer, memory__FREESHREDDER, RealBlockSize);

  /* Get current block´s debug information */
  Info = (MEMORY_INFO) ((char *) Freepointer - memory_OFFSET);

  /* Set block´s debug and administration information */
  memory_SetInfo(Info,Info->mallocInFile, Info->mallocAtLine, File, Line);
  memory_SetBlockStatusAndSize(Freepointer, memory_MAGICFREE, Size);
}
#endif /* CHECK */

/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *  MALLOC                                                * */
/* *                                                        * */
/* ********************************************************** */
/**************************************************************/

#ifdef NO_MEMORY_MANAGEMENT

POINTER memory_Malloc(unsigned int Bytes)
{
  char *mem; /* pointer to memory block obtained from malloc */

  /* Pass the call through to compiler´s malloc */
  mem = (char *)malloc(Bytes);

  /* If malloc fails print an error message and exit */
  if (mem == NULL) {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In memory_Malloc:");
    misc_UserErrorReport("\n Memory Error. Out of memory.\n");
    misc_FinishUserErrorReport();
  }

  return mem;
}

#else

#ifdef CHECK
POINTER memory_MallocIntern(unsigned int Bytes, 
			    const char * File, 
			    unsigned short int Line)
#else
POINTER memory_Malloc(unsigned int Bytes)
#endif
/********************************************************
  INPUT  : The size of the requested memory block.      
  RETURNS: A pointer to a block of <Bytes> bytes.       
  SUMMARY: Allocates a memory block of requested length.
  EXCEPT : Trying to allocate 0 bytes, violating a memory 
           restriction, or running out of system memory 
    	   cause the function to print an error message and 
	   call exit().
*********************************************************/
{
  char                *NewMemory;       /* pointer to allocated memory */

  MEMORY_RESOURCE     *Resource;        /* current page resource,
					   required if we do not allocate 
					   a big block */

#ifdef CHECK
  MEMORY_INFO         NewInfo;          /* Storage for file and line 
					   of allocation */
#endif


#ifdef CHECK
  /* Is the module initialized? */
  memory_CheckIfModuleIsInitialized("memory_Malloc", File, Line);

  /* Is it a request for a block of zero bytes? */
  if (Bytes == 0) {
    /* The latest draft for the ANSI C 9X standard says in section 7.20.3:

       "If the size of the space requested is zero, the behavior is
        implementation-defined: either a null pointer is returned, or
	the behavior is as if the size were some nonzero value,
	except that the pointer shall not be used to access an object."

	We have decided to print an error and exit upon such requests 
	since they are often originated by a bug. 

	Nonstandard but hopefully helpful.
    */

    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In memory_Malloc:");
    misc_UserErrorReport("\n Memory Error. Tried to allocate 0 Bytes!");
    misc_UserErrorReport("\n Error occurred in memory_Malloc");
    misc_UserErrorReport(" called from file %s at line %d.\n",
			 File, Line);
    misc_FinishUserErrorReport();
  }
#endif
  
  /* If it is a big block, then it has to be 
     administrated in a special way 
  */
  if (Bytes >= memory__DYNMAXSIZE) {
    unsigned int        RealBigBlockSize; /* real block size including 
					     padding,header 
					     and debug marks */

    /* This is what a big block looks like:

       --------------------------------------------------------------------
       | MEMORY_BIGBLOCKHEADERNODE   | debug marks | char * | debug marks |
       | previous and next big block |in debug mode| block  |in debug mode|
       --------------------------------------------------------------------
    */


    /* Calculate the real size of the big block, 
       from the size of administration information,
       the size of debug marks and the requested block size
    */

    RealBigBlockSize = sizeof(MEMORY_BIGBLOCKHEADERNODE) + 
      memory_MARKSIZE + memory_CalculateRealBlockSize(Bytes);

    /* Check for violation of maximum allocation limit */
    if (memory_MAXMEM >= 0) {
      /* there is a maximum allocation limit, 
	 let´s see if there is enough left 
      */
      if ((unsigned int)memory_MAXMEM < RealBigBlockSize) {
	/* if it is not print an error message and exit */
	misc_StartUserErrorReport();
	misc_UserErrorReport("\n In memory_Malloc:");
	misc_UserErrorReport("\n Memory Error.");
	misc_UserErrorReport(" Terminated by user given memory restriction,\n");
	misc_UserErrorReport("\n while trying to allocate %lu bytes.\n", 
			     RealBigBlockSize);
	misc_UserErrorReport("\n Maximum amount of memory");
	misc_UserErrorReport(" left for allocation is %l bytes.\n", 
			     memory_MAXMEM);
#ifdef CHECK
	misc_UserErrorReport("\n Error occurred in memory_Malloc");
	misc_UserErrorReport(" called from file %s at line %d.\n",
			     File, Line);
#endif
	misc_FinishUserErrorReport();
      } 
      else
	/* otherwise subtract the real block size 
	   from the amount of memory available for 
	   allocation
	*/
	memory_MAXMEM -= RealBigBlockSize;
    }

    /* allocate a fresh block of memory via a call to malloc */
    NewMemory = (char *)malloc(RealBigBlockSize);

    /* Check if allocation was successful */
    if (NewMemory != NULL) {

      /* if it was, then administrate the fresh block:
	 insert it into the big block list. The list 
	 is double linked for fast deletion 
      */

      MEMORY_BIGBLOCKHEADER NewBigBlock; /* new block´s administration 
					    information */

      /* insert the fresh block as the first list element */
      NewBigBlock = (MEMORY_BIGBLOCKHEADER) NewMemory;
      NewBigBlock->next = memory_BIGBLOCKS;
      NewBigBlock->previous = NULL;

      /* if there are already elements in the big block list,
	 change the first element´s pointer to the previous block
	 to point to the fresh block´s administration information
      */
      if (memory_BIGBLOCKS != NULL) {
	memory_BIGBLOCKS->previous = NewBigBlock;
      }

      /* reset the big block list pointer to point to the fresh block */ 
      memory_BIGBLOCKS = NewBigBlock;

      /* skip the administration information */
      NewMemory += sizeof(MEMORY_BIGBLOCKHEADERNODE);

#ifdef CHECK
      /* set the debug information address */
      NewInfo = (MEMORY_INFO) NewMemory;

      /* skip left debug mark */
      NewMemory += memory_OFFSET;
#endif

      /* add block´s real size to the total sum of allocated bytes */
      memory_NEWBYTES    += RealBigBlockSize;
    }
    else {
      /* NewMemory == NULL. 
	 malloc could not allocate a memory block of required size,
	 so we print an error message and exit 
      */
      misc_StartUserErrorReport();
      misc_UserErrorReport("\n In memory_MallocIntern:");
      misc_UserErrorReport("\n Memory Error. Out of memory.");
      misc_UserErrorReport("\n Failed to allocate %d bytes.\n", 
			   RealBigBlockSize);
#ifdef CHECK
      misc_UserErrorReport("\n Error occurred in memory_Malloc");
      misc_UserErrorReport(" called from file %s at line %d.\n",
			   File, Line);
#endif
      misc_FinishUserErrorReport();
    }
  }
  else {
    /* Bytes < memory__DYNMAXSIZE.
       A memory request for a manageable size 
    */

    /* Initialize the memory resource for the given size */
    Resource = memory_ARRAY[Bytes];


    /* Check if there are freed blocks of that size */
    if (*((int *)Resource->free) != EOF) {

      /* if that is the case, then use an already freed block */

      NewMemory                 = (char *) Resource->free;

      /* update the free blocks list for that size */
      Resource->free            = *((POINTER *)(NewMemory));

      /* subtract block´s total size from the sum of freed bytes */
      memory_FREEDBYTES        -= Resource->total_size;

#ifdef CHECK
      /* calculate the address of the block´s debug information */ 
      NewInfo = (MEMORY_INFO) ((char*) NewMemory - memory_OFFSET);

      /* Check if the block has been used after deallocation */
      memory_CheckPointer(NewMemory, Bytes);  
#endif
    } 
    else { 
      /* there are no already freed blocks of that size */
 
      /* Check if there is enough space left on current page */
      if (Resource->next != Resource->end_of_page) {

	/* if that is the case, then use a fresh block from current page */
	NewMemory                = (char *)Resource->next;

	/* update the pointer to the next usable block */
	Resource->next           = NewMemory + Resource->total_size;

	/* add block´s total size to the sum of allocated bytes */
	memory_NEWBYTES         += Resource->total_size;

#ifdef CHECK
	/* Check if the fresh block´s address is sane */
	if ((char *)NewMemory > (char *) Resource->end_of_page) {
	  /* if it is not, then we have detected an internal error
	     in the module itself. Oops! So we print an error message
	     and abort, hoping that the core dump will enable us to 
	     trace the error back to its origin
	  */
	  misc_StartErrorReport();
	  misc_ErrorReport("\n In memory_Malloc:");
	  misc_ErrorReport("\n Memory Error. Address overflow %d.",Bytes);
	  misc_ErrorReport("\n Error occurred in memory_Malloc");
	  misc_ErrorReport(" called from file %s at line %d.\n", File, Line);
	  misc_FinishErrorReport();
	}

	/* if all is well, we initialize the pointer to fresh block´s
	   debug information 
	*/
	NewInfo = (MEMORY_INFO)((char*) NewMemory - memory_OFFSET);
#endif

      } 
      else { 
	/* Check for violation of maximum allocation limit */
	if (memory_MAXMEM >=0) {
	  /* there is a maximum allocation limit, 
	     let´s see if there is enough left
	  */
	  if ((unsigned int)memory_MAXMEM < memory_PAGESIZE) {
	    /* if it is not, then print an error message and exit */
	    misc_StartUserErrorReport();
	    misc_UserErrorReport("\n In memory_Malloc:");
	    misc_UserErrorReport("\n Memory Error.");
	    misc_UserErrorReport(" Terminated by user given memory restriction.\n");
#ifdef CHECK
	    misc_UserErrorReport("\n Error occurred in memory_Malloc");
	    misc_UserErrorReport(" called from file %s at line %d.\n",
				 File, Line);
#endif
	    misc_FinishUserErrorReport();
	  } 
	  else {
	    /* otherwise subtract the page size from the limit */
	    memory_MAXMEM -= memory_PAGESIZE;
	  }
	}

	/* try to allocate a new page via malloc */
	NewMemory=(char *)malloc(memory_PAGESIZE);

	/* check if allocation was successful */
	if (NewMemory == NULL) {
	  /* if it wasn´t print an error message and exit */
	  misc_StartUserErrorReport();
	  misc_UserErrorReport("\n In memory_Malloc:");
	  misc_UserErrorReport("\n Memory Error.");
	  misc_UserErrorReport(" Terminated, ran out of system memory.\n");
#ifdef CHECK
	  misc_UserErrorReport("\n Error occurred in memory_Malloc");
	  misc_UserErrorReport(" called from file %s at line %d.\n",
			       File, Line);
#endif
	  misc_FinishUserErrorReport();
	}

	/* otherwise administrate the fresh page,
	   i.e insert it as the first element of the 
	   page list for the given size 
	*/
	*((POINTER *)NewMemory)     = Resource->page;
	Resource->page              = NewMemory;

	/* add block´s total size to the sum of allocated bytes */
	memory_NEWBYTES            += Resource->total_size;

	/* set the end of page pointer for the fresh page */
	Resource->end_of_page       = (char *) NewMemory + Resource->offset;

	/* skip the page list */
	NewMemory += sizeof(POINTER);

#ifdef CHECK
	/* set the debug information address */
	NewInfo    = (MEMORY_INFO) NewMemory;

	/* skip the left debug mark */
	NewMemory += memory_OFFSET;
#endif

	/* update the pointer to the next usable block */	
	Resource->next              = NewMemory + Resource->total_size;
      }
    }
  }

#ifdef CHECK
  /* Set block´s debug information */
  memory_SetInfo(NewInfo, File, Line, NULL, 0);
  memory_SetBlockStatusAndSize(NewMemory,  
			       memory_MAGICMALLOC, Bytes);

  /* delete all block´s usable bytes with a shredder value */
  memset(NewMemory, memory__FREESHREDDER,
	 memory_LookupRealBlockSize(Bytes));
#endif

  return NewMemory;
}

#endif



#ifdef NO_MEMORY_MANAGEMENT

POINTER memory_Calloc(unsigned int Elements, unsigned int Bytes)
{
  char *mem; /* pointer to memory block obtained from calloc */

  /* Pass call through to compiler´s calloc */
  mem = (char *)calloc(Elements, Bytes);
  
  /* If calloc fails print an error message and exit */
  if (mem == NULL) {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In memory_Calloc:");
    misc_UserErrorReport("\n Memory Error. Out of memory.\n");
    misc_FinishUserErrorReport();
  }

  return mem;
}

#else

#ifdef CHECK
POINTER memory_CallocIntern(unsigned int Elements, unsigned int Bytes, 
			    const char * File, unsigned short int Line)
#else
POINTER memory_Calloc(unsigned int Elements, unsigned int Bytes)
#endif
/********************************************************
  INPUT  : The number of requested equally huge blocks, 
           and each block's size.
  RETURNS: A pointer to a block of (Bytes * Elements) bytes.
  SUMMARY: Allocates a memory block of requested length
           filled with char value '\0'.
*********************************************************/
{
  char       * mem; /* pointer to memory block obtained from the module */

  /* Allocate memory via our memory management */
#ifdef CHECK
  mem = (char *)memory_MallocIntern(Elements * Bytes, File, Line);
#else
  mem = (char *)memory_Malloc(Elements * Bytes);
#endif

  /* If allocation was successful set all bytes to zero */ 
  if (mem != NULL) {
    memset(mem,0, Elements * Bytes);
  }
  /* otherwise print an error message and exit */
  else {
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In memory_Calloc:");
    misc_UserErrorReport("\n Memory Error. Out of memory.\n");
#ifdef CHECK
    misc_UserErrorReport("\n Error occurred in memory_Calloc");
    misc_UserErrorReport(" called from file %s at line %d.\n",
			 File, Line);
#endif
    misc_FinishUserErrorReport();
  }

  return mem;
}
#endif

void memory_FreeAllMem(void) 
/**************************************************************
  INPUT  : None.
  RETURNS: None.
  SUMMARY: Frees all memory allocated by calls to the module.
***************************************************************/
{
  int i;

  /* delete all pages first by going through the memory_ARRAY.
     This is slower than traversing the array memory_PAGES
     directly, but is easier to implement correctly. Since
     the only reasonable way to call memory_FreeAllMem is
     before the program exits, a minimal performance penalty
     should be acceptable
  */

  for (i = 1; i < memory__DYNMAXSIZE; i++) {
    POINTER thispage, nextpage;
    MEMORY_RESOURCE * Resource;

    Resource = memory_ARRAY[i];

    thispage = Resource->page;

    if (*((int *)thispage) != EOF) {
      do {
	nextpage = *((POINTER *)thispage);
	free(thispage);
	thispage = nextpage;
      } while  (*((int *)thispage) != EOF);

      /* and reset the resource structure */
      Resource->page        = &memory__EOF;
      Resource->free        = &memory__EOF;
      Resource->next        = &memory__EOF;
      Resource->end_of_page = &memory__EOF;
    }
  }

  /* now delete all big blocks left */

  if (memory_BIGBLOCKS != NULL) {
    MEMORY_BIGBLOCKHEADER thisblock, nextblock;
    
    for (thisblock = memory_BIGBLOCKS; 
	 thisblock != NULL; 
	 thisblock = nextblock) {
      nextblock = thisblock->next;
      free(thisblock);
    }

    /* and reset the list pointer */
    memory_BIGBLOCKS = NULL;
  }
}

/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *  DEBUGGING INFORMATION                                 * */
/* *                                                        * */
/* ********************************************************** */
/**************************************************************/

void memory_Print(void)
/**************************************************************
  INPUT  : None.
  RETURNS: None.
  SUMMARY: Prints module status information to stdout:
           the fixed size of an internal memory page, the size 
	   of debug marks for a block of memory, the size of 
	   demanded and freed memory in kilobytes, remaining 
	   memory in bytes and the number of allocated pages of 
	   memory.
***************************************************************/
{
#ifndef NO_MEMORY_MANAGEMENT
  /* Call memory_FPrint to print status information to stdout */
  memory_FPrint(stdout);
#endif
}

void memory_FPrint(FILE* File)
/**************************************************************
  INPUT  : A file pointer.
  RETURNS: None.
  SUMMARY: Prints module status information to given File:
           the fixed size of an internal memory page, the size 
	   of debug marks for a block of memory, the size of 
	   demanded and freed memory in kilobytes, remaining 
	   memory in bytes and the number of allocated pages of 
	   memory.
***************************************************************/
{
#ifndef NO_MEMORY_MANAGEMENT
  int     Pages;    /* number of allocated pages                  */
  int     i;
  POINTER ActPage;  /* current page in page list for a block size */

  /* Calculate the total number of pages */
  Pages = 0;
  for (i = 1; i < memory__DYNMAXSIZE; i+=memory__SHAREDPAGES) {
    /* increase i by memory_SHAREDPAGES due to page sharing */
    ActPage = memory_ARRAY[i]->page;

    /* Traverse the page list */
    while (*((int *)ActPage) != EOF) {
      Pages++;
      ActPage = *((POINTER *)ActPage);
    }
  }

  /* Print status information */
  fputs("\n###\n", File);
  fprintf(File,"### Pagesize: %d\n",
	  memory_PAGESIZE);
  fprintf(File,"### Marksize: %d\n",
	  (int)memory_MARKSIZE);
  fprintf(File,"### Memory demanded:  %lu KBytes\n", 
	  memory_NEWBYTES/memory__KILOBYTE);
  fprintf(File,"### Memory freed:     %lu KBytes\n", 
	  memory_FREEDBYTES/memory__KILOBYTE);
  fprintf(File,"### Memory remaining: %lu Bytes\n", 
	  memory_NEWBYTES-memory_FREEDBYTES);
  fprintf(File,"### Pages allocated:  %d Pages\n", 
	  Pages);
  fputs("###\n", File);
#endif
}

void memory_PrintAllocatedBlocks(unsigned int Size)
/**************************************************************
  INPUT  : Block size.
  RETURNS: None.
  SUMMARY: Prints addresses of allocated memory blocks with
           given Size to stdout, if Size is less than 
	   memory_DYNMAXSIZE.
***************************************************************/
{
#ifndef NO_MEMORY_MANAGEMENT
  MEMORY_RESOURCE *Resource;     /* current resource                   */

  POINTER          ActPage;      /* current page                       */
  POINTER          ActNext;      /* next usable block on current page */
  POINTER          ActEndOfPage; /* end of current page                */

  unsigned int     BlockSize;    /* current block size                 */

#ifdef CHECK
  MEMORY_INFO      Info;         /* current block´s debug information  */
#endif

  /* Allocated blocks are administered 
     in two ways depending on their 
     size. If the size is less than
     memory__DYNMAXSIZE the block is
     allocated from the appropriate
     page. Otherwise the block is 
     allocated directly via a call
     to malloc or calloc.

     Thus we have two functions to
     print the allocated blocks:
     memory_PrintAllocatedBlocks and
     memory_PrintAlocatedBigBlocks.
  */


  /* Check if memory_PrintAllocatedBlocks has been called for
     a legal block size
  */

  if (Size >= memory__DYNMAXSIZE) {
    /* if that´s not the case print an error message and exit */
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In memory_PrintAllocatedBlocks:");
    misc_UserErrorReport("\n Parameter size is too big: %d.",
			 Size);
    misc_UserErrorReport("\n Maximal allowed value is: %d.\n", 
			 memory__DYNMAXSIZE);
    misc_FinishUserErrorReport();
  }
  else {
    /* otherwise size is legal */

    /* initialize the variables */
    Resource     = memory_ARRAY[Size];
    ActPage      = Resource->page;
    ActNext      = Resource->next;
    ActEndOfPage = Resource->end_of_page;
    BlockSize    = Resource->total_size;

    /* Test if there were any requests made for blocks of that size */
    if (*((int *)ActPage) == EOF) {
      /* Check if pointers are consistent */
      if (*((int *)ActNext) == EOF) {
	/* If that is true, print that information to stdout */
	puts("   No request so far");
      }
      else {
	/* Otherwise print an error message and abort */
	 misc_StartErrorReport();
	 misc_ErrorReport("\n In memory_PrintAllocatedBlocks:");
	 misc_ErrorReport("\n Memory Error. No Page entry but Next entry.\n");
	 misc_FinishErrorReport();
      }
    }
    else {
      /* We have received some requests for blocks of that size */ 
#ifdef CHECK

      POINTER ActData; /* current block */


      /* Traverse through the page list for given block size */
      while (*((int *)ActPage) != EOF) {

	/* Initialize the variables */
	ActData      = (char *)ActPage + sizeof(POINTER) + memory_OFFSET;
	ActEndOfPage = (char *)ActPage + Resource->offset;

	/* Visit blocks on current page until the end of
	   page is reached, or an allocated block is found
	*/
	while (ActData != ActNext 
	       && ActData != ActEndOfPage
	       && memory_GetBlockStatus(ActData) != memory_MAGICMALLOC) {
	  ActData = (char *)ActData + BlockSize;
	}

	/* Check if there were any allocated blocks from current page */
	if (ActData == ActNext || ActData == ActEndOfPage) {
	  /* if that´s not the case print the information to stdout */
	  printf("\n\n   No memory allocated from page at address %p\n", ActPage);
	}
	else {
	  /* otherwise print address and origin of (de)allocation of
	     all allocated blocks on current page, starting
	     with the block just found
	  */
	  fputs("\n\n   Allocated but not freed: ", stdout);
	  do  {
	    Info = (MEMORY_INFO) ((char *) ActData - memory_OFFSET);
	    if (memory_GetBlockStatus(ActData) == memory_MAGICMALLOC 
		&& memory_GetBlockSize(ActData) == Size) {
	      printf("\n\t%p allocated in file %s at line %d ", 
		     ActData, Info->mallocInFile, Info->mallocAtLine);
	    }
	    ActData = (char *)ActData + BlockSize;
	  } while (ActData != ActNext && ActData != ActEndOfPage);
	}

	/* go to the next page in the page list for given block size */
	ActPage = *((POINTER *)ActPage);
      }
#endif
    }
  }
#endif
}

void memory_PrintFreedBlocks(unsigned int Size)
/**************************************************************
  INPUT  : Block size.
  RETURNS: None.
  SUMMARY: Prints addresses of freed memory blocks with given 
           Size to stdout, if Size is less than 
	   memory_DYNMAXSIZE.
***************************************************************/
{
#ifndef NO_MEMORY_MANAGEMENT
  POINTER     ActFree; /* current block */

#ifdef CHECK
  MEMORY_INFO Info;    /* current block´s debug information */
#endif

  /* since we don´t recycle blocks whose size is
     greater or equal to memory__DYNMAXSIZE, 
     memory_PrintFreedBlocks is meaningless
     for such block sizes.
  */

  /* test if given block size is legal */
  if (Size >= memory__DYNMAXSIZE) {
    /* if that´s not the case print an error message and exit */
    misc_StartUserErrorReport();
    misc_UserErrorReport("\n In memory_PrintFreedBlocks.");
    misc_UserErrorReport("\n Parameter Size is too big: %d.", 
			 Size);
    misc_UserErrorReport("\n Maximal allowed value is: %d.\n", 
			 memory__DYNMAXSIZE);
    misc_FinishUserErrorReport();
  }
  else {
    /* otherwise size is legal */

    /* start at the first element of the free block list
       for the given block size
    */
    ActFree = memory_ARRAY[Size]->free;

    /* test if the free block list is empty */
    if (*((int *)ActFree) == EOF) {
      /* if that´s true, print that information to stdout */
      puts("\n\n   No freed memory");
    }
    else {
      /* otherwise traverse the list of freed blocks */

      fputs("\n\n   Free: ", stdout);
      while (*((int *)ActFree) != EOF) {
#ifdef CHECK
	/* in debug mode print current block´s address
	   and origin of (de)allocation
	*/

	/* check if block´s size is correct */ 
	if ( memory_GetBlockSize(ActFree) == Size) {
	  /* if that´s true than print block´s information */
	  Info = (MEMORY_INFO) ((char *) ActFree - memory_OFFSET);
	  printf("\n\t%p\tallocated in file %s at line %d",
		 ActFree,  Info->mallocInFile, Info->mallocAtLine);
	  printf("\n\t\tfreed in file %s at line %d",
		 Info->freeInFile, Info->freeAtLine);
	}
	else {
	  /* otherwise if we are sharing pages among different
	     block sizes, the block is uncorrupted, despite not 
	     matching assumed and real size. But if we are
	     not sharing pages then the block is probably corrupted, 
	     so print an error message and exit 
	  */

	  /* test if we are not in page sharing mode */
	  if (memory__SHAREDPAGES == 1) {
	    /* if that´s true print an error message and exit */
	    misc_StartUserErrorReport();
	    misc_UserErrorReport("\n In memory_PrintFreedBlocks:");
	    misc_UserErrorReport("\n Memory Error. Memory block size mismatch.");
	    misc_UserErrorReport("\n Expected %d found %d for memory block at %p.\n",
				 Size, memory_GetBlockSize(ActFree), ActFree);
	    misc_UserErrorReport("\n Probably the memory block was corrupted.\n");	    
	    misc_FinishUserErrorReport();
	  }
	}

#endif

	/* go to the next free block in list */
	ActFree = *((POINTER *)ActFree);
      }
    }
  }
#endif
}


void memory_PrintAllocatedBigBlocks(void)
/**************************************************************
  INPUT  : None.
  RETURNS: None.
  SUMMARY: Prints addresses of all allocated memory blocks,
           that are greater than memory_DYNMAXSIZE to stdout.
***************************************************************/
{
#ifndef NO_MEMORY_MANAGEMENT
#ifdef CHECK
  MEMORY_BIGBLOCKHEADER Ptr;         /* current big block in list */
  MEMORY_INFO           Info;        /* block´s debug information */
  char                * BlockStart;  /* block´s start address     */
  
  /* start with the first block in the big block list */
  Ptr = memory_BIGBLOCKS;

  /* check whether big block list isn´t empty */
  if (Ptr != NULL) {
    /* if that´s the case traverse through the list
       and print each block´s address, size and
       origin of (de)allocation information
    */
    do {
      BlockStart = (char *)Ptr + memory_OFFSET 
	+ sizeof(MEMORY_BIGBLOCKHEADERNODE);
      
      Info = (MEMORY_INFO) (BlockStart - memory_OFFSET);
      printf("\n\t%p %d bytes allocated in file %s at line %d ", 
	     (void*)BlockStart, memory_GetBlockSize(BlockStart),
	     Info->mallocInFile, Info->mallocAtLine);
      Ptr = Ptr->next;
    } while (Ptr != NULL);
    puts("");
  }
  else {
    /* otherwise there are no big blocks allocated */
    puts("   No request so far");
  }
#endif
#endif
}

void memory_PrintDetailed(void)
/**************************************************************
  INPUT  : None.
  RETURNS: None.
  SUMMARY: Prints addresses of all pages, and allocated and freed 
           blocks on them.
***************************************************************/
{
#ifndef NO_MEMORY_MANAGEMENT
  MEMORY_RESOURCE  *Resource;     /* current resource                      */

  POINTER           ActPage;      /* current page                          */
  POINTER           ActData;      /* current block                         */
  POINTER           ActEndOfPage; /* end of current page                   */
  unsigned int      BlockSize;    /* total size of a block of current size */
  unsigned int      PageOffset;   /* current page´s offset                 */

  unsigned int      i;


  /* print end-of-memory pointer´s address */
  printf("\n\nEOF Pointer: %p\n", (void*)&memory__EOF);

  /* for all administrated block sizes print detailed information */
  for (i=1; i<memory__DYNMAXSIZE; i++) {
    /* initialize variables for requested block size i */
    Resource     = memory_ARRAY[i];
    ActPage      = Resource->page;
    ActData      = Resource->next;
    ActEndOfPage = Resource->end_of_page;
    PageOffset   = Resource->offset;
    BlockSize    = Resource->total_size;

    /* print requested block size, aligned block size 
       and block size including debug marks
    */
    printf("\n\n Entry: %d aligned size: %d total size: %d\n", 
	   i , Resource->aligned_size, BlockSize);

    /* Check if there were any requests for blocks of size i */
    if (*((int *)ActPage) == EOF) {
      /* if that´s not the case check if memory management is consistent */
      if (*((int *)ActData) == EOF) {
	/* if that´s true, print that no requests occurred to stdout */
	puts("   No request so far");
      }
      else {
	/* our memory management is no longer consistent, 
	   so print an error message and abort. We hope that
	   the core dump will help us to find the bug
	*/
	misc_StartErrorReport();
	misc_ErrorReport("\n In memory_PrintDetailed:");
	misc_ErrorReport("\n Memory Error. No Page entry but Next entry.\n");
	misc_FinishErrorReport();
      }
    }
    else {
      /* we have received requests for blocks of size i */

      /* traverse the list of pages for size i */
      while (*((int *)ActPage) != EOF) {
	/* print information about current page */
	printf("\n\n   Page: %p Next Page: %p\n",
	       ActPage, *((POINTER *)ActPage));

	/* initialize variables for current page */
	ActData = ((char *)ActPage + sizeof(POINTER) + memory_OFFSET);
	ActEndOfPage = (char *)ActPage + PageOffset;

	/* print addresses of all blocks on current page */
	fputs("   Data: ", stdout);
	while (ActData != ActEndOfPage) {
	  int column;

	  fputs("\n\t\t", stdout);
	  for (column = 0; column < 6; column++) {
	    printf("%p ", ActData);
	    ActData = (char *)ActData + BlockSize;
	    if (ActData == ActEndOfPage) {
	      break;
	    }
	  }
	}

	/* go to next page in list */
	ActPage = *((POINTER *)ActPage);
      }

      /* print allocated and freed blocks of size i */
      memory_PrintAllocatedBlocks(i);
      memory_PrintFreedBlocks(i);
    }
  }

#ifdef CHECK
  /* print allocated blocks of size >= memory_DYNMAXSIZE */
  printf("\n\n Allocated blocks of size >= %d\n", 
	 memory__DYNMAXSIZE);
  memory_PrintAllocatedBigBlocks();
#endif
#endif
}


void memory_PrintLeaks(void)
/**************************************************************
  INPUT  : None.
  RETURNS: None.
  SUMMARY: Prints addresses of all allocated blocks. Should be
           used at the end of a program before the call to
	   memory_FreeAllMem.
***************************************************************/
{
#ifndef NO_MEMORY_MANAGEMENT
  POINTER           ActPage;       /* current page                     */
  POINTER           ActNext;       /* next fresh block on current page */
  POINTER           ActEndOfPage;  /* end of current page              */
  MEMORY_RESOURCE  *Resource;      /* current resource                 */
  unsigned int      Size;          /* current size                     */
  unsigned int      BlockSize;     /* total block size                 */

  /* Check if some memory is still allocated */ 
  if (memory_UsedBytes() != 0L) { 

    /* If that´s true, print all allocated blocks  */

    /* Start with blocks administered by our memory management */
    for (Size = 1; Size < memory__DYNMAXSIZE; Size++) {
      /* Initialize variables for current block size */
      Resource     = memory_ARRAY[Size];
      ActPage      = Resource->page;
      ActNext      = Resource->next;
      ActEndOfPage = Resource->end_of_page;
      BlockSize    = Resource->total_size;

      /* Check if there were any requests for 
	 memory blocks of that size */
      if (*((int *)ActPage) != EOF) {
      
	/* if that´s true, browse through all blocks on all pages
	   to find a block that is still allocated
	*/
#ifdef CHECK
	
	POINTER ActData;
	BOOL    LeakFound;
	
	LeakFound = FALSE;
	
	while (*((int *)ActPage) != EOF) {
	  
	  /* search through all pages for a block that is still allocated */
	  
	  ActData      = (char *)ActPage + sizeof(POINTER) + memory_OFFSET;
	  ActEndOfPage = (char *)ActPage + Resource->offset;
	  
	  while (ActData != ActNext && ActData != ActEndOfPage) {
	    if (memory_GetBlockStatus(ActData) == memory_MAGICMALLOC) {
	      LeakFound = TRUE;
	      break;
	    }
	    ActData = (char *)ActData + BlockSize;
	  }
	  
	  if (LeakFound) {
	    
	    /* if we have found one, than call memory_PrintAllocatedBlocks
	       to print its address */
	    
	    printf("\n\n  Leaked blocks of size %d:", Size);
	    
	    memory_PrintAllocatedBlocks(Size);
	    putchar('\n');
	    /* since memory_PrintAllocatedblocks prints 
	     *all* allocated blocks of specific size, we can
	     break out of the while loop
	    */
	    break;
	  }
	  else {
	    /* go to next page */
	    ActPage = *((POINTER *)ActPage);
	  }
	}

#endif

      }      
    }

#ifdef CHECK
    /* Print allocated blocks of size >= memory__DYNMAXSIZE */
    if (memory_BIGBLOCKS != NULL) {
      printf("\n\n  Leaked blocks of size >= %d\n", 
	     memory__DYNMAXSIZE);
      memory_PrintAllocatedBigBlocks();
      putchar('\n');
    }
#endif

  }
#endif
}