1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
 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);
 }