ss_file_ref_t *
ss_file_references(ss_file_t *master, /* The file in question */
size_t *nfiles, /* INOUT: Upon return this argument will point to the number of valid entries
* in the return value. If FILEREF is non-null then the input value of this
* pointer specifies the maximum number of file reference entries to
* initialize in FILEREF and if there are more than that many that are found
* in the MASTER file then an error is raised. */
ss_file_ref_t *fileref, /* Optional pointer to an array of file reference information that will be
* initialized by this function and returned (if non-null) as the successful
* return value of this function. */
ss_prop_t UNUSED *props /* File properties (none defined yet) */
)
{
SS_ENTER(ss_file_references, ss_file_ref_tP);
ss_scope_t topscope;
ss_scope_t scope;
unsigned scope_idx, file_idx;
size_t nused=0, nalloc=0;
ss_gfile_t *gfile=NULL;
ss_file_ref_t *retval=fileref;
ss_file_t file;
char *pathname=NULL;
const char *filename=NULL;
SS_ASSERT(nfiles);
if (!ss_file_isopen(master, NULL)) SS_ERROR_FMT(PERM, ("file is not open"));
if (NULL==ss_file_topscope(master, &topscope)) SS_ERROR(FAILED);
if (NULL==(gfile=SS_GFILE_LINK(master))) SS_ERROR(FAILED);
/* The "pathname" is the directory part of the normalized, absolute master name. */
#ifdef WIN32
/*handle windows case where absolute path is like "c:\" or "d://"*/
SS_ASSERT((gfile->name[0]=='/' && gfile->name[1]) ||
(strlen(gfile->name)>=3 && gfile->name[1]==':' && (gfile->name[2]=='/' || gfile->name[2]=='\\')));
#else
SS_ASSERT(gfile->name[0]=='/' && gfile->name[1]);
#endif
if (NULL==(pathname=malloc(strlen(gfile->name)+1))) SS_ERROR(RESOURCE);
strcpy(pathname, gfile->name);
#ifdef WIN32
{
char *fwd_slash = strrchr(pathname, '/');
char *back_slash = strrchr(pathname, '\\');
SS_ASSERT(fwd_slash || back_slash);
if(fwd_slash && !back_slash) *fwd_slash='\0';
else if(!fwd_slash && back_slash) *back_slash='\0';
else if(fwd_slash > back_slash) *fwd_slash='\0';
else *back_slash='\0';
}
#else
SS_ASSERT(strrchr(pathname, '/'));
*(strrchr(pathname, '/')) = '\0';
#endif
/* For each scope in the file */
for (scope_idx=0; /*void*/; scope_idx++) {
if (NULL==ss_pers_refer_c(&topscope, SS_MAGIC(ss_scope_t), scope_idx, (ss_pers_t*)&scope)) SS_ERROR(FAILED);
if (NULL==SS_SCOPE(&scope)) break;
/* For each file in that scope except the first one (which is the MASTER) */
for (file_idx=1; /*void*/; file_idx++) {
if (NULL==ss_pers_refer_c(&scope, SS_MAGIC(ss_file_t), file_idx, (ss_pers_t*)&file)) SS_ERROR(FAILED);
if (NULL==SS_FILE(&file)) break;
/* Extend the return value array if necessary. */
if (!fileref) {
SS_EXTEND(retval, MAX(32,nused+1), nalloc);
} else if (nused>=*nfiles) {
SS_ERROR(OVERFLOW);
}
/* The name of the file is either absolute or relative to the master file. If relative then we need to make it
* relative to the current working directory. */
filename = ss_string_ptr(SS_FILE_P(&file,name));
if ('/'==filename[0]) {
if (NULL==(retval[nused].newname=malloc(strlen(filename)+1))) SS_ERROR(RESOURCE);
strcpy(retval[nused].newname, filename);
} else {
if (NULL==(retval[nused].newname=ss_file_fixname(ss_string_ptr(SS_FILE_P(&file,name)), pathname, ".", 0, NULL)))
SS_ERROR(RESOURCE);
}
/* Save other stuff */
retval[nused].file = file;
nused++;
}
}
SS_FREE(pathname);
*nfiles=nused;
if (0==nused && !retval && NULL==(retval=calloc(1, sizeof(*retval)))) SS_ERROR(RESOURCE);
SS_CLEANUP:
if (!fileref) SS_FREE(retval);
SS_LEAVE(retval);
}