| /* |
| * Useful functions for winegcc/winewrap |
| * |
| * Copyright 2000 Francois Gouget |
| * Copyright 2002 Dimitrie O. Paun |
| * Copyright 2003 Richard Cohen |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdarg.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| |
| #include "utils.h" |
| |
| #if !defined(min) |
| # define min(x,y) (((x) < (y)) ? (x) : (y)) |
| #endif |
| |
| int verbose = 0; |
| |
| void error(const char* s, ...) |
| { |
| va_list ap; |
| |
| va_start(ap, s); |
| fprintf(stderr, "winegcc: "); |
| vfprintf(stderr, s, ap); |
| fprintf(stderr, "\n"); |
| va_end(ap); |
| exit(2); |
| } |
| |
| void* xmalloc(size_t size) |
| { |
| void* p; |
| |
| if ((p = malloc (size)) == NULL) |
| error("Could not malloc %d bytes.", size); |
| |
| return p; |
| } |
| |
| void *xrealloc(void* p, size_t size) |
| { |
| void* p2 = realloc (p, size); |
| if (size && !p2) |
| error("Could not realloc %d bytes.", size); |
| |
| return p2; |
| } |
| |
| int strendswith(const char* str, const char* end) |
| { |
| int l = strlen(str); |
| int m = strlen(end); |
| |
| return l >= m && strcmp(str + l - m, end) == 0; |
| } |
| |
| char* strmake(const char* fmt, ...) |
| { |
| int n; |
| size_t size = 100; |
| char* p; |
| va_list ap; |
| |
| p = xmalloc (size); |
| while (1) |
| { |
| va_start(ap, fmt); |
| n = vsnprintf (p, size, fmt, ap); |
| va_end(ap); |
| if (n > -1 && (size_t)n < size) return p; |
| size = min( size*2, (size_t)n+1 ); |
| p = xrealloc (p, size); |
| } |
| } |
| |
| strarray* strarray_alloc(void) |
| { |
| strarray* arr = xmalloc(sizeof(*arr)); |
| arr->maximum = arr->size = 0; |
| arr->base = NULL; |
| return arr; |
| } |
| |
| void strarray_free(strarray* arr) |
| { |
| free(arr->base); |
| free(arr); |
| } |
| |
| void strarray_add(strarray* arr, const char* str) |
| { |
| if (arr->size == arr->maximum) |
| { |
| arr->maximum += 10; |
| arr->base = xrealloc(arr->base, sizeof(*(arr->base)) * arr->maximum); |
| } |
| arr->base[arr->size++] = str; |
| } |
| |
| void strarray_del(strarray* arr, int i) |
| { |
| if (i < 0 || i >= arr->size) error("Invalid index i=%d", i); |
| memmove(&arr->base[i], &arr->base[i + 1], (arr->size - i - 1) * sizeof(arr->base[0])); |
| arr->size--; |
| } |
| |
| void strarray_addall(strarray* arr, const strarray* from) |
| { |
| int i; |
| |
| for (i = 0; i < from->size; i++) |
| strarray_add(arr, from->base[i]); |
| } |
| |
| strarray* strarray_dup(const strarray* arr) |
| { |
| strarray* dup = strarray_alloc(); |
| int i; |
| |
| for (i = 0; i < arr->size; i++) |
| strarray_add(dup, arr->base[i]); |
| |
| return dup; |
| } |
| |
| strarray* strarray_fromstring(const char* str, const char* delim) |
| { |
| strarray* arr = strarray_alloc(); |
| char* buf = strdup(str); |
| const char* tok; |
| |
| for(tok = strtok(buf, delim); tok; tok = strtok(0, delim)) |
| strarray_add(arr, strdup(tok)); |
| |
| free(buf); |
| return arr; |
| } |
| |
| char* strarray_tostring(const strarray* arr, const char* sep) |
| { |
| char *str, *newstr; |
| int i; |
| |
| str = strmake("%s", arr->base[0]); |
| for (i = 1; i < arr->size; i++) |
| { |
| newstr = strmake("%s%s%s", str, sep, arr->base[i]); |
| free(str); |
| str = newstr; |
| } |
| |
| return str; |
| } |
| |
| char* get_basename(const char* file) |
| { |
| const char* name; |
| char *base_name, *p; |
| |
| if ((name = strrchr(file, '/'))) name++; |
| else name = file; |
| |
| base_name = strdup(name); |
| if ((p = strrchr(base_name, '.'))) *p = 0; |
| |
| return base_name; |
| } |
| |
| void create_file(const char* name, int mode, const char* fmt, ...) |
| { |
| va_list ap; |
| FILE *file; |
| |
| if (verbose) printf("Creating file %s\n", name); |
| va_start(ap, fmt); |
| if ( !(file = fopen(name, "w")) ) |
| error("Unable to open %s for writing.", name); |
| vfprintf(file, fmt, ap); |
| va_end(ap); |
| fclose(file); |
| chmod(name, mode); |
| } |
| |
| file_type get_file_type(const char* filename) |
| { |
| /* see tools/winebuild/res32.c: check_header for details */ |
| static const char res_sig[] = { 0,0,0,0, 32,0,0,0, 0xff,0xff, 0,0, 0xff,0xff, 0,0, 0,0,0,0, 0,0, 0,0, 0,0,0,0, 0,0,0,0 }; |
| char buf[sizeof(res_sig)]; |
| int fd, cnt; |
| |
| fd = open( filename, O_RDONLY ); |
| if (fd == -1) return file_na; |
| cnt = read(fd, buf, sizeof(buf)); |
| close( fd ); |
| if (cnt == -1) return file_na; |
| |
| if (cnt == sizeof(res_sig) && !memcmp(buf, res_sig, sizeof(res_sig))) return file_res; |
| if (strendswith(filename, ".o")) return file_obj; |
| if (strendswith(filename, ".a")) return file_arh; |
| if (strendswith(filename, ".res")) return file_res; |
| if (strendswith(filename, ".so")) return file_so; |
| if (strendswith(filename, ".dylib")) return file_so; |
| if (strendswith(filename, ".def")) return file_def; |
| if (strendswith(filename, ".spec")) return file_spec; |
| if (strendswith(filename, ".rc")) return file_rc; |
| |
| return file_other; |
| } |
| |
| static char* try_lib_path(const char* dir, const char* pre, |
| const char* library, const char* ext, |
| file_type expected_type) |
| { |
| char *fullname; |
| file_type type; |
| |
| fullname = strmake("%s/%s%s%s", dir, pre, library, ext); |
| if (verbose > 1) fprintf(stderr, "Try %s...", fullname); |
| type = get_file_type(fullname); |
| if (verbose > 1) fprintf(stderr, type == expected_type ? "FOUND!\n" : "no\n"); |
| if (type == expected_type) return fullname; |
| free( fullname ); |
| return 0; |
| } |
| |
| static file_type guess_lib_type(const char* dir, const char* library, char** file) |
| { |
| /* Unix shared object */ |
| if ((*file = try_lib_path(dir, "lib", library, ".so", file_so))) |
| return file_so; |
| |
| /* Mach-O (Darwin/Mac OS X) Dynamic Library behaves mostly like .so */ |
| if ((*file = try_lib_path(dir, "lib", library, ".dylib", file_so))) |
| return file_so; |
| |
| /* Windows DLL */ |
| if ((*file = try_lib_path(dir, "lib", library, ".def", file_def))) |
| return file_dll; |
| if ((*file = try_lib_path(dir, "", library, ".def", file_def))) |
| return file_dll; |
| |
| /* Unix static archives */ |
| if ((*file = try_lib_path(dir, "lib", library, ".a", file_arh))) |
| return file_arh; |
| |
| return file_na; |
| } |
| |
| file_type get_lib_type(strarray* path, const char* library, char** file) |
| { |
| int i; |
| |
| for (i = 0; i < path->size; i++) |
| { |
| file_type type = guess_lib_type(path->base[i], library, file); |
| if (type != file_na) return type; |
| } |
| return file_na; |
| } |
| |
| void spawn(const strarray* prefix, const strarray* args) |
| { |
| int i, status; |
| strarray* arr = strarray_dup(args); |
| const char** argv; |
| char* prog = 0; |
| |
| strarray_add(arr, NULL); |
| argv = arr->base; |
| |
| if (prefix) |
| { |
| for (i = 0; i < prefix->size; i++) |
| { |
| const char* p; |
| struct stat st; |
| |
| if (!(p = strrchr(argv[0], '/'))) p = argv[0]; |
| free( prog ); |
| prog = strmake("%s/%s", prefix->base[i], p); |
| if (stat(prog, &st) == 0) |
| { |
| if ((st.st_mode & S_IFREG) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) |
| { |
| argv[0] = prog; |
| break; |
| } |
| } |
| } |
| } |
| |
| if (verbose) |
| { |
| for(i = 0; argv[i]; i++) printf("%s ", argv[i]); |
| printf("\n"); |
| } |
| |
| if ((status = spawnvp( _P_WAIT, argv[0], argv))) |
| { |
| if (status > 0) error("%s failed.", argv[0]); |
| else perror("winegcc"); |
| exit(3); |
| } |
| |
| free(prog); |
| strarray_free(arr); |
| } |