📄 util.c
字号:
#include <string.h>#include <assert.h>#include <stdio.h>#include <stdlib.h>#include "util.h"#include "vpr_types.h"#include "globals.h"/* This file contains utility functions widely used in * * my programs. Many are simply versions of file and * * memory grabbing routines that take the same * * arguments as the standard library ones, but exit * * the program if they find an error condition. */int linenum; /* Line in file being parsed. *//* Returns the min of cur and max. If cur > max, a warning * is emitted. */intlimit_value(int cur, int max, const char *name){ if(cur > max) { printf(WARNTAG "%s is being limited from [%d] to [%d]\n", name, cur, max); return max; } return cur;}/* An alternate for strncpy since strncpy doesn't work as most * people would expect. This ensures null termination */char *my_strncpy(char *dest, const char *src, size_t size){ /* Find string's length */ size_t len = strlen(src); /* Cap length at (num - 1) to leave room for \0 */ if(size <= len) len = (size - 1); /* Copy as much of string as we can fit */ memcpy(dest, src, len); /* explicit null termination */ dest[len] = '\0'; return dest;}/* Uses global var 'OutFilePrefix' */FILE *my_fopen(const char *fname, const char *flag){ FILE *fp; int Len; char *new_fname = NULL; /* Appends a prefix string for output files */ if(OutFilePrefix) { if(strchr(flag, 'w')) { Len = 1; /* NULL char */ Len += strlen(OutFilePrefix); Len += strlen(fname); new_fname = (char *)my_malloc(Len * sizeof(char)); strcpy(new_fname, OutFilePrefix); strcat(new_fname, fname); fname = new_fname; } } if(NULL == (fp = fopen(fname, flag))) { printf("Error opening file %s for %s access.\n", fname, flag); exit(1); } if(new_fname) free(new_fname); return (fp);}char *my_strdup(const char *str){ int Len; char *Dst; Len = 1 + strlen(str); Dst = (char *)my_malloc(Len * sizeof(char)); memcpy(Dst, str, Len); return Dst;}intmy_atoi(const char *str){/* Returns the integer represented by the first part of the character * * string. */ if(str[0] < '0' || str[0] > '9') { if(!(str[0] == '-' && str[1] >= '0' && str[1] <= '9')) { printf(ERRTAG "expected number instead of '%s'.\n", str); exit(1); } } return (atoi(str));}void *my_calloc(size_t nelem, size_t size){ void *ret; if((ret = calloc(nelem, size)) == NULL) { fprintf(stderr, "Error: Unable to calloc memory. Aborting.\n"); exit(1); } return (ret);}void *my_malloc(size_t size){ void *ret; if((ret = malloc(size)) == NULL) { fprintf(stderr, "Error: Unable to malloc memory. Aborting.\n"); abort(); exit(1); } return (ret);}void *my_realloc(void *ptr, size_t size){ void *ret; if(size <= 0) { printf("reallocating of size <= 0.\n"); } ret = realloc(ptr, size); if(NULL == ret) { printf(ERRTAG "Unable to realloc memory. Aborting. " "ptr=%p, Size=%d.\n", ptr, size); if(ptr == NULL) { printf(ERRTAG "my_realloc: ptr == NULL. Aborting.\n"); } exit(1); } return (ret);}void *my_chunk_malloc(size_t size, struct s_linked_vptr **chunk_ptr_head, int *mem_avail_ptr, char **next_mem_loc_ptr){/* This routine should be used for allocating fairly small data * * structures where memory-efficiency is crucial. This routine allocates * * large "chunks" of data, and parcels them out as requested. Whenever * * it mallocs a new chunk it adds it to the linked list pointed to by * * chunk_ptr_head. This list can be used to free the chunked memory. * * If chunk_ptr_head is NULL, no list of chunked memory blocks will be kept * * -- this is useful for data structures that you never intend to free as * * it means you don't have to keep track of the linked lists. * * Information about the currently open "chunk" must be stored by the * * user program. mem_avail_ptr points to an int storing how many bytes are * * left in the current chunk, while next_mem_loc_ptr is the address of a * * pointer to the next free bytes in the chunk. To start a new chunk, * * simply set *mem_avail_ptr = 0. Each independent set of data structures * * should use a new chunk. *//* To make sure the memory passed back is properly aligned, I must * * only send back chunks in multiples of the worst-case alignment * * restriction of the machine. On most machines this should be * * a long, but on 64-bit machines it might be a long long or a * * double. Change the typedef below if this is the case. */ typedef long Align;#define CHUNK_SIZE 32768#define FRAGMENT_THRESHOLD 100 char *tmp_ptr; int aligned_size; assert(*mem_avail_ptr >= 0); if((size_t) (*mem_avail_ptr) < size) { /* Need to malloc more memory. */ if(size > CHUNK_SIZE) { /* Too big, use standard routine. */ tmp_ptr = my_malloc(size);/* When debugging, uncomment the code below to see if memory allocation size *//* makes sense *//*#ifdef DEBUG printf("NB: my_chunk_malloc got a request for %d bytes.\n", size); printf("You should consider using my_malloc for such big requests.\n");#endif */ if(chunk_ptr_head != NULL) *chunk_ptr_head = insert_in_vptr_list(*chunk_ptr_head, tmp_ptr); return (tmp_ptr); } if(*mem_avail_ptr < FRAGMENT_THRESHOLD) { /* Only a small scrap left. */ *next_mem_loc_ptr = my_malloc(CHUNK_SIZE); *mem_avail_ptr = CHUNK_SIZE; if(chunk_ptr_head != NULL) *chunk_ptr_head = insert_in_vptr_list(*chunk_ptr_head, *next_mem_loc_ptr); }/* Execute else clause only when the chunk we want is pretty big, * * and would leave too big an unused fragment. Then we use malloc * * to allocate normally. */ else { tmp_ptr = my_malloc(size); if(chunk_ptr_head != NULL) *chunk_ptr_head = insert_in_vptr_list(*chunk_ptr_head, tmp_ptr); return (tmp_ptr); } }/* Find the smallest distance to advance the memory pointer and keep * * everything aligned. */ if(size % sizeof(Align) == 0) { aligned_size = size; } else { aligned_size = size + sizeof(Align) - size % sizeof(Align); } tmp_ptr = *next_mem_loc_ptr; *next_mem_loc_ptr += aligned_size; *mem_avail_ptr -= aligned_size; return (tmp_ptr);}voidfree_chunk_memory(struct s_linked_vptr *chunk_ptr_head){/* Frees the memory allocated by a sequence of calls to my_chunk_malloc. */ struct s_linked_vptr *curr_ptr, *prev_ptr; curr_ptr = chunk_ptr_head; while(curr_ptr != NULL) { free(curr_ptr->data_vptr); /* Free memory "chunk". */ prev_ptr = curr_ptr; curr_ptr = curr_ptr->next; free(prev_ptr); /* Free memory used to track "chunk". */ }}struct s_linked_vptr *insert_in_vptr_list(struct s_linked_vptr *head, void *vptr_to_add){/* Inserts a new element at the head of a linked list of void pointers. * * Returns the new head of the list. */ struct s_linked_vptr *linked_vptr; linked_vptr = (struct s_linked_vptr *)my_malloc(sizeof(struct s_linked_vptr)); linked_vptr->data_vptr = vptr_to_add; linked_vptr->next = head; return (linked_vptr); /* New head of the list */}t_linked_int *insert_in_int_list(t_linked_int * head, int data, t_linked_int ** free_list_head_ptr){/* Inserts a new element at the head of a linked list of integers. Returns * * the new head of the list. One argument is the address of the head of * * a list of free ilist elements. If there are any elements on this free * * list, the new element is taken from it. Otherwise a new one is malloced. */ t_linked_int *linked_int; if(*free_list_head_ptr != NULL) { linked_int = *free_list_head_ptr; *free_list_head_ptr = linked_int->next; } else { linked_int = (t_linked_int *) my_malloc(sizeof(t_linked_int)); } linked_int->data = data; linked_int->next = head; return (linked_int);}voidfree_int_list(t_linked_int ** int_list_head_ptr){/* This routine truly frees (calls free) all the integer list elements * * on the linked list pointed to by *head, and sets head = NULL. */ t_linked_int *linked_int, *next_linked_int; linked_int = *int_list_head_ptr; while(linked_int != NULL) { next_linked_int = linked_int->next; free(linked_int); linked_int = next_linked_int; } *int_list_head_ptr = NULL;}voidalloc_ivector_and_copy_int_list(t_linked_int ** list_head_ptr, int num_items, struct s_ivec *ivec, t_linked_int ** free_list_head_ptr){/* Allocates an integer vector with num_items elements and copies the * * integers from the list pointed to by list_head (of which there must be * * num_items) over to it. The int_list is then put on the free list, and * * the list_head_ptr is set to NULL. */ t_linked_int *linked_int, *list_head; int i, *list; list_head = *list_head_ptr; if(num_items == 0) { /* Empty list. */ ivec->nelem = 0; ivec->list = NULL; if(list_head != NULL) { printf(ERRTAG "alloc_ivector_and_copy_int_list: Copied %d elements, " "but list at %p contains more.\n", num_items, (void *)list_head); exit(1); } return; } ivec->nelem = num_items; list = (int *)my_malloc(num_items * sizeof(int)); ivec->list = list; linked_int = list_head; for(i = 0; i < num_items - 1; i++) { list[i] = linked_int->data; linked_int = linked_int->next; } list[num_items - 1] = linked_int->data; if(linked_int->next != NULL) { printf ("Error in alloc_ivector_and_copy_int_list:\n Copied %d elements, " "but list at %p contains more.\n", num_items, (void *)list_head); exit(1); } linked_int->next = *free_list_head_ptr; *free_list_head_ptr = list_head; *list_head_ptr = NULL;}static int cont; /* line continued? */char *my_fgets(char *buf, int max_size, FILE * fp){ /* Get an input line, update the line number and cut off * * any comment part. A \ at the end of a line with no * * comment part (#) means continue. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -