/* source.c - source files, include paths and dependencies */ /* (c) in 2020 by Volker Barthelmann and Frank Wille */ #include "vasm.h" #include "osdep.h" #include "dwarf.h" #define SRCREADINC (64*1024) /* extend buffer in these steps when reading */ char *compile_dir; int ignore_multinc,depend,depend_all; static struct include_path *first_incpath; static struct source_file *first_source; static struct deplist *first_depend,*last_depend; void source_debug_init(int type,void *data) { if (type) { /* @@@ currently we only support DWARF source level debugging here */ dwarf_init((struct dwarf_info *)data,first_incpath,first_source); } } static void add_depend(char *name) { if (depend) { struct deplist *d = first_depend; /* check if an entry with the same file name already exists */ while (d != NULL) { if (!strcmp(d->filename,name)) return; d = d->next; } /* append new dependency record */ d = mymalloc(sizeof(struct deplist)); d->next = NULL; if (name[0]=='.'&&(name[1]=='/'||name[1]=='\\')) name += 2; /* skip "./" in paths */ d->filename = mystrdup(name); if (last_depend) last_depend = last_depend->next = d; else first_depend = last_depend = d; } } void write_depends(FILE *f) { struct deplist *d = first_depend; if (depend==DEPEND_MAKE && d!=NULL && outname!=NULL) fprintf(f,"%s:",outname); while (d != NULL) { switch (depend) { case DEPEND_LIST: fprintf(f,"%s\n",d->filename); break; case DEPEND_MAKE: if (str_is_graph(d->filename)) fprintf(f," %s",d->filename); else fprintf(f," \"%s\"",d->filename); break; default: ierror(0); } d = d->next; } if (depend == DEPEND_MAKE) fputc('\n',f); } static FILE *open_path(char *compdir,char *path,char *name,char *mode) { char pathbuf[MAXPATHLEN]; FILE *f; if (strlen(compdir) + strlen(path) + strlen(name) + 1 <= MAXPATHLEN) { strcpy(pathbuf,compdir); strcat(pathbuf,path); strcat(pathbuf,name); if (f = fopen(pathbuf,mode)) { if (depend_all || !abs_path(pathbuf)) add_depend(pathbuf); return f; } } return NULL; } static FILE *locate_file(char *filename,char *mode,struct include_path **ipath_used) { struct include_path *ipath; FILE *f; if (abs_path(filename)) { /* file name is absolute, then don't use any include paths */ if (f = fopen(filename,mode)) { if (depend_all) add_depend(filename); if (ipath_used) *ipath_used = NULL; /* no path used, file name was absolute */ return f; } } else { /* locate file name in all known include paths */ for (ipath=first_incpath; ipath; ipath=ipath->next) { if ((f = open_path(emptystr,ipath->path,filename,mode)) == NULL) { if (compile_dir && !abs_path(ipath->path) && (f = open_path(compile_dir,ipath->path,filename,mode))) ipath->compdir_based = 1; } if (f != NULL) { if (ipath_used) *ipath_used = ipath; return f; } } } general_error(12,filename); return NULL; } /* create a new source text instance, which has cur_src as parent */ source *new_source(char *srcname,struct source_file *srcfile, char *text,size_t size) { static unsigned long id = 0; source *s = mymalloc(sizeof(source)); size_t i; char *p; /* scan the source for strange characters */ for (p=text,i=0; iparent = cur_src; s->parent_line = cur_src ? cur_src->line : 0; s->srcfile = srcfile; /* NULL for macros and repetitions */ s->name = mystrdup(srcname); s->text = text; s->size = size; s->defsrc = NULL; s->defline = 0; s->srcdebug = cur_src ? cur_src->srcdebug : 1; /* source-level debugging */ s->macro = NULL; s->repeat = 1; /* read just once */ s->irpname = NULL; s->cond_level = clev; /* remember level of conditional nesting */ s->num_params = -1; /* not a macro, no parameters */ s->param[0] = emptystr; s->param_len[0] = 0; s->id = id++; /* every source has unique id - important for macros */ s->srcptr = text; s->line = 0; s->bufsize = INITLINELEN; s->linebuf = mymalloc(INITLINELEN); #ifdef CARGSYM s->cargexp = NULL; #endif #ifdef REPTNSYM /* -1 outside of a repetition block */ s->reptn = cur_src ? cur_src->reptn : -1; #endif return s; } /* quit parsing the current source instance, leave macros, repeat loops and restore the conditional assembly level */ void end_source(source *s) { if(s){ s->srcptr=s->text+s->size; s->repeat=1; clev=s->cond_level; } } source *include_source(char *inc_name) { static int srcfileidx; char *filename; struct source_file **nptr = &first_source; struct source_file *srcfile; source *newsrc = NULL; FILE *f; filename = convert_path(inc_name); /* check whether this source file name was already included */ while (srcfile = *nptr) { if (!filenamecmp(srcfile->name,filename)) { myfree(filename); nptr = NULL; /* reuse existing source in memory */ break; } nptr = &srcfile->next; } if (nptr != NULL) { /* allocate, locate and read a new source file */ struct include_path *ipath; if (f = locate_file(filename,"r",&ipath)) { char *text; size_t size; for (text=NULL,size=0; ; size+=SRCREADINC) { size_t nchar; text = myrealloc(text,size+SRCREADINC); nchar = fread(text+size,1,SRCREADINC,f); if (nchar < SRCREADINC) { size += nchar; break; } } if (feof(f)) { if (size > 0) { text = myrealloc(text,size+2); *(text+size) = '\n'; *(text+size+1) = '\0'; size++; } else { myfree(text); text = "\n"; size = 1; } srcfile = mymalloc(sizeof(struct source_file)); srcfile->next = NULL; srcfile->name = filename; srcfile->incpath = ipath; srcfile->text = text; srcfile->size = size; srcfile->index = ++srcfileidx; *nptr = srcfile; cur_src = newsrc = new_source(filename,srcfile,text,size); } else general_error(29,filename); fclose(f); } } else { /* same source was already loaded before, source_file node exists */ if (ignore_multinc) return NULL; /* ignore multiple inclusion of this source completely */ /* new source instance from existing source file */ cur_src = newsrc = new_source(srcfile->name,srcfile,srcfile->text, srcfile->size); } return newsrc; } void include_binary_file(char *inname,long nbskip,unsigned long nbkeep) /* locate a binary file and convert into a data atom */ { char *filename; FILE *f; filename = convert_path(inname); if (f = locate_file(filename,"rb",NULL)) { size_t size = filesize(f); if (size > 0) { if (nbskip>=0 && (size_t)nbskip<=size) { dblock *db = new_dblock(); if (nbkeep > (unsigned long)(size - (size_t)nbskip) || nbkeep==0) db->size = size - (size_t)nbskip; else db->size = nbkeep; db->data = mymalloc(size); if (nbskip > 0) fseek(f,nbskip,SEEK_SET); if (fread(db->data,1,db->size,f) != db->size) general_error(29,filename); /* read error */ add_atom(0,new_data_atom(db,1)); } else general_error(46); /* bad file-offset argument */ } fclose(f); } myfree(filename); } static struct include_path *new_ipath_node(char *pathname) { struct include_path *new = mymalloc(sizeof(struct include_path)); new->next = NULL; new->path = pathname; new->compdir_based = 0; return new; } static char *make_canonical_path(char *pathname) { char *newpath = convert_path(pathname); pathname = append_path_delimiter(newpath); /* append '/', when needed */ myfree(newpath); return pathname; } /* add the main source include path, which is searched first */ void main_include_path(char *pathname) { struct include_path *ipath; ipath = new_ipath_node(make_canonical_path(pathname)); ipath->next = first_incpath; first_incpath = ipath; } struct include_path *new_include_path(char *pathname) { struct include_path *ipath; /* check if path already exists, otherwise append new node */ pathname = make_canonical_path(pathname); for (ipath=first_incpath; ipath; ipath=ipath->next) { if (!filenamecmp(pathname,ipath->path)) { myfree(pathname); return ipath; } if (ipath->next == NULL) return ipath->next = new_ipath_node(pathname); } return first_incpath = new_ipath_node(pathname); }