/* * Copyright (C) 2003, 2004, 2005 Filip Pizlo. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY FILIP PIZLO ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FILIP PIZLO OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "gpc_internal.h" #include "tsf_format.h" #include #include #include #include #include #include #include #include #include /* code generation debugging */ /* NOTE: It is now the case that the count may be incremented multiple times, * in order to insure that files are not overwritten. This allows multiple * processes to use the same directory for code gen debugging. However, the * multi-increment appproach may be overkill, since I could have probably just * as well have used the PID. */ static volatile uint32_t count=0; static tsf_once_t once_control = TSF_ONCE_INIT; static tsf_mutex_t count_lock; static void count_init(void) { tsf_mutex_init(&count_lock); } static uint32_t next_count() { uint32_t result; tsf_once(&once_control, count_init); tsf_mutex_lock(&count_lock); result=count++; tsf_mutex_unlock(&count_lock); return result; } void gpc_dyncc_code_gen_debug(const char *type, const char *src_filename) { const char *tsf_code_gen_debug=getenv("TSF_CODE_GEN_DEBUG"); const char *tsf_code_gen_debug_path; char *dest_filename; int fd_src,fd_trg; uint32_t cur_cnt; if (tsf_code_gen_debug==NULL || strcasecmp(tsf_code_gen_debug,"YES")) { return; } tsf_code_gen_debug_path=getenv("TSF_CODE_GEN_DEBUG_PATH"); if (tsf_code_gen_debug_path==NULL) { return; } fd_src=open(src_filename,O_RDONLY); if (fd_src<0) { return; } /* loop until we hit a filename that isn't in use */ for (cur_cnt=count;;cur_cnt=next_count()) { dest_filename=tsf_asprintf("%s/" fui32 "_%s", tsf_code_gen_debug_path, cur_cnt, type); if (dest_filename==NULL) { close(fd_src); return; } fd_trg=open(dest_filename,O_CREAT|O_EXCL|O_WRONLY,0600); free(dest_filename); if (fd_trg>=0) { break; } if (errno!=EEXIST) { close(fd_src); return; } } for (;;) { char buf[1024]; int res=read(fd_src,buf,sizeof(buf)); if (res<=0) { break; } if (write(fd_trg,buf,res)!=res) { break; } } close(fd_src); close(fd_trg); } void gpc_code_gen_debug(const char *type, gpc_proto_t *proto) { const char *tsf_code_gen_debug=getenv("TSF_CODE_GEN_DEBUG"); const char *tsf_code_gen_debug_path; char *dest_filename; FILE *out; uint32_t cur_cnt; /* printf("dumping %s\n",type); */ if (tsf_code_gen_debug==NULL || strcasecmp(tsf_code_gen_debug,"YES")) { return; } tsf_code_gen_debug_path=getenv("TSF_CODE_GEN_DEBUG_PATH"); if (tsf_code_gen_debug_path==NULL) { return; } for (cur_cnt=count;;cur_cnt=next_count()) { int fd; dest_filename=tsf_asprintf("%s/" fui32 "_%s", tsf_code_gen_debug_path, cur_cnt, type); if (dest_filename==NULL) { return; } fd=open(dest_filename,O_CREAT|O_EXCL|O_WRONLY,0600); free(dest_filename); if (fd>=0) { out=fdopen(fd,"w"); if (out==NULL) { close(fd); return; } break; } if (errno!=EEXIST) { /* printf("error not eexist\n"); */ return; } } gpc_proto_print(proto,out); fclose(out); } /* stupid stuff */ void gpc_unlink_free(char *name) { unlink(name); free(name); } void gpc_rmdir_free(char *name) { rmdir(name); free(name); } /* this isn't a real rm -rf; it only goes down one level. */ void gpc_rmdashrf_free(char *name) { DIR *dir; dir=opendir(name); if (dir!=NULL) { for (;;) { struct dirent entry,*result=NULL; int res=readdir_r(dir,&entry,&result); if (res!=0 || result==NULL) { break; } if (strcmp(entry.d_name,".") && strcmp(entry.d_name,"..")) { char *flnm=tsf_asprintf("%s/%s",name,entry.d_name); if (flnm!=NULL) { unlink(flnm); free(flnm); } } } closedir(dir); rmdir(name); } free(name); }