kopia lustrzana https://github.com/hoglet67/RGBtoHDMI
362 wiersze
8.8 KiB
C
362 wiersze
8.8 KiB
C
/* 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; i<size; i++,p++) {
|
|
if (*p == 0x1a) {
|
|
/* EOF character - replace by newline and ignore rest of source */
|
|
*p = '\n';
|
|
size = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
s->parent = 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);
|
|
}
|