- Syntax is now much closer to gnu ar, but still supports whatever was supported before, with the following exceptions (which gnu ar has too): - lib is now mandatory (was optional and defaulted to ar_test.a before). - Path cannot start with '-' (but ./-myfile.o is OK). - Unlike gnu ar, modes are still optional (as before). - Now supports also (like gnu ar): - First argument as options doesn't have to start with '-', later options do. - Now supports mode v (verbose) with same output format as gnu ar. - Any names for lib/objs (were limited to .a/.o - broke cmake on windows). - Now explicitly fail on options which would be destructive for the user. - Now doesn't get confused by options between file arguments. - Still ignores other unknown options - as before. - Now doesn't read out-of-bounds if an option is one char. - As a result, cmake for windows can now use tiny_libmaker as ar, and configure can also detect tiny_libmaker as a valid ar (both couldn't before). Ignoring all options could previously cause to misinterpret the mode in a destructive way, e.g. if the user wanted to do something with an existing archive (such as p - print, or x - extract, etc), then it would instead just delete (re-create) the archive. Modes which can be destructive if ignored now explicitly fail. These include [habdioptxN]. Note that 'h' can be ignored, but this way we also implicitly print the usage for -h/--help. The .a/.o name limitations previously resulted in complete failure on some cases, such as cmake on windows which uses <filename>.obj and <libname>.lib .
Unified · Split
| @@ -71,50 +71,69 @@ ArHdr arhdro = { · 70 unmodified lines | ||
| 71 | 71 | ARFMAG |
| 72 | 72 | }; |
| 73 | 73 | |
| 74 | +/* Returns 1 if s contains any of the chars of list, else 0 */ | |
| 75 | +int contains_any(const char *s, const char *list) { | |
| 76 | + const char *l; | |
| 77 | + for (; *s; s++) { | |
| 78 | + for (l = list; *l; l++) { | |
| 79 | + if (*s == *l) | |
| 80 | + return 1; | |
| 81 | + } | |
| 82 | + } | |
| 83 | + return 0; | |
| 84 | +} | |
| 85 | + | |
| 86 | +int usage(int ret) { | |
| 87 | + fprintf(stderr, "usage: tiny_libmaker [rcsv] lib file...\n"); | |
| 88 | + fprintf(stderr, "Always creates a new lib. [abdioptxN] are explicitly rejected.\n"); | |
| 89 | + return ret; | |
| 90 | +} | |
| 91 | + | |
| 74 | 92 | int main(int argc, char **argv) |
| 75 | 93 | { |
| 76 | 94 | FILE *fi, *fh = NULL, *fo = NULL; |
| 77 | 95 | ElfW(Ehdr) *ehdr; |
| 78 | 96 | ElfW(Shdr) *shdr; |
| 79 | 97 | ElfW(Sym) *sym; |
| 80 | − int i, fsize, iarg; | |
| 98 | + int i, fsize, i_lib, i_obj; | |
| 81 | 99 | char *buf, *shstr, *symtab = NULL, *strtab = NULL; |
| 82 | 100 | int symtabsize = 0;//, strtabsize = 0; |
| 83 | 101 | char *anames = NULL; |
| 84 | 102 | int *afpos = NULL; |
| 85 | 103 | int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs; |
| 86 | − char afile[260], tfile[260], stmp[20]; | |
| 104 | + char tfile[260], stmp[20]; | |
| 87 | 105 | char *file, *name; |
| 88 | 106 | int ret = 2; |
| 107 | + char *ops_conflict = "habdioptxN"; // unsupported but destructive if ignored. | |
| 108 | + int verbose = 0; | |
| 89 | 109 | |
| 90 | − | |
| 91 | − strcpy(afile, "ar_test.a"); | |
| 92 | − iarg = 1; | |
| 93 | − | |
| 94 | − if (argc < 2) | |
| 95 | − { | |
| 96 | − printf("usage: tiny_libmaker [lib] file...\n"); | |
| 97 | − return 1; | |
| 98 | − } | |
| 99 | − for (i=1; i<argc; i++) { | |
| 100 | − istrlen = strlen(argv[i]); | |
| 101 | − if (argv[i][istrlen-2] == '.') { | |
| 102 | − if(argv[i][istrlen-1] == 'a') | |
| 103 | − strcpy(afile, argv[i]); | |
| 104 | − else if(argv[i][istrlen-1] == 'o') { | |
| 105 | − iarg = i; | |
| 106 | − break; | |
| 107 | − } | |
| 110 | + i_lib = 0; i_obj = 0; // will hold the index of the lib and first obj | |
| 111 | + for (i = 1; i < argc; i++) { | |
| 112 | + const char *a = argv[i]; | |
| 113 | + if (*a == '-' && strstr(a, ".")) | |
| 114 | + return usage(1); // -x.y is always invalid (same as gnu ar) | |
| 115 | + if ((*a == '-') || (i == 1 && !strstr(a, "."))) { // options argument | |
| 116 | + if (contains_any(a, ops_conflict)) | |
| 117 | + return usage(1); | |
| 118 | + if (strstr(a, "v")) | |
| 119 | + verbose = 1; | |
| 120 | + } else { // lib or obj files: don't abort - keep validating all args. | |
| 121 | + if (!i_lib) // first file is the lib | |
| 122 | + i_lib = i; | |
| 123 | + else if (!i_obj) // second file is the first obj | |
| 124 | + i_obj = i; | |
| 108 | 125 | } |
| 109 | 126 | } |
| 127 | + if (!i_obj) // implies also no i_lib | |
| 128 | + return usage(1); | |
| 110 | 129 | |
| 111 | − if ((fh = fopen(afile, "wb")) == NULL) | |
| 130 | + if ((fh = fopen(argv[i_lib], "wb")) == NULL) | |
| 112 | 131 | { |
| 113 | − fprintf(stderr, "Can't open file %s \n", afile); | |
| 132 | + fprintf(stderr, "Can't open file %s \n", argv[i_lib]); | |
| 114 | 133 | goto the_end; |
| 115 | 134 | } |
| 116 | 135 | |
| 117 | − sprintf(tfile, "%s.tmp", afile); | |
| 136 | + sprintf(tfile, "%s.tmp", argv[i_lib]); | |
| 118 | 137 | if ((fo = fopen(tfile, "wb+")) == NULL) |
| 119 | 138 | { |
| 120 | 139 | fprintf(stderr, "Can't create temporary file %s\n", tfile); |
| @@ -125,16 +144,19 @@ int main(int argc, char **argv) · 4 unmodified lines | ||
| 125 | 144 | afpos = realloc(NULL, funcmax * sizeof *afpos); // 250 func |
| 126 | 145 | memcpy(&arhdro.ar_mode, "100666", 6); |
| 127 | 146 | |
| 128 | − //iarg = 1; | |
| 129 | − while (iarg < argc) | |
| 147 | + // i_obj = first input object file | |
| 148 | + while (i_obj < argc) | |
| 130 | 149 | { |
| 131 | − if (!strcmp(argv[iarg], "rcs")) { | |
| 132 | − iarg++; | |
| 150 | + if (*argv[i_obj] == '-') { // by now, all options start with '-' | |
| 151 | + i_obj++; | |
| 133 | 152 | continue; |
| 134 | 153 | } |
| 135 | − if ((fi = fopen(argv[iarg], "rb")) == NULL) | |
| 154 | + if (verbose) | |
| 155 | + printf("a - %s\n", argv[i_obj]); | |
| 156 | + | |
| 157 | + if ((fi = fopen(argv[i_obj], "rb")) == NULL) | |
| 136 | 158 | { |
| 137 | − fprintf(stderr, "Can't open file %s \n", argv[iarg]); | |
| 159 | + fprintf(stderr, "Can't open file %s \n", argv[i_obj]); | |
| 138 | 160 | goto the_end; |
| 139 | 161 | } |
| 140 | 162 | fseek(fi, 0, SEEK_END); |
| @@ -144,13 +166,11 @@ int main(int argc, char **argv) · 3 unmodified lines | ||
| 144 | 166 | fread(buf, fsize, 1, fi); |
| 145 | 167 | fclose(fi); |
| 146 | 168 | |
| 147 | − //printf("%s:\n", argv[iarg]); | |
| 148 | − | |
| 149 | 169 | // elf header |
| 150 | 170 | ehdr = (ElfW(Ehdr) *)buf; |
| 151 | 171 | if (ehdr->e_ident[4] != ELFCLASSW) |
| 152 | 172 | { |
| 153 | − fprintf(stderr, "Unsupported Elf Class: %s\n", argv[iarg]); | |
| 173 | + fprintf(stderr, "Unsupported Elf Class: %s\n", argv[i_obj]); | |
| 154 | 174 | goto the_end; |
| 155 | 175 | } |
| 156 | 176 | |
| @@ -202,7 +222,7 @@ int main(int argc, char **argv) · 45 unmodified lines | ||
| 202 | 222 | } |
| 203 | 223 | } |
| 204 | 224 | |
| 205 | − file = argv[iarg]; | |
| 225 | + file = argv[i_obj]; | |
| 206 | 226 | for (name = strchr(file, 0); |
| 207 | 227 | name > file && name[-1] != '/' && name[-1] != '\\'; |
| 208 | 228 | --name); |
| @@ -217,7 +237,7 @@ int main(int argc, char **argv) · 8 unmodified lines | ||
| 217 | 237 | fwrite(&arhdro, sizeof(arhdro), 1, fo); |
| 218 | 238 | fwrite(buf, fsize, 1, fo); |
| 219 | 239 | free(buf); |
| 220 | − iarg++; | |
| 240 | + i_obj++; | |
| 221 | 241 | fpos += (fsize + sizeof(arhdro)); |
| 222 | 242 | } |
| 223 | 243 | hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int); |