/* A collection of C wrappers I use. Should be very obvious. The ones that are not obvious have comments before the function itself. Bugs: Please email me manodeep at gmail dot com Ver 1.0: Manodeep Sinha, 2nd April, 2012 Ver 1.1: Manodeep Sinha, 14th June, 2012 - replaced check_string_copy with a "real" wrapper to snprintf. Ver 1.2: Manodeep Sinha, Jan 8, 2012 - replaced print_time with timeval and gettimeofday */ #include #include #include//defines int64_t datatype -> *exactly* 8 bytes int #include//defines PRId64 for printing int64_t #include #include #include #include #include #include #include //function declarations -> you might want to package them into utils.h //routines for file i/o FILE * my_fopen(const char *fname,const char *mode); FILE * my_fopen_carefully(const char *fname,void (*header)(FILE *)); size_t my_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream); size_t my_fread(void *ptr, size_t size, size_t nmemb, FILE *stream); //general utilities int my_snprintf(char *buffer,int len,const char *format, ...) __attribute__((format(printf,3,4))); void print_time(struct timeval t0,struct timeval t1,const char *s); int64_t getnumlines(const char *fname,const char comment); short float_almost_equal(float A, float B, int maxUlps); //memory routines void* my_realloc(void *x,size_t size,int64_t N,const char *varname); void* my_malloc(size_t size,int64_t N); void* my_calloc(size_t size,int64_t N); void my_free(void ** x); //end function declarations FILE * my_fopen(const char *fname,const char *mode) { FILE *fp=NULL; fp = fopen(fname,mode); if(fp == NULL) { fprintf(stderr,"Could not open file `%s'\n",fname); exit(EXIT_FAILURE); } return fp; } /* The following function opens a file (if it already exists) in append mode. If the file doesn't exist, then the function creates one, calls the *header() function [which presumably prints a header to the file] and then returns the file pointer. As usual, you need to be careful with the file you are appending to -> otherwise you might end up with a ginormous file. Usually, I do a system("rm -f filename") before the loop where the file might be created/modified and remove the file from previous runs. */ FILE * my_fopen_carefully(const char *fname,void (*header)(FILE *)) { FILE *fp = NULL; fp = fopen(fname,"r");//note I am using fopen and not my_fopen. if(fp == NULL) { /*file does not exist -> open with "w" */ fp = my_fopen(fname,"w");//using my_fopen here. (*header)(fp);/* print the header */ } else { fclose(fp); fp = my_fopen(fname,"a+");//open with append mode } return fp; } size_t my_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream) { size_t nwritten; nwritten = fwrite(ptr, size, nmemb, stream); if(nwritten != nmemb) { fprintf(stderr,"I/O error (fwrite) has occured.\n"); fprintf(stderr,"Instead of reading nmemb=%zu, I got nread = %zu ..exiting\n",nmemb,nwritten); exit(EXIT_FAILURE); } return nwritten; } size_t my_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { size_t nread; nread = fread(ptr, size, nmemb, stream); if(nread != nmemb) { fprintf(stderr,"I/O error (fread) has occured.\n"); fprintf(stderr,"Instead of reading nmemb=%zu, I got nread = %zu ..exiting\n",nmemb,nread); exit(EXIT_FAILURE); } return nread; } // A real wrapper to snprintf that will exit() if the allocated buffer length // was not sufficient. Usage is the same as snprintf int my_snprintf(char *buffer,int len,const char *format, ...) { va_list args; int nwritten=0; va_start(args,format); nwritten=vsnprintf(buffer, len, format, args ); va_end(args); if (nwritten > len || nwritten < 0) { fprintf(stderr,"ERROR: printing to string failed (wrote %d characters while only %d characters were allocated)\n",nwritten,len); fprintf(stderr,"Increase maxlen in `defs.h' ..exiting\n"); exit(EXIT_FAILURE); } return nwritten; } /* I like this particular function. Generic replacement for printing (in meaningful units) the actual execution time of a code/code segment. The function call should be like this: --------------------------- struct timeval t_start,t_end; gettimeofday(&t_start,NULL); do_something(); gettimeofday(&t_end,NULL); print_time(t_start,t_end,"do something"); --------------------------- if the code took 220 mins 30.1 secs -> print_time will output `Time taken to execute `do something' = 3 hours 40 mins 30.1 seconds (code can be easily extended to include `weeks' as a system of time unit. left to the reader) */ void print_time(struct timeval t0,struct timeval t1,const char *s) { double timediff = difftime(t1.tv_sec,t0.tv_sec); double ratios[] = {24*3600.0, 3600.0, 60.0, 1}; char units[4][10] = {"days", "hrs" , "mins", "secs"}; int which = 0; double timeleft = timediff; double time_to_print; fprintf(stderr,"Time taken to execute '%s' = ",s); if(timediff < ratios[2]) fprintf(stderr,"%6.3lf secs",1e-6*(t1.tv_usec-t0.tv_usec) + timediff); else while (which < 4) { time_to_print = floor(timeleft/ratios[which]); if (time_to_print > 1) { timeleft -= (time_to_print*ratios[which]); fprintf(stderr,"%5d %s",(int)time_to_print,units[which]); } which++; } fprintf(stderr,"\n"); } //wrapper for realloc. varname should contain the name of the //variable being re-allocated -> helps debugging in case of a crash. void* my_realloc(void *x,size_t size,int64_t N,const char *varname) { void *tmp = realloc(x,N*size); size_t gigabytes = N*size/(1024.0*1024.0*1024.0); if (tmp==NULL) { fprintf(stderr,"ERROR: Could not reallocate for %"PRId64" elements with %zu size for variable `%s' ..aborting\n",N,size,varname); my_free((void **) &x); exit(EXIT_FAILURE); } else if(gigabytes > 1) fprintf(stderr,"\n Successfully re-allocated %"PRId64" elements with total size %zu (GB) for variable `%s' \n",N, gigabytes,varname); return tmp; } void* my_malloc(size_t size,int64_t N) { void *x = NULL; x = malloc(N*size); size_t megabytes = N*size/(1024.0*1024.0); if (x==NULL) { fprintf(stderr,"malloc for %"PRId64" elements with %zu bytes failed..aborting\n",N,size); exit(EXIT_FAILURE); } else if(megabytes > 100) fprintf(stderr,"\n Successfully allocated %"PRId64" elements with total size %zu (MB) \n",N, megabytes); return x; } void* my_calloc(size_t size,int64_t N) { void *x = NULL; x = calloc((size_t) N, size); if (x==NULL) { fprintf(stderr,"malloc for %"PRId64" elements with %zu size failed..aborting\n",N,size); exit(EXIT_FAILURE); } return x; } //real free. Use only if you are going to check the //pointer variable afterwards for NULL. void my_free(void ** x) { /* my_free(void *x) would also free the memory but then x would be a local variable and the pointer itself in the calling routine could not be set to NULL. Hence the pointer to pointer business. */ if(*x!=NULL) free(*x);//free the memory *x=NULL;//sets the pointer in the calling routine to NULL. } int64_t getnumlines(const char *fname,const char comment) { FILE *fp= NULL; const int MAXLINESIZE = 10000; int64_t nlines=0; char str_line[MAXLINESIZE]; fp = my_fopen(fname,"rt"); while(1) { if(fgets(str_line, MAXLINESIZE,fp)!=NULL) { //WARNING: this does not remove white-space. You might //want to implement that (was never an issue for me) if(str_line[0] !=comment) nlines++; } else break; } fclose(fp); return nlines; } /* The following function breaks the strict aliasing rules. Hence the added compile time option for no-strict-aliasing in the Makefile. */ short float_almost_equal(float A, float B, int maxUlps) { /* MS -- taken from http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm */ /* Make sure maxUlps is non-negative and small enough that the default NAN won't compare as equal to anything.*/ assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); int aInt = *(int*)&A; /* Make aInt lexicographically ordered as a twos-complement int*/ if (aInt < 0) aInt = 0x80000000 - aInt; /* Make bInt lexicographically ordered as a twos-complement int*/ int bInt = *(int*)&B; if (bInt < 0) bInt = 0x80000000 - bInt; int intDiff = abs(aInt - bInt); if (intDiff <= maxUlps) return 1; return 0; } /* //fake main. If you want to compile and test this file by itself */ /* int main(void) */ /* { */ /* return EXIT_SUCCESS; */ /* } */