VPR-6.0
|
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