VPR-6.0

libvpr/util.c

Go to the documentation of this file.
00001 #include <string.h>
00002 #include <assert.h>
00003 #include <stdio.h>
00004 #include <stdlib.h>
00005 #include "util.h"
00006 
00007 /** 
00008  * @file
00009  *
00010  * This file contains utility functions widely used in 
00011  * my programs.  Many are simply versions of file and  
00012  * memory grabbing routines that take the same         
00013  * arguments as the standard library ones, but exit    
00014  * the program if they find an error condition.        
00015  */
00016 
00017 int linenum;                    /**< Line in file being parsed. */
00018 char *OutFilePrefix = NULL;
00019 static int cont;                /**< line continued? */
00020 
00021 /** Returns the min of cur and max. If cur > max, a warning
00022  * is emitted. 
00023  */
00024 int
00025 limit_value(int cur, int max, const char *name)
00026 {
00027     if(cur > max)
00028         {
00029             printf(WARNTAG "%s is being limited from [%d] to [%d]\n",
00030                    name, cur, max);
00031             return max;
00032         }
00033     return cur;
00034 }
00035 
00036 /* An alternate for strncpy since strncpy doesn't work as most
00037  * people would expect. This ensures null termination */
00038 char *
00039 my_strncpy(char *dest, const char *src, size_t size)
00040 {
00041     /* Find string's length */
00042     size_t len = strlen(src);
00043 
00044     /* Cap length at (num - 1) to leave room for \0 */
00045     if(size <= len)
00046         len = (size - 1);
00047 
00048     /* Copy as much of string as we can fit */
00049     memcpy(dest, src, len);
00050 
00051     /* explicit null termination */
00052     dest[len] = '\0';
00053 
00054     return dest;
00055 }
00056 
00057 /** Uses global var 'OutFilePrefix' */
00058 FILE *
00059 my_fopen(const char *fname, const char *flag, int prompt)
00060 {
00061     FILE *fp;
00062     int Len;
00063     char *new_fname = NULL;
00064         char prompt_filename[256];
00065 
00066     /* Appends a prefix string for output files */
00067     if(OutFilePrefix)
00068         {
00069             if(strchr(flag, 'w'))
00070                 {
00071                     Len = 1;    /* NULL char */
00072                     Len += strlen(OutFilePrefix);
00073                     Len += strlen(fname);
00074                     new_fname = (char *)my_malloc(Len * sizeof(char));
00075                     strcpy(new_fname, OutFilePrefix);
00076                     strcat(new_fname, fname);
00077                     fname = new_fname;
00078                 }
00079         }
00080 
00081         if (prompt) 
00082         {
00083                 scanf("%s",prompt_filename);
00084                 fname = prompt_filename;
00085         }
00086 
00087     if(NULL == (fp = fopen(fname, flag)))
00088         {
00089             printf("Error opening file %s for %s access.\n", fname, flag);
00090             exit(1);
00091         }
00092 
00093     if(new_fname)
00094         free(new_fname);
00095 
00096     return (fp);
00097 }
00098 
00099 char *
00100 my_strdup(const char *str)
00101 {
00102     int Len;
00103     char *Dst;
00104 
00105         if(str == NULL) {
00106                 return NULL;
00107         }
00108 
00109     Len = 1 + strlen(str);
00110     Dst = (char *)my_malloc(Len * sizeof(char));
00111     memcpy(Dst, str, Len);
00112 
00113     return Dst;
00114 }
00115 
00116 /** Returns the integer represented by the first part of the character      
00117  * string.                                              
00118  */
00119 int
00120 my_atoi(const char *str)
00121 {
00122 
00123     if(str[0] < '0' || str[0] > '9')
00124         {
00125             if(!(str[0] == '-' && str[1] >= '0' && str[1] <= '9'))
00126                 {
00127                     printf(ERRTAG "expected number instead of '%s'.\n", str);
00128                     exit(1);
00129                 }
00130         }
00131     return (atoi(str));
00132 }
00133 
00134 void *
00135 my_calloc(size_t nelem, size_t size)
00136 {
00137     void *ret;
00138         if(nelem == 0) {
00139                 return NULL;
00140         }
00141 
00142     if((ret = calloc(nelem, size)) == NULL)
00143         {
00144             fprintf(stderr, "Error:  Unable to calloc memory.  Aborting.\n");
00145             exit(1);
00146         }
00147     return (ret);
00148 }
00149 
00150 void *
00151 my_malloc(size_t size)
00152 {
00153     void *ret;
00154         if(size == 0) {
00155                 return NULL;
00156         }
00157 
00158     if((ret = malloc(size)) == NULL)
00159         {
00160             fprintf(stderr, "Error:  Unable to malloc memory.  Aborting.\n");
00161             abort();
00162             exit(1);
00163         }
00164     return (ret);
00165 }
00166 
00167 void *
00168 my_realloc(void *ptr, size_t size)
00169 {
00170     void *ret;
00171 
00172     if(size <= 0)
00173         {
00174             printf("reallocating of size <= 0.\n");
00175         }
00176 
00177     ret = realloc(ptr, size);
00178     if(NULL == ret)
00179         {
00180             printf(ERRTAG "Unable to realloc memory. Aborting. "
00181                    "ptr=%p, Size=%d.\n", ptr, (int)size);
00182             if(ptr == NULL)
00183                 {
00184                     printf(ERRTAG "my_realloc: ptr == NULL. Aborting.\n");
00185                 }
00186             exit(1);
00187         }
00188     return (ret);
00189 }
00190 
00191 /** This routine should be used for allocating fairly small data             
00192  * structures where memory-efficiency is crucial.  This routine allocates   
00193  * large "chunks" of data, and parcels them out as requested.  Whenever     
00194  * it mallocs a new chunk it adds it to the linked list pointed to by       
00195  * chunk_ptr_head.  This list can be used to free the chunked memory.       
00196  * If chunk_ptr_head is NULL, no list of chunked memory blocks will be kept 
00197  * -- this is useful for data structures that you never intend to free as   
00198  * it means you don't have to keep track of the linked lists.               
00199  * Information about the currently open "chunk" must be stored by the       
00200  * user program.  mem_avail_ptr points to an int storing how many bytes are 
00201  * left in the current chunk, while next_mem_loc_ptr is the address of a    
00202  * pointer to the next free bytes in the chunk.  To start a new chunk,      
00203  * simply set *mem_avail_ptr = 0.  Each independent set of data structures  
00204  * should use a new chunk.                                                  
00205  */
00206 void *
00207 my_chunk_malloc(size_t size, struct s_linked_vptr **chunk_ptr_head,
00208         int *mem_avail_ptr, char **next_mem_loc_ptr)
00209 {
00210 
00211 /* To make sure the memory passed back is properly aligned, I must *
00212  * only send back chunks in multiples of the worst-case alignment  *
00213  * restriction of the machine.  On most machines this should be    *
00214  * a long, but on 64-bit machines it might be a long long or a     *
00215  * double.  Change the typedef below if this is the case.          */
00216 
00217     typedef long Align;
00218 
00219 #define CHUNK_SIZE 32768
00220 #define FRAGMENT_THRESHOLD 100
00221 
00222     char *tmp_ptr;
00223     int aligned_size;
00224 
00225     assert(*mem_avail_ptr >= 0);
00226 
00227     if((size_t) (*mem_avail_ptr) < size)
00228         {                       /* Need to malloc more memory. */
00229             if(size > CHUNK_SIZE)
00230                 {               /* Too big, use standard routine. */
00231                     tmp_ptr = my_malloc(size);
00232 
00233 /* When debugging, uncomment the code below to see if memory allocation size */
00234 /* makes sense */
00235 /*#ifdef DEBUG
00236        printf("NB:  my_chunk_malloc got a request for %d bytes.\n",
00237           size);
00238        printf("You should consider using my_malloc for such big requests.\n");
00239 #endif */
00240 
00241                     if(chunk_ptr_head != NULL)
00242                         *chunk_ptr_head =
00243                             insert_in_vptr_list(*chunk_ptr_head, tmp_ptr);
00244                     return (tmp_ptr);
00245                 }
00246 
00247             if(*mem_avail_ptr < FRAGMENT_THRESHOLD)
00248                 {               /* Only a small scrap left. */
00249                     *next_mem_loc_ptr = my_malloc(CHUNK_SIZE);
00250                     *mem_avail_ptr = CHUNK_SIZE;
00251                     if(chunk_ptr_head != NULL)
00252                         *chunk_ptr_head = insert_in_vptr_list(*chunk_ptr_head,
00253                                                               *next_mem_loc_ptr);
00254                 }
00255 
00256 /* Execute else clause only when the chunk we want is pretty big,  *
00257  * and would leave too big an unused fragment.  Then we use malloc *
00258  * to allocate normally.                                           */
00259 
00260             else
00261                 {
00262                     tmp_ptr = my_malloc(size);
00263                     if(chunk_ptr_head != NULL)
00264                         *chunk_ptr_head =
00265                             insert_in_vptr_list(*chunk_ptr_head, tmp_ptr);
00266                     return (tmp_ptr);
00267                 }
00268         }
00269 
00270 /* Find the smallest distance to advance the memory pointer and keep *
00271  * everything aligned.                                               */
00272 
00273     if(size % sizeof(Align) == 0)
00274         {
00275             aligned_size = size;
00276         }
00277     else
00278         {
00279             aligned_size = size + sizeof(Align) - size % sizeof(Align);
00280         }
00281 
00282     tmp_ptr = *next_mem_loc_ptr;
00283     *next_mem_loc_ptr += aligned_size;
00284     *mem_avail_ptr -= aligned_size;
00285     return (tmp_ptr);
00286 }
00287 
00288 /** Frees the memory allocated by a sequence of calls to my_chunk_malloc. */
00289 void
00290 free_chunk_memory(struct s_linked_vptr *chunk_ptr_head)
00291 {
00292     struct s_linked_vptr *curr_ptr, *prev_ptr;
00293 
00294     curr_ptr = chunk_ptr_head;
00295 
00296     while(curr_ptr != NULL)
00297         {
00298             free(curr_ptr->data_vptr);  /* Free memory "chunk". */
00299             prev_ptr = curr_ptr;
00300             curr_ptr = curr_ptr->next;
00301             free(prev_ptr);     /* Free memory used to track "chunk". */
00302         }
00303 }
00304 
00305 /** Inserts a new element at the head of a linked list of void pointers. 
00306  * Returns the new head of the list.                                    
00307  */
00308 struct s_linked_vptr *
00309 insert_in_vptr_list(struct s_linked_vptr *head, void *vptr_to_add)
00310 {
00311 
00312     struct s_linked_vptr *linked_vptr;
00313 
00314     linked_vptr = (struct s_linked_vptr *)my_malloc(sizeof(struct
00315                                                            s_linked_vptr));
00316 
00317     linked_vptr->data_vptr = vptr_to_add;
00318     linked_vptr->next = head;
00319     return (linked_vptr);       /* New head of the list */
00320 }
00321 
00322 /** Deletes the element at the head of a linked list of void pointers. 
00323  * Returns the new head of the list.                                    
00324  */
00325 struct s_linked_vptr *
00326 delete_in_vptr_list(struct s_linked_vptr *head)
00327 {
00328     struct s_linked_vptr *linked_vptr;
00329 
00330     if (head == NULL)
00331         return NULL;
00332     linked_vptr = head->next;
00333     free(head);
00334     return linked_vptr; /* New head of the list */
00335 }
00336 
00337 /** Inserts a new element at the head of a linked list of integers.  Returns  
00338  * the new head of the list.  One argument is the address of the head of     
00339  * a list of free ilist elements.  If there are any elements on this free    
00340  * list, the new element is taken from it.  Otherwise a new one is malloced. 
00341  */
00342 t_linked_int *
00343 insert_in_int_list(t_linked_int * head, int data,
00344         t_linked_int ** free_list_head_ptr)
00345 {
00346 
00347     t_linked_int *linked_int;
00348 
00349     if(*free_list_head_ptr != NULL)
00350         {
00351             linked_int = *free_list_head_ptr;
00352             *free_list_head_ptr = linked_int->next;
00353         }
00354     else
00355         {
00356             linked_int = (t_linked_int *) my_malloc(sizeof(t_linked_int));
00357         }
00358 
00359     linked_int->data = data;
00360     linked_int->next = head;
00361     return (linked_int);
00362 }
00363 
00364 /** This routine truly frees (calls free) all the integer list elements     
00365  * on the linked list pointed to by *head, and sets head = NULL.          
00366  */
00367 void
00368 free_int_list(t_linked_int ** int_list_head_ptr)
00369 {
00370 
00371     t_linked_int *linked_int, *next_linked_int;
00372 
00373     linked_int = *int_list_head_ptr;
00374 
00375     while(linked_int != NULL)
00376         {
00377             next_linked_int = linked_int->next;
00378             free(linked_int);
00379             linked_int = next_linked_int;
00380         }
00381 
00382     *int_list_head_ptr = NULL;
00383 }
00384 
00385 /** Allocates an integer vector with num_items elements and copies the       
00386  * integers from the list pointed to by list_head (of which there must be   
00387  * num_items) over to it.  The int_list is then put on the free list, and   
00388  * the list_head_ptr is set to NULL.                                        
00389  */
00390 void
00391 alloc_ivector_and_copy_int_list(t_linked_int ** list_head_ptr, int num_items,
00392         struct s_ivec *ivec, t_linked_int ** free_list_head_ptr)
00393 {
00394     t_linked_int *linked_int, *list_head;
00395     int i, *list;
00396 
00397     list_head = *list_head_ptr;
00398 
00399     if(num_items == 0)
00400         {                       /* Empty list. */
00401             ivec->nelem = 0;
00402             ivec->list = NULL;
00403 
00404             if(list_head != NULL)
00405                 {
00406                     printf(ERRTAG
00407                            "alloc_ivector_and_copy_int_list: Copied %d elements, "
00408                            "but list at %p contains more.\n", num_items,
00409                            (void *)list_head);
00410                     exit(1);
00411                 }
00412             return;
00413         }
00414 
00415     ivec->nelem = num_items;
00416     list = (int *)my_malloc(num_items * sizeof(int));
00417     ivec->list = list;
00418     linked_int = list_head;
00419 
00420     for(i = 0; i < num_items - 1; i++)
00421         {
00422             list[i] = linked_int->data;
00423             linked_int = linked_int->next;
00424         }
00425 
00426     list[num_items - 1] = linked_int->data;
00427 
00428     if(linked_int->next != NULL)
00429         {
00430             printf
00431                 ("Error in alloc_ivector_and_copy_int_list:\n Copied %d elements, "
00432                  "but list at %p contains more.\n", num_items,
00433                  (void *)list_head);
00434             exit(1);
00435         }
00436 
00437     linked_int->next = *free_list_head_ptr;
00438     *free_list_head_ptr = list_head;
00439     *list_head_ptr = NULL;
00440 }
00441 
00442 /** Get an input line, update the line number and cut off 
00443  * any comment part.  A \ at the end of a line with no   
00444  * comment part (#) means continue.                      
00445  */
00446 char *
00447 my_fgets(char *buf, int max_size, FILE * fp)
00448 {
00449     char *val;
00450     int i;
00451 
00452     cont = 0;
00453     val = fgets(buf, max_size, fp);
00454     linenum++;
00455     if(val == NULL)
00456         return (val);
00457 
00458 /* Check that line completely fit into buffer.  (Flags long line   *
00459  * truncation).                                                    */
00460 
00461     for(i = 0; i < max_size; i++)
00462         {
00463             if(buf[i] == '\n')
00464                 break;
00465             if(buf[i] == '\0')
00466                 {
00467                     printf
00468                         ("Error on line %d -- line is too long for input buffer.\n",
00469                          linenum);
00470                     printf("All lines must be at most %d characters long.\n",
00471                            BUFSIZE - 2);
00472                     printf
00473                         ("The problem could also be caused by a missing newline.\n");
00474                     exit(1);
00475                 }
00476         }
00477 
00478 
00479     for(i = 0; i < max_size && buf[i] != '\0'; i++)
00480         {
00481             if(buf[i] == '#')
00482                 {
00483                     buf[i] = '\0';
00484                     break;
00485                 }
00486         }
00487 
00488     if(i < 2)
00489         return (val);
00490     if(buf[i - 1] == '\n' && buf[i - 2] == '\\')
00491         {
00492             cont = 1;           /* line continued */
00493             buf[i - 2] = '\n';  /* May need this for tokens */
00494             buf[i - 1] = '\0';
00495         }
00496     return (val);
00497 }
00498 
00499 /** Get next token, and wrap to next line if \ at end of line.    
00500  * There is a bit of a "gotcha" in strtok.  It does not make a   
00501  * copy of the character array which you pass by pointer on the  
00502  * first call.  Thus, you must make sure this array exists for   
00503  * as long as you are using strtok to parse that line.  Don't    
00504  * use local buffers in a bunch of subroutines calling each      
00505  * other; the local buffer may be overwritten when the stack is  
00506  * restored after return from the subroutine.                    
00507  */
00508 char *
00509 my_strtok(char *ptr, char *tokens, FILE * fp, char *buf)
00510 {
00511 
00512     char *val;
00513 
00514     val = strtok(ptr, tokens);
00515     for(;;)
00516         {
00517             if(val != NULL || cont == 0)
00518                 return (val);
00519 
00520             /* return unless we have a null value and a continuation line */
00521             if(my_fgets(buf, BUFSIZE, fp) == NULL)
00522                 return (NULL);
00523 
00524             val = strtok(buf, tokens);
00525         }
00526 }
00527 
00528 /** Frees a 1D array of integer vectors.                              */
00529 void
00530 free_ivec_vector(struct s_ivec *ivec_vector, int nrmin, int nrmax)
00531 {
00532     int i;
00533 
00534     for(i = nrmin; i <= nrmax; i++)
00535         if(ivec_vector[i].nelem != 0)
00536             free(ivec_vector[i].list);
00537 
00538     free(ivec_vector + nrmin);
00539 }
00540 
00541 /** Frees a 2D matrix of integer vectors (ivecs).                     */
00542 void
00543 free_ivec_matrix(struct s_ivec **ivec_matrix, int nrmin, int nrmax, int ncmin,
00544         int ncmax)
00545 {
00546     int i, j;
00547 
00548     for(i = nrmin; i <= nrmax; i++)
00549         {
00550             for(j = ncmin; j <= ncmax; j++)
00551                 {
00552                     if(ivec_matrix[i][j].nelem != 0)
00553                         {
00554                             free(ivec_matrix[i][j].list);
00555                         }
00556                 }
00557         }
00558 
00559     free_matrix(ivec_matrix, nrmin, nrmax, ncmin, sizeof(struct s_ivec));
00560 }
00561 
00562 /** Frees a 3D matrix of integer vectors (ivecs).                     */
00563 void
00564 free_ivec_matrix3(struct s_ivec ***ivec_matrix3, int nrmin, int nrmax,
00565         int ncmin, int ncmax, int ndmin, int ndmax)
00566 {
00567     int i, j, k;
00568 
00569     for(i = nrmin; i <= nrmax; i++)
00570         {
00571             for(j = ncmin; j <= ncmax; j++)
00572                 {
00573                     for(k = ndmin; k <= ndmax; k++)
00574                         {
00575                             if(ivec_matrix3[i][j][k].nelem != 0)
00576                                 {
00577                                     free(ivec_matrix3[i][j][k].list);
00578                                 }
00579                         }
00580                 }
00581         }
00582 
00583     free_matrix3(ivec_matrix3, nrmin, nrmax, ncmin, ncmax, ndmin,
00584                  sizeof(struct s_ivec));
00585 }
00586 
00587 /** allocates an generic matrix with nrmax-nrmin + 1 rows and ncmax - 
00588  * ncmin + 1 columns, with each element of size elsize. i.e.         
00589  * returns a pointer to a storage block [nrmin..nrmax][ncmin..ncmax].
00590  * Simply cast the returned array pointer to the proper type.        
00591  */
00592 void **
00593 alloc_matrix(int nrmin, int nrmax, int ncmin, int ncmax, size_t elsize)
00594 {
00595 
00596     int i;
00597     char **cptr;
00598 
00599     cptr = (char **)my_malloc((nrmax - nrmin + 1) * sizeof(char *));
00600     cptr -= nrmin;
00601     for(i = nrmin; i <= nrmax; i++)
00602         {
00603             cptr[i] = (char *)my_malloc((ncmax - ncmin + 1) * elsize);
00604             cptr[i] -= ncmin * elsize / sizeof(char);   /* sizeof(char) = 1 */
00605         }
00606     return ((void **)cptr);
00607 }
00608 
00609 /* NB:  need to make the pointer type void * instead of void ** to allow   *
00610  * any pointer to be passed in without a cast.                             */
00611 
00612 void
00613 free_matrix(void *vptr, int nrmin, int nrmax, int ncmin, size_t elsize)
00614 {
00615     int i;
00616     char **cptr;
00617 
00618     cptr = (char **)vptr;
00619 
00620     for(i = nrmin; i <= nrmax; i++)
00621         free(cptr[i] + ncmin * elsize / sizeof(char));
00622     free(cptr + nrmin);
00623 }
00624 
00625 /** allocates a 3D generic matrix with nrmax-nrmin + 1 rows, ncmax -  
00626  * ncmin + 1 columns, and a depth of ndmax-ndmin + 1, with each      
00627  * element of size elsize. i.e. returns a pointer to a storage block 
00628  * [nrmin..nrmax][ncmin..ncmax][ndmin..ndmax].  Simply cast the      
00629  *  returned array pointer to the proper type.                      
00630  */
00631 void ***
00632 alloc_matrix3(int nrmin, int nrmax, int ncmin, int ncmax, int ndmin,
00633         int ndmax, size_t elsize)
00634 {
00635 
00636     int i, j;
00637     char ***cptr;
00638 
00639     cptr = (char ***)my_malloc((nrmax - nrmin + 1) * sizeof(char **));
00640     cptr -= nrmin;
00641     for(i = nrmin; i <= nrmax; i++)
00642         {
00643             cptr[i] =
00644                 (char **)my_malloc((ncmax - ncmin + 1) * sizeof(char *));
00645             cptr[i] -= ncmin;
00646             for(j = ncmin; j <= ncmax; j++)
00647                 {
00648                     cptr[i][j] =
00649                         (char *)my_malloc((ndmax - ndmin + 1) * elsize);
00650                     cptr[i][j] -= ndmin * elsize / sizeof(char);        /* sizeof(char) = 1) */
00651                 }
00652         }
00653     return ((void ***)cptr);
00654 }
00655 
00656 /** allocates a 3D generic matrix with nrmax-nrmin + 1 rows, ncmax -  
00657  * ncmin + 1 columns, and a depth of ndmax-ndmin + 1, with each      
00658  * element of size elsize. i.e. returns a pointer to a storage block 
00659  * [nrmin..nrmax][ncmin..ncmax][ndmin..ndmax].  Simply cast the      
00660  *  returned array pointer to the proper type.                       
00661  */
00662 void ****
00663 alloc_matrix4(int nrmin, int nrmax, int ncmin, int ncmax, int ndmin,
00664         int ndmax, int nemin, int nemax, size_t elsize)
00665 {
00666 
00667     int i, j, k;
00668     char ****cptr;
00669 
00670     cptr = (char ****)my_malloc((nrmax - nrmin + 1) * sizeof(char ***));
00671     cptr -= nrmin;
00672     for(i = nrmin; i <= nrmax; i++)
00673         {
00674             cptr[i] =
00675                 (char ***)my_malloc((ncmax - ncmin + 1) * sizeof(char **));
00676             cptr[i] -= ncmin;
00677             for(j = ncmin; j <= ncmax; j++)
00678                 {
00679                     cptr[i][j] =
00680                         (char **)my_malloc((ndmax - ndmin + 1) *
00681                                            sizeof(char *));
00682                     cptr[i][j] -= ndmin;
00683                     for(k = ndmin; k <= ndmax; k++)
00684                         {
00685                             cptr[i][j][k] =
00686                                 (char *)my_malloc((nemax - nemin + 1) *
00687                                                   elsize);
00688                             cptr[i][j][k] -= nemin * elsize / sizeof(char);     /* sizeof(char) = 1) */
00689                         }
00690                 }
00691         }
00692     return ((void ****)cptr);
00693 }
00694 
00695 void
00696 print_int_matrix3(int ***vptr, int nrmin, int nrmax, int ncmin, int ncmax,
00697         int ndmin, int ndmax, char *file)
00698 {
00699     FILE *outfile;
00700     int i, j, k;
00701 
00702     outfile = my_fopen(file, "w", 0);
00703 
00704     for(k = nrmin; k <= nrmax; ++k)
00705         {
00706             fprintf(outfile, "Plane %d\n", k);
00707             for(j = ncmin; j <= ncmax; ++j)
00708                 {
00709                     for(i = ndmin; i <= ndmax; ++i)
00710                         {
00711                             fprintf(outfile, "%d ", vptr[k][j][i]);
00712                         }
00713                     fprintf(outfile, "\n");
00714                 }
00715             fprintf(outfile, "\n");
00716         }
00717 
00718     fclose(outfile);
00719 }
00720 
00721 void
00722 free_matrix3(void *vptr, int nrmin, int nrmax, int ncmin, int ncmax,
00723         int ndmin, size_t elsize)
00724 {
00725     int i, j;
00726     char ***cptr;
00727 
00728     cptr = (char ***)vptr;
00729 
00730     for(i = nrmin; i <= nrmax; i++)
00731         {
00732             for(j = ncmin; j <= ncmax; j++)
00733                 free(cptr[i][j] + ndmin * elsize / sizeof(char));
00734             free(cptr[i] + ncmin);
00735         }
00736     free(cptr + nrmin);
00737 }
00738 
00739 void
00740 free_matrix4(void *vptr, int nrmin, int nrmax, int ncmin, int ncmax, int ndmin,
00741         int ndmax, int nemin, size_t elsize)
00742 {
00743     int i, j, k;
00744     char ****cptr;
00745 
00746     cptr = (char ****)vptr;
00747 
00748     for(i = nrmin; i <= nrmax; i++)
00749         {
00750             for(j = ncmin; j <= ncmax; j++)
00751                 {
00752                     for(k = ndmin; k <= ndmax; k++)
00753                                 free(cptr[i][j][k] + nemin * elsize / sizeof(char));
00754                     free(cptr[i][j] + ndmin * elsize / sizeof(char));
00755                 }
00756             free(cptr[i] + ncmin);
00757         }
00758     free(cptr + nrmin);
00759 }
00760 
00761 /* Portable random number generator defined below.  Taken from ANSI C by  *
00762  * K & R.  Not a great generator, but fast, and good enough for my needs. */
00763 
00764 #define IA 1103515245u
00765 #define IC 12345u
00766 #define IM 2147483648u
00767 #define CHECK_RAND
00768 
00769 static unsigned int current_random = 0;
00770 
00771 void
00772 my_srandom(int seed)
00773 {
00774     current_random = (unsigned int)seed;
00775 }
00776 
00777 /** Creates a random integer between 0 and imax, inclusive.  i.e. [0..imax] */
00778 int
00779 my_irand(int imax)
00780 {
00781     int ival;
00782 
00783 /* current_random = (current_random * IA + IC) % IM; */
00784     current_random = current_random * IA + IC;  /* Use overflow to wrap */
00785     ival = current_random & (IM - 1);   /* Modulus */
00786     ival = (int)((float)ival * (float)(imax + 0.999) / (float)IM);
00787 
00788 #ifdef CHECK_RAND
00789     if((ival < 0) || (ival > imax))
00790         {
00791                 if(ival == imax + 1) {
00792                         /* Due to random floating point rounding, sometimes above calculation gives number greater than ival by 1 */
00793                         ival = imax;
00794                 } else {
00795                         printf("Bad value in my_irand, imax = %d  ival = %d\n", imax,
00796                            ival);
00797                         exit(1);
00798                 }
00799         }
00800 #endif
00801 
00802     return (ival);
00803 }
00804 
00805 /** Creates a random float between 0 and 1.  i.e. [0..1).        */
00806 float
00807 my_frand(void)
00808 {
00809     float fval;
00810     int ival;
00811 
00812     current_random = current_random * IA + IC;  /* Use overflow to wrap */
00813     ival = current_random & (IM - 1);   /* Modulus */
00814     fval = (float)ival / (float)IM;
00815 
00816 #ifdef CHECK_RAND
00817     if((fval < 0) || (fval > 1.))
00818         {
00819             printf("Bad value in my_frand, fval = %g\n", fval);
00820             exit(1);
00821         }
00822 #endif
00823 
00824     return (fval);
00825 }
00826