Fossil SCM
Allow reading the list of input resources from a file with --reslist option.
Commit
ba8ba160f94e35a45840da45daaf71fef0176ac5e12619be03c0ac9904a1d104
Parent
cddc7bb0e4fe905…
1 file changed
+208
-15
+208
-15
| --- src/mkbuiltin.c | ||
| +++ src/mkbuiltin.c | ||
| @@ -17,18 +17,26 @@ | ||
| 17 | 17 | ** |
| 18 | 18 | ** This is a stand-alone utility program that is part of the Fossil build |
| 19 | 19 | ** process. This program reads files named on the command line and converts |
| 20 | 20 | ** them into ANSI-C static char array variables. Output is written onto |
| 21 | 21 | ** standard output. |
| 22 | +** | |
| 23 | +** Additionally, the input files may be listed in a separate list file (one | |
| 24 | +** resource name per line, optionally enclosed in double quotes). Pass the list | |
| 25 | +** via '--reslist <the-list-file>' option. Both lists, from the command line and | |
| 26 | +** the list file, are merged; duplicate file names skipped from processing. | |
| 27 | +** This option is useful to get around the command line length limitations | |
| 28 | +** under some OS, like Windows. | |
| 22 | 29 | ** |
| 23 | 30 | ** The makefiles use this utility to package various resources (large scripts, |
| 24 | 31 | ** GIF images, etc) that are separate files in the source code as byte |
| 25 | 32 | ** arrays in the resulting executable. |
| 26 | 33 | */ |
| 27 | 34 | #include <stdio.h> |
| 28 | 35 | #include <stdlib.h> |
| 29 | 36 | #include <string.h> |
| 37 | +#include <ctype.h> | |
| 30 | 38 | |
| 31 | 39 | |
| 32 | 40 | /* |
| 33 | 41 | ** Read the entire content of the file named zFilename into memory obtained |
| 34 | 42 | ** from malloc() and return a pointer to that memory. Write the size of the |
| @@ -64,47 +72,231 @@ | ||
| 64 | 72 | struct Resource { |
| 65 | 73 | const char *zName; |
| 66 | 74 | int nByte; |
| 67 | 75 | int idx; |
| 68 | 76 | }; |
| 77 | + | |
| 78 | +typedef struct ResourceList ResourceList; | |
| 79 | +struct ResourceList { | |
| 80 | + Resource *aRes; | |
| 81 | + int nRes; | |
| 82 | + char *buf; | |
| 83 | + long bufsize; | |
| 84 | +}; | |
| 85 | + | |
| 86 | + | |
| 87 | +Resource *read_reslist(char *name, ResourceList *list){ | |
| 88 | +#define RESLIST_BUF_MAXBYTES (1L<<20) /* 1 MB of text */ | |
| 89 | + FILE *in; | |
| 90 | + long filesize = 0L; | |
| 91 | + long linecount = 0L; | |
| 92 | + char *p = 0; | |
| 93 | + char *pb = 0; | |
| 94 | + | |
| 95 | + memset(list, 0, sizeof(*list)); | |
| 96 | + | |
| 97 | + if( (in = fopen(name, "rb"))==0 ){ | |
| 98 | + return list->aRes; | |
| 99 | + } | |
| 100 | + fseek(in, 0L, SEEK_END); | |
| 101 | + filesize = ftell(in); | |
| 102 | + rewind(in); | |
| 103 | + | |
| 104 | + if( filesize > RESLIST_BUF_MAXBYTES ){ | |
| 105 | + fprintf(stderr, "List file [%s] must be smaller than %ld bytes\n", name, | |
| 106 | + RESLIST_BUF_MAXBYTES); | |
| 107 | + return list->aRes; | |
| 108 | + } | |
| 109 | + list->bufsize = filesize; | |
| 110 | + list->buf = (char *)calloc((list->bufsize + 2), sizeof(list->buf[0])); | |
| 111 | + if( list->buf==0 ){ | |
| 112 | + fprintf(stderr, "failed to allocated %ld bytes\n", list->bufsize + 1); | |
| 113 | + list->bufsize = 0L; | |
| 114 | + return list->aRes; | |
| 115 | + } | |
| 116 | + filesize = fread(list->buf, sizeof(list->buf[0]),list->bufsize, in); | |
| 117 | + if ( filesize!=list->bufsize ){ | |
| 118 | + fprintf(stderr, "failed to read [%s]\n", name); | |
| 119 | + return list->aRes; | |
| 120 | + } | |
| 121 | + fclose(in); | |
| 122 | + | |
| 123 | + /* | |
| 124 | + ** append an extra newline (if missing) for a correct line count | |
| 125 | + */ | |
| 126 | + if( list->buf[list->bufsize-1]!='\n' ) list->buf[list->bufsize]='\n'; | |
| 127 | + | |
| 128 | + linecount = 0L; | |
| 129 | + for( p = strchr(list->buf, '\n'); | |
| 130 | + p && p <= &list->buf[list->bufsize-1]; | |
| 131 | + p = strchr(++p, '\n') ){ | |
| 132 | + ++linecount; | |
| 133 | + } | |
| 134 | + | |
| 135 | + list->aRes = (Resource *)calloc(linecount+1, sizeof(list->aRes[0])); | |
| 136 | + for( pb = list->buf, p = strchr(pb, '\n'); | |
| 137 | + p && p <= &list->buf[list->bufsize-1]; | |
| 138 | + pb = ++p, p = strchr(pb, '\n') ){ | |
| 139 | + | |
| 140 | + char *path = pb; | |
| 141 | + char *pe = p - 1; | |
| 142 | + | |
| 143 | + /* strip leading and trailing whitespace */ | |
| 144 | + while( path < p && isspace(*path) ) ++path; | |
| 145 | + while( pe > path && isspace(*pe) ){ | |
| 146 | + *pe = '\0'; | |
| 147 | + --pe; | |
| 148 | + } | |
| 149 | + | |
| 150 | + /* strip outer quotes */ | |
| 151 | + while( path < p && *path=='\"') ++path; | |
| 152 | + while( pe > path && *pe=='\"' ){ | |
| 153 | + *pe = '\0'; | |
| 154 | + --pe; | |
| 155 | + } | |
| 156 | + *p = '\0'; | |
| 157 | + | |
| 158 | + /* skip empty path */ | |
| 159 | + if( *path ){ | |
| 160 | + list->aRes[list->nRes].zName = path; | |
| 161 | + ++(list->nRes); | |
| 162 | + } | |
| 163 | + } | |
| 164 | + return list->aRes; | |
| 165 | +} | |
| 166 | + | |
| 167 | +void free_reslist(ResourceList *list){ | |
| 168 | + if( list ){ | |
| 169 | + if( list->buf ) free(list->buf); | |
| 170 | + if( list->aRes) free(list->aRes); | |
| 171 | + memset(list, 0, sizeof(*list)); | |
| 172 | + } | |
| 173 | +} | |
| 69 | 174 | |
| 70 | 175 | /* |
| 71 | 176 | ** Compare two Resource objects for sorting purposes. They sort |
| 72 | 177 | ** in zName order so that Fossil can search for resources using |
| 73 | 178 | ** a binary search. |
| 74 | 179 | */ |
| 75 | -static int compareResource(const void *a, const void *b){ | |
| 76 | - Resource *pA = (Resource*)a; | |
| 77 | - Resource *pB = (Resource*)b; | |
| 78 | - return strcmp(pA->zName, pB->zName); | |
| 180 | +typedef int (*QsortCompareFunc)(const void *, const void*); | |
| 181 | + | |
| 182 | +static int compareResource(const Resource *a, const Resource *b){ | |
| 183 | + return strcmp(a->zName, b->zName); | |
| 184 | +} | |
| 185 | + | |
| 186 | +int remove_duplicates(ResourceList *list){ | |
| 187 | + char dupNameAsc[64] = "\255"; | |
| 188 | + char dupNameDesc[64] = ""; | |
| 189 | + Resource dupResAsc; | |
| 190 | + Resource dupResDesc; | |
| 191 | + Resource *pDupRes; | |
| 192 | + int dupcount = 0; | |
| 193 | + int i; | |
| 194 | + | |
| 195 | + if( list->nRes==0 ){ | |
| 196 | + return list->nRes; | |
| 197 | + } | |
| 198 | + | |
| 199 | + /* | |
| 200 | + ** scan for duplicates and assign their names to a string that would sort to | |
| 201 | + ** the bottom, then re-sort and truncate the duplicates | |
| 202 | + */ | |
| 203 | + memset(dupNameAsc, dupNameAsc[0], sizeof(dupNameAsc)-2); | |
| 204 | + memset(dupNameDesc, dupNameDesc[0], sizeof(dupNameDesc)-2); | |
| 205 | + memset(&dupResAsc, 0, sizeof(dupResAsc)); | |
| 206 | + dupResAsc.zName = dupNameAsc; | |
| 207 | + memset(&dupResDesc, 0, sizeof(dupResDesc)); | |
| 208 | + dupResDesc.zName = dupNameDesc; | |
| 209 | + pDupRes = (compareResource(&dupResAsc, &dupResDesc) > 0 | |
| 210 | + ? &dupResAsc : &dupResDesc); | |
| 211 | + | |
| 212 | + qsort(list->aRes, list->nRes, sizeof(list->aRes[0]), | |
| 213 | + (QsortCompareFunc)compareResource); | |
| 214 | + for( i=0; i<list->nRes-1 ; ++i){ | |
| 215 | + Resource *res = &list->aRes[i]; | |
| 216 | + | |
| 217 | + while( i<list->nRes-1 | |
| 218 | + && compareResource(res, &list->aRes[i+1])==0 ){ | |
| 219 | + fprintf(stderr, "Skipped a duplicate file [%s]\n", list->aRes[i+1].zName); | |
| 220 | + memcpy(&list->aRes[i+1], pDupRes, sizeof(list->aRes[0])); | |
| 221 | + ++dupcount; | |
| 222 | + | |
| 223 | + ++i; | |
| 224 | + } | |
| 225 | + } | |
| 226 | + if( dupcount == 0){ | |
| 227 | + return list->nRes; | |
| 228 | + } | |
| 229 | + qsort(list->aRes, list->nRes, sizeof(list->aRes[0]), | |
| 230 | + (QsortCompareFunc)compareResource); | |
| 231 | + list->nRes -= dupcount; | |
| 232 | + memset(&list->aRes[list->nRes], 0, sizeof(list->aRes[0])); | |
| 233 | + | |
| 234 | + return list->nRes; | |
| 79 | 235 | } |
| 80 | 236 | |
| 81 | 237 | int main(int argc, char **argv){ |
| 82 | 238 | int i, sz; |
| 83 | 239 | int j, n; |
| 240 | + ResourceList resList; | |
| 84 | 241 | Resource *aRes; |
| 85 | 242 | int nRes; |
| 86 | 243 | unsigned char *pData; |
| 87 | 244 | int nErr = 0; |
| 88 | 245 | int nSkip; |
| 89 | 246 | int nPrefix = 0; |
| 90 | 247 | |
| 248 | + if( argc==1 ){ | |
| 249 | + fprintf(stderr, "usage\t:%s " | |
| 250 | + "[--prefix path] [--reslist file] [resource-file1 ...]\n", | |
| 251 | + argv[0] | |
| 252 | + ); | |
| 253 | + return 1; | |
| 254 | + } | |
| 91 | 255 | if( argc>3 && strcmp(argv[1],"--prefix")==0 ){ |
| 92 | 256 | nPrefix = (int)strlen(argv[2]); |
| 93 | 257 | argc -= 2; |
| 94 | 258 | argv += 2; |
| 95 | 259 | } |
| 96 | - nRes = argc - 1; | |
| 97 | - aRes = malloc( nRes*sizeof(aRes[0]) ); | |
| 98 | - if( aRes==0 ){ | |
| 99 | - fprintf(stderr, "malloc failed\n"); | |
| 100 | - return 1; | |
| 101 | - } | |
| 102 | - for(i=0; i<argc-1; i++){ | |
| 103 | - aRes[i].zName = argv[i+1]; | |
| 104 | - } | |
| 105 | - qsort(aRes, nRes, sizeof(aRes[0]), compareResource); | |
| 260 | + | |
| 261 | + memset(&resList, 0, sizeof(resList)); | |
| 262 | + if( argc>2 && strcmp(argv[1],"--reslist")==0 ){ | |
| 263 | + if( read_reslist(argv[2], &resList)==0 ){ | |
| 264 | + fprintf(stderr, "Failed to load resource list from [%s]", argv[2]); | |
| 265 | + free_reslist(&resList); | |
| 266 | + return 1; | |
| 267 | + } | |
| 268 | + argc -= 2; | |
| 269 | + argv += 2; | |
| 270 | + } | |
| 271 | + | |
| 272 | + if( argc>1 ){ | |
| 273 | + aRes = realloc(resList.aRes, (resList.nRes+argc-1)*sizeof(resList.aRes[0])); | |
| 274 | + if( aRes==0 || aRes==resList.aRes ){ | |
| 275 | + fprintf(stderr, "realloc failed\n"); | |
| 276 | + free_reslist(&resList); | |
| 277 | + return 1; | |
| 278 | + } | |
| 279 | + resList.aRes = aRes; | |
| 280 | + | |
| 281 | + for(i=0; i<argc-1; i++){ | |
| 282 | + resList.aRes[resList.nRes].zName = argv[i+1]; | |
| 283 | + ++resList.nRes; | |
| 284 | + } | |
| 285 | + } | |
| 286 | + | |
| 287 | + if( resList.nRes==0 ){ | |
| 288 | + fprintf(stderr,"No resource files to process\n"); | |
| 289 | + free_reslist(&resList); | |
| 290 | + return 1; | |
| 291 | + } | |
| 292 | + remove_duplicates(&resList); | |
| 293 | + | |
| 294 | + nRes = resList.nRes; | |
| 295 | + aRes = resList.aRes; | |
| 296 | + qsort(aRes, nRes, sizeof(aRes[0]), (QsortCompareFunc)compareResource); | |
| 297 | + | |
| 106 | 298 | printf("/* Automatically generated code: Do not edit.\n**\n" |
| 107 | 299 | "** Rerun the \"mkbuiltin.c\" program or rerun the Fossil\n" |
| 108 | 300 | "** makefile to update this source file.\n" |
| 109 | 301 | "*/\n"); |
| 110 | 302 | for(i=0; i<nRes; i++){ |
| @@ -152,13 +344,14 @@ | ||
| 152 | 344 | const char *z = aRes[i].zName; |
| 153 | 345 | if( strlen(z)>=nPrefix ) z += nPrefix; |
| 154 | 346 | while( z[0]=='.' || z[0]=='/' ){ z++; } |
| 155 | 347 | aRes[i].zName = z; |
| 156 | 348 | } |
| 157 | - qsort(aRes, nRes, sizeof(aRes[0]), compareResource); | |
| 349 | + qsort(aRes, nRes, sizeof(aRes[0]), (QsortCompareFunc)compareResource); | |
| 158 | 350 | for(i=0; i<nRes; i++){ |
| 159 | 351 | printf(" { \"%s\", bidata%d, %d },\n", |
| 160 | 352 | aRes[i].zName, aRes[i].idx, aRes[i].nByte); |
| 161 | 353 | } |
| 162 | 354 | printf("};\n"); |
| 355 | + free_reslist(&resList); | |
| 163 | 356 | return nErr; |
| 164 | 357 | } |
| 165 | 358 |
| --- src/mkbuiltin.c | |
| +++ src/mkbuiltin.c | |
| @@ -17,18 +17,26 @@ | |
| 17 | ** |
| 18 | ** This is a stand-alone utility program that is part of the Fossil build |
| 19 | ** process. This program reads files named on the command line and converts |
| 20 | ** them into ANSI-C static char array variables. Output is written onto |
| 21 | ** standard output. |
| 22 | ** |
| 23 | ** The makefiles use this utility to package various resources (large scripts, |
| 24 | ** GIF images, etc) that are separate files in the source code as byte |
| 25 | ** arrays in the resulting executable. |
| 26 | */ |
| 27 | #include <stdio.h> |
| 28 | #include <stdlib.h> |
| 29 | #include <string.h> |
| 30 | |
| 31 | |
| 32 | /* |
| 33 | ** Read the entire content of the file named zFilename into memory obtained |
| 34 | ** from malloc() and return a pointer to that memory. Write the size of the |
| @@ -64,47 +72,231 @@ | |
| 64 | struct Resource { |
| 65 | const char *zName; |
| 66 | int nByte; |
| 67 | int idx; |
| 68 | }; |
| 69 | |
| 70 | /* |
| 71 | ** Compare two Resource objects for sorting purposes. They sort |
| 72 | ** in zName order so that Fossil can search for resources using |
| 73 | ** a binary search. |
| 74 | */ |
| 75 | static int compareResource(const void *a, const void *b){ |
| 76 | Resource *pA = (Resource*)a; |
| 77 | Resource *pB = (Resource*)b; |
| 78 | return strcmp(pA->zName, pB->zName); |
| 79 | } |
| 80 | |
| 81 | int main(int argc, char **argv){ |
| 82 | int i, sz; |
| 83 | int j, n; |
| 84 | Resource *aRes; |
| 85 | int nRes; |
| 86 | unsigned char *pData; |
| 87 | int nErr = 0; |
| 88 | int nSkip; |
| 89 | int nPrefix = 0; |
| 90 | |
| 91 | if( argc>3 && strcmp(argv[1],"--prefix")==0 ){ |
| 92 | nPrefix = (int)strlen(argv[2]); |
| 93 | argc -= 2; |
| 94 | argv += 2; |
| 95 | } |
| 96 | nRes = argc - 1; |
| 97 | aRes = malloc( nRes*sizeof(aRes[0]) ); |
| 98 | if( aRes==0 ){ |
| 99 | fprintf(stderr, "malloc failed\n"); |
| 100 | return 1; |
| 101 | } |
| 102 | for(i=0; i<argc-1; i++){ |
| 103 | aRes[i].zName = argv[i+1]; |
| 104 | } |
| 105 | qsort(aRes, nRes, sizeof(aRes[0]), compareResource); |
| 106 | printf("/* Automatically generated code: Do not edit.\n**\n" |
| 107 | "** Rerun the \"mkbuiltin.c\" program or rerun the Fossil\n" |
| 108 | "** makefile to update this source file.\n" |
| 109 | "*/\n"); |
| 110 | for(i=0; i<nRes; i++){ |
| @@ -152,13 +344,14 @@ | |
| 152 | const char *z = aRes[i].zName; |
| 153 | if( strlen(z)>=nPrefix ) z += nPrefix; |
| 154 | while( z[0]=='.' || z[0]=='/' ){ z++; } |
| 155 | aRes[i].zName = z; |
| 156 | } |
| 157 | qsort(aRes, nRes, sizeof(aRes[0]), compareResource); |
| 158 | for(i=0; i<nRes; i++){ |
| 159 | printf(" { \"%s\", bidata%d, %d },\n", |
| 160 | aRes[i].zName, aRes[i].idx, aRes[i].nByte); |
| 161 | } |
| 162 | printf("};\n"); |
| 163 | return nErr; |
| 164 | } |
| 165 |
| --- src/mkbuiltin.c | |
| +++ src/mkbuiltin.c | |
| @@ -17,18 +17,26 @@ | |
| 17 | ** |
| 18 | ** This is a stand-alone utility program that is part of the Fossil build |
| 19 | ** process. This program reads files named on the command line and converts |
| 20 | ** them into ANSI-C static char array variables. Output is written onto |
| 21 | ** standard output. |
| 22 | ** |
| 23 | ** Additionally, the input files may be listed in a separate list file (one |
| 24 | ** resource name per line, optionally enclosed in double quotes). Pass the list |
| 25 | ** via '--reslist <the-list-file>' option. Both lists, from the command line and |
| 26 | ** the list file, are merged; duplicate file names skipped from processing. |
| 27 | ** This option is useful to get around the command line length limitations |
| 28 | ** under some OS, like Windows. |
| 29 | ** |
| 30 | ** The makefiles use this utility to package various resources (large scripts, |
| 31 | ** GIF images, etc) that are separate files in the source code as byte |
| 32 | ** arrays in the resulting executable. |
| 33 | */ |
| 34 | #include <stdio.h> |
| 35 | #include <stdlib.h> |
| 36 | #include <string.h> |
| 37 | #include <ctype.h> |
| 38 | |
| 39 | |
| 40 | /* |
| 41 | ** Read the entire content of the file named zFilename into memory obtained |
| 42 | ** from malloc() and return a pointer to that memory. Write the size of the |
| @@ -64,47 +72,231 @@ | |
| 72 | struct Resource { |
| 73 | const char *zName; |
| 74 | int nByte; |
| 75 | int idx; |
| 76 | }; |
| 77 | |
| 78 | typedef struct ResourceList ResourceList; |
| 79 | struct ResourceList { |
| 80 | Resource *aRes; |
| 81 | int nRes; |
| 82 | char *buf; |
| 83 | long bufsize; |
| 84 | }; |
| 85 | |
| 86 | |
| 87 | Resource *read_reslist(char *name, ResourceList *list){ |
| 88 | #define RESLIST_BUF_MAXBYTES (1L<<20) /* 1 MB of text */ |
| 89 | FILE *in; |
| 90 | long filesize = 0L; |
| 91 | long linecount = 0L; |
| 92 | char *p = 0; |
| 93 | char *pb = 0; |
| 94 | |
| 95 | memset(list, 0, sizeof(*list)); |
| 96 | |
| 97 | if( (in = fopen(name, "rb"))==0 ){ |
| 98 | return list->aRes; |
| 99 | } |
| 100 | fseek(in, 0L, SEEK_END); |
| 101 | filesize = ftell(in); |
| 102 | rewind(in); |
| 103 | |
| 104 | if( filesize > RESLIST_BUF_MAXBYTES ){ |
| 105 | fprintf(stderr, "List file [%s] must be smaller than %ld bytes\n", name, |
| 106 | RESLIST_BUF_MAXBYTES); |
| 107 | return list->aRes; |
| 108 | } |
| 109 | list->bufsize = filesize; |
| 110 | list->buf = (char *)calloc((list->bufsize + 2), sizeof(list->buf[0])); |
| 111 | if( list->buf==0 ){ |
| 112 | fprintf(stderr, "failed to allocated %ld bytes\n", list->bufsize + 1); |
| 113 | list->bufsize = 0L; |
| 114 | return list->aRes; |
| 115 | } |
| 116 | filesize = fread(list->buf, sizeof(list->buf[0]),list->bufsize, in); |
| 117 | if ( filesize!=list->bufsize ){ |
| 118 | fprintf(stderr, "failed to read [%s]\n", name); |
| 119 | return list->aRes; |
| 120 | } |
| 121 | fclose(in); |
| 122 | |
| 123 | /* |
| 124 | ** append an extra newline (if missing) for a correct line count |
| 125 | */ |
| 126 | if( list->buf[list->bufsize-1]!='\n' ) list->buf[list->bufsize]='\n'; |
| 127 | |
| 128 | linecount = 0L; |
| 129 | for( p = strchr(list->buf, '\n'); |
| 130 | p && p <= &list->buf[list->bufsize-1]; |
| 131 | p = strchr(++p, '\n') ){ |
| 132 | ++linecount; |
| 133 | } |
| 134 | |
| 135 | list->aRes = (Resource *)calloc(linecount+1, sizeof(list->aRes[0])); |
| 136 | for( pb = list->buf, p = strchr(pb, '\n'); |
| 137 | p && p <= &list->buf[list->bufsize-1]; |
| 138 | pb = ++p, p = strchr(pb, '\n') ){ |
| 139 | |
| 140 | char *path = pb; |
| 141 | char *pe = p - 1; |
| 142 | |
| 143 | /* strip leading and trailing whitespace */ |
| 144 | while( path < p && isspace(*path) ) ++path; |
| 145 | while( pe > path && isspace(*pe) ){ |
| 146 | *pe = '\0'; |
| 147 | --pe; |
| 148 | } |
| 149 | |
| 150 | /* strip outer quotes */ |
| 151 | while( path < p && *path=='\"') ++path; |
| 152 | while( pe > path && *pe=='\"' ){ |
| 153 | *pe = '\0'; |
| 154 | --pe; |
| 155 | } |
| 156 | *p = '\0'; |
| 157 | |
| 158 | /* skip empty path */ |
| 159 | if( *path ){ |
| 160 | list->aRes[list->nRes].zName = path; |
| 161 | ++(list->nRes); |
| 162 | } |
| 163 | } |
| 164 | return list->aRes; |
| 165 | } |
| 166 | |
| 167 | void free_reslist(ResourceList *list){ |
| 168 | if( list ){ |
| 169 | if( list->buf ) free(list->buf); |
| 170 | if( list->aRes) free(list->aRes); |
| 171 | memset(list, 0, sizeof(*list)); |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | /* |
| 176 | ** Compare two Resource objects for sorting purposes. They sort |
| 177 | ** in zName order so that Fossil can search for resources using |
| 178 | ** a binary search. |
| 179 | */ |
| 180 | typedef int (*QsortCompareFunc)(const void *, const void*); |
| 181 | |
| 182 | static int compareResource(const Resource *a, const Resource *b){ |
| 183 | return strcmp(a->zName, b->zName); |
| 184 | } |
| 185 | |
| 186 | int remove_duplicates(ResourceList *list){ |
| 187 | char dupNameAsc[64] = "\255"; |
| 188 | char dupNameDesc[64] = ""; |
| 189 | Resource dupResAsc; |
| 190 | Resource dupResDesc; |
| 191 | Resource *pDupRes; |
| 192 | int dupcount = 0; |
| 193 | int i; |
| 194 | |
| 195 | if( list->nRes==0 ){ |
| 196 | return list->nRes; |
| 197 | } |
| 198 | |
| 199 | /* |
| 200 | ** scan for duplicates and assign their names to a string that would sort to |
| 201 | ** the bottom, then re-sort and truncate the duplicates |
| 202 | */ |
| 203 | memset(dupNameAsc, dupNameAsc[0], sizeof(dupNameAsc)-2); |
| 204 | memset(dupNameDesc, dupNameDesc[0], sizeof(dupNameDesc)-2); |
| 205 | memset(&dupResAsc, 0, sizeof(dupResAsc)); |
| 206 | dupResAsc.zName = dupNameAsc; |
| 207 | memset(&dupResDesc, 0, sizeof(dupResDesc)); |
| 208 | dupResDesc.zName = dupNameDesc; |
| 209 | pDupRes = (compareResource(&dupResAsc, &dupResDesc) > 0 |
| 210 | ? &dupResAsc : &dupResDesc); |
| 211 | |
| 212 | qsort(list->aRes, list->nRes, sizeof(list->aRes[0]), |
| 213 | (QsortCompareFunc)compareResource); |
| 214 | for( i=0; i<list->nRes-1 ; ++i){ |
| 215 | Resource *res = &list->aRes[i]; |
| 216 | |
| 217 | while( i<list->nRes-1 |
| 218 | && compareResource(res, &list->aRes[i+1])==0 ){ |
| 219 | fprintf(stderr, "Skipped a duplicate file [%s]\n", list->aRes[i+1].zName); |
| 220 | memcpy(&list->aRes[i+1], pDupRes, sizeof(list->aRes[0])); |
| 221 | ++dupcount; |
| 222 | |
| 223 | ++i; |
| 224 | } |
| 225 | } |
| 226 | if( dupcount == 0){ |
| 227 | return list->nRes; |
| 228 | } |
| 229 | qsort(list->aRes, list->nRes, sizeof(list->aRes[0]), |
| 230 | (QsortCompareFunc)compareResource); |
| 231 | list->nRes -= dupcount; |
| 232 | memset(&list->aRes[list->nRes], 0, sizeof(list->aRes[0])); |
| 233 | |
| 234 | return list->nRes; |
| 235 | } |
| 236 | |
| 237 | int main(int argc, char **argv){ |
| 238 | int i, sz; |
| 239 | int j, n; |
| 240 | ResourceList resList; |
| 241 | Resource *aRes; |
| 242 | int nRes; |
| 243 | unsigned char *pData; |
| 244 | int nErr = 0; |
| 245 | int nSkip; |
| 246 | int nPrefix = 0; |
| 247 | |
| 248 | if( argc==1 ){ |
| 249 | fprintf(stderr, "usage\t:%s " |
| 250 | "[--prefix path] [--reslist file] [resource-file1 ...]\n", |
| 251 | argv[0] |
| 252 | ); |
| 253 | return 1; |
| 254 | } |
| 255 | if( argc>3 && strcmp(argv[1],"--prefix")==0 ){ |
| 256 | nPrefix = (int)strlen(argv[2]); |
| 257 | argc -= 2; |
| 258 | argv += 2; |
| 259 | } |
| 260 | |
| 261 | memset(&resList, 0, sizeof(resList)); |
| 262 | if( argc>2 && strcmp(argv[1],"--reslist")==0 ){ |
| 263 | if( read_reslist(argv[2], &resList)==0 ){ |
| 264 | fprintf(stderr, "Failed to load resource list from [%s]", argv[2]); |
| 265 | free_reslist(&resList); |
| 266 | return 1; |
| 267 | } |
| 268 | argc -= 2; |
| 269 | argv += 2; |
| 270 | } |
| 271 | |
| 272 | if( argc>1 ){ |
| 273 | aRes = realloc(resList.aRes, (resList.nRes+argc-1)*sizeof(resList.aRes[0])); |
| 274 | if( aRes==0 || aRes==resList.aRes ){ |
| 275 | fprintf(stderr, "realloc failed\n"); |
| 276 | free_reslist(&resList); |
| 277 | return 1; |
| 278 | } |
| 279 | resList.aRes = aRes; |
| 280 | |
| 281 | for(i=0; i<argc-1; i++){ |
| 282 | resList.aRes[resList.nRes].zName = argv[i+1]; |
| 283 | ++resList.nRes; |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | if( resList.nRes==0 ){ |
| 288 | fprintf(stderr,"No resource files to process\n"); |
| 289 | free_reslist(&resList); |
| 290 | return 1; |
| 291 | } |
| 292 | remove_duplicates(&resList); |
| 293 | |
| 294 | nRes = resList.nRes; |
| 295 | aRes = resList.aRes; |
| 296 | qsort(aRes, nRes, sizeof(aRes[0]), (QsortCompareFunc)compareResource); |
| 297 | |
| 298 | printf("/* Automatically generated code: Do not edit.\n**\n" |
| 299 | "** Rerun the \"mkbuiltin.c\" program or rerun the Fossil\n" |
| 300 | "** makefile to update this source file.\n" |
| 301 | "*/\n"); |
| 302 | for(i=0; i<nRes; i++){ |
| @@ -152,13 +344,14 @@ | |
| 344 | const char *z = aRes[i].zName; |
| 345 | if( strlen(z)>=nPrefix ) z += nPrefix; |
| 346 | while( z[0]=='.' || z[0]=='/' ){ z++; } |
| 347 | aRes[i].zName = z; |
| 348 | } |
| 349 | qsort(aRes, nRes, sizeof(aRes[0]), (QsortCompareFunc)compareResource); |
| 350 | for(i=0; i<nRes; i++){ |
| 351 | printf(" { \"%s\", bidata%d, %d },\n", |
| 352 | aRes[i].zName, aRes[i].idx, aRes[i].nByte); |
| 353 | } |
| 354 | printf("};\n"); |
| 355 | free_reslist(&resList); |
| 356 | return nErr; |
| 357 | } |
| 358 |