librazor/util.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Oct 04 18:12:58 2014 +0100 (2014-10-04)
changeset 454 56ff755c268c
parent 442 c4bcba8023a9
child 455 df914f383f5c
permissions -rw-r--r--
Only export symbols starting with razor_ in dynamic library.

Apart from being good practice to avoid clashes with higher-level
libraries and the application, this also fixes an obscure bug: The
gnulib library is used both by librazor (the dynamic library) and
by razor (the executable). In doing so, we want to have two separate
copies of the library despite the code duplication this involves.
Without the explicit limit to export only razor_ symbols, the razor
executable under mingw64 was picking up the getopt_long function
from librazor and the optind variable from libgnu which meant that
it did not see optind changing. Hiding librazor's copy of getopt
causes the linker to find libgnu's copy and everything works.

Note that under mingw librazor-#.dll still contains undocumented
(private) razor_ symbols but these will do no harm as long as nobody
tries to use them.
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011, 2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
     5  *
     6  * This program is free software; you can redistribute it and/or modify
     7  * it under the terms of the GNU General Public License as published by
     8  * the Free Software Foundation; either version 2 of the License, or
     9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along
    17  * with this program; if not, write to the Free Software Foundation, Inc.,
    18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    19  */
    20 
    21 #include "config.h"
    22 
    23 #include <limits.h>
    24 #include <string.h>
    25 #include <sys/types.h>
    26 #include <sys/stat.h>
    27 #include <stdlib.h>
    28 #include <stdio.h>
    29 #include <stdint.h>
    30 #include <errno.h>
    31 #include <unistd.h>
    32 #include <fcntl.h>
    33 #ifdef MSWIN_API
    34 #include <windows.h>
    35 #include <direct.h>
    36 #else
    37 #include <sys/utsname.h>
    38 #endif
    39 #if HAVE_SYS_MMAN_H
    40 #include <sys/mman.h>
    41 #endif
    42 #include <assert.h>
    43 
    44 #include "razor.h"
    45 #include "razor-internal.h"
    46 
    47 #ifndef O_BINARY
    48 #define O_BINARY	0
    49 #endif
    50 
    51 /* Required by gnulib on non-libc platforms */
    52 char *program_name = "librazor";
    53 
    54 void *
    55 zalloc(size_t size)
    56 {
    57 	void *p;
    58 
    59 	p = malloc(size);
    60 	memset(p, 0, size);
    61 
    62 	return p;
    63 }
    64 
    65 void *
    66 razor_file_get_contents(const char *filename, size_t *length, int private,
    67 			struct razor_error **error)
    68 {
    69 	int fd;
    70 	struct stat st;
    71 	void *addr = NULL;
    72 	size_t nb;
    73 	ssize_t res;
    74 
    75 	fd = open(filename, O_RDONLY | O_BINARY);
    76 	if (fd < 0) {
    77 		razor_set_error_posix(error, filename);
    78 		return NULL;
    79 	}
    80 
    81 	if (fstat(fd, &st) < 0) {
    82 		razor_set_error_posix(error, filename);
    83 		close(fd);
    84 		return NULL;
    85 	}
    86 
    87 	*length = st.st_size;
    88 #if HAVE_SYS_MMAN_H
    89 	if (!private) {
    90 		addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    91 		if (addr == MAP_FAILED)
    92 			addr = NULL;
    93 	}
    94 #endif
    95 	if (!addr) {
    96 		addr = malloc(st.st_size);
    97 		if (addr) {
    98 			nb = 0;
    99 			while(nb < st.st_size) {
   100 				res = read(fd, addr + nb, st.st_size - nb);
   101 				if (res <= 0) {
   102 					razor_set_error_posix(error, filename);
   103 					free(addr);
   104 					addr = NULL;
   105 					break;
   106 				}
   107 				nb += res;
   108 			}
   109 		} else
   110 			razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
   111 					"Not enough memory");
   112 	}
   113 	close(fd);
   114 
   115 	return addr;
   116 }
   117 
   118 int razor_file_free_contents(void *addr, size_t length)
   119 {
   120 #if HAVE_SYS_MMAN_H
   121 	return munmap(addr, length);
   122 #else
   123 	free(addr);
   124 	return 0;
   125 #endif
   126 }
   127 
   128 struct qsort_context {
   129 	size_t size;
   130 	razor_compare_with_data_func_t compare;
   131 	void *data;
   132 };
   133 
   134 static void
   135 qsort_swap(void *p1, void *p2, size_t size)
   136 {
   137 	char buffer[size];
   138 
   139 	if (p1 != p2) {
   140 		memcpy(buffer, p1, size);
   141 		memcpy(p1, p2, size);
   142 		memcpy(p2, buffer, size);
   143 	}
   144 }
   145 
   146 static void
   147 __qsort_with_data(void *base, size_t nelem, uint32_t *map,
   148 		  struct qsort_context *ctx)
   149 {
   150 	void *p, *start, *end, *pivot;
   151 	uint32_t *mp, *mstart, *mend, tmp;
   152 	int left, right, result;
   153 	size_t size = ctx->size;
   154 
   155 	p = base;
   156 	start = base;
   157 	end = base + nelem * size;
   158 	mp = map;
   159 	mstart = map;
   160 	mend = map + nelem;
   161 	pivot = base + (rand() % nelem) * size;
   162 
   163 	while (p < end) {
   164 		result = ctx->compare(p, pivot, ctx->data);
   165 		if (result < 0) {
   166 			qsort_swap(p, start, size);
   167 			tmp = *mp;
   168 			*mp = *mstart;
   169 			*mstart = tmp;
   170 			if (start == pivot)
   171 				pivot = p;
   172 			start += size;
   173 			mstart++;
   174 			p += size;
   175 			mp++;
   176 		} else if (result == 0) {
   177 			p += size;
   178 			mp++;
   179 		} else {
   180  			end -= size;
   181 			mend--;
   182 			qsort_swap(p, end, size);
   183 			tmp = *mp;
   184 			*mp = *mend;
   185 			*mend = tmp;
   186 			if (end == pivot)
   187 				pivot = p;
   188 		}
   189 	}
   190 
   191 	left = (start - base) / size;
   192 	right = (base + nelem * size - end) / size;
   193 	if (left > 1)
   194 		__qsort_with_data(base, left, map, ctx);
   195 	if (right > 1)
   196 		__qsort_with_data(end, right, mend, ctx);
   197 }
   198 
   199 uint32_t *
   200 razor_qsort_with_data(void *base, size_t nelem, size_t size,
   201 		      razor_compare_with_data_func_t compare, void *data)
   202 {
   203 	struct qsort_context ctx;
   204 	uint32_t *map;
   205 	int i;
   206 
   207 	if (nelem == 0)
   208 		return NULL;
   209 
   210 	ctx.size = size;
   211 	ctx.compare = compare;
   212 	ctx.data = data;
   213 
   214 	map = malloc(nelem * sizeof (uint32_t));
   215 	for (i = 0; i < nelem; i++)
   216 		map[i] = i;
   217 
   218 	__qsort_with_data(base, nelem, map, &ctx);
   219 
   220 	return map;
   221 }
   222 
   223 void environment_init(struct environment *env)
   224 {
   225 	env->is_set = 0;
   226 	array_init(&env->string_pool);
   227 	array_init(&env->vars);
   228 }
   229 
   230 void environment_add_variable(struct environment *env,
   231 			      const char *variable, const char *value)
   232 {
   233 	char *s;
   234 	uint32_t *r;
   235 	assert(!env->is_set);
   236 
   237 	s = array_add(&env->string_pool,
   238 		      strlen(variable) + strlen(value) + 2);
   239 	sprintf(s, "%s=%s", variable, value);
   240 	r = array_add(&env->vars, sizeof *r);
   241 	*r = s - (char *)env->string_pool.data;
   242 }
   243 
   244 void environment_set(struct environment *env)
   245 {
   246 	int i, count;
   247 	char *s;
   248 #ifndef WIN32
   249 	char *t;
   250 #endif
   251         uint32_t *r;
   252 
   253 	if (!env->is_set) {
   254 		count = env->vars.size / sizeof(uint32_t);
   255 		r = (uint32_t *)env->vars.data;
   256 		for (i = 0; i < count; i++) {
   257 			s = env->string_pool.data + *r++;
   258 #ifdef WIN32
   259 			putenv(s);
   260 #else
   261 			t = strchr(s, '=');
   262 			*t = '\0';
   263 			setenv(s, t + 1, 1);
   264 			*t = '=';
   265 #endif
   266 		}
   267 
   268 		env->is_set = 1;
   269 	}
   270 }
   271 
   272 void environment_unset(struct environment *env)
   273 {
   274 	int i, count;
   275 	char c, *s, *t;
   276         uint32_t *r;
   277 
   278 	if (env->is_set) {
   279 		count = env->vars.size / sizeof(uint32_t);
   280 		r = (uint32_t *)env->vars.data;
   281 		for (i = 0; i < count; i++) {
   282 			s = env->string_pool.data + *r++;
   283 			t = strchr(s, '=');
   284 #ifdef WIN32
   285 			t++;
   286 			c = *t;
   287 			*t = '\0';
   288 			putenv(s);
   289 			*t = c;
   290 #else
   291 			c = *t;
   292 			*t = '\0';
   293 			unsetenv(s);
   294 			*t = c;
   295 #endif
   296 		}
   297 
   298 		env->is_set = 0;
   299 	}
   300 }
   301 
   302 void environment_release(struct environment *env)
   303 {
   304 	environment_unset(env);
   305 	array_release(&env->string_pool);
   306 	array_release(&env->vars);
   307 }
   308 
   309 RAZOR_EXPORT char *razor_concat(const char *s, ...)
   310 {
   311 	va_list args;
   312 	const char *string;
   313 	char *concat;
   314 	size_t n, len;
   315 
   316 	va_start(args, s);
   317 
   318 	len = strlen(s);
   319 	while((string = va_arg(args, const char *)))
   320 		len += strlen(string);
   321 
   322 	va_end(args);
   323 
   324 	concat = malloc(len + 1);
   325 
   326 	if (!concat)
   327 		return NULL;
   328 
   329 	va_start(args, s);
   330 
   331 	len = strlen(s);
   332 	memcpy(concat, s, len);
   333 	n = len;
   334 	while((string = va_arg(args, const char *))) {
   335 		len = strlen(string);
   336 		memcpy(concat + n, string, len);
   337 		n += len;
   338 	}
   339 
   340 	va_end(args);
   341 
   342 	concat[n] = '\0';
   343 
   344 	return concat;
   345 }
   346 
   347 /**
   348  * razor_path_add_root:
   349  *
   350  * Adds a root to a path. path must be an absolute pathname. In POSIX
   351  * environments this is equivalent to the concationation of root and path.
   352  * In Microsoft Windows an adjustment may need to be made for a drive letter
   353  * in path (which will be dropped).
   354  *
   355  * Returns: The new pathname.
   356  **/
   357 RAZOR_EXPORT char *razor_path_add_root(const char *path, const char *root)
   358 {
   359 	if (root && *root)
   360 		return razor_concat(root, SKIP_DRIVE_LETTER(path), NULL);
   361 	else
   362 		return strdup(path);
   363 }
   364 
   365 RAZOR_EXPORT const char *razor_system_arch(void)
   366 {
   367 #ifdef MSWIN_API
   368 	SYSTEM_INFO si;
   369 
   370 	GetNativeSystemInfo(&si);
   371 	switch(si.wProcessorArchitecture)
   372 	{
   373 		case PROCESSOR_ARCHITECTURE_INTEL:
   374 			return "i686";
   375 		case PROCESSOR_ARCHITECTURE_AMD64:
   376 			return "x86_64";
   377 		default:
   378 			return NULL;
   379 	}
   380 #else
   381 	static struct utsname un;
   382 
   383 	if (uname(&un))
   384 		return NULL;
   385 	else
   386 		return un.machine;
   387 #endif
   388 }
   389 
   390 #ifdef MSWIN_API
   391 
   392 char *razor_utf16_to_utf8(const wchar_t *utf16, int len)
   393 {
   394 	int n;
   395 	char *utf8;
   396 
   397 	n = WideCharToMultiByte(CP_UTF8, 0, utf16, len, NULL, 0, NULL, NULL);
   398 	if (len >= 0 && utf16[len])
   399 		n++;
   400 	utf8 = malloc(n);
   401 	(void)WideCharToMultiByte(CP_UTF8, 0, utf16, len, utf8, n, NULL, NULL);
   402 	if (len >= 0 && utf16[len])
   403 		utf8[n - 1] = 0;
   404 
   405 	return utf8;
   406 }
   407 
   408 wchar_t *razor_utf8_to_utf16(const char *utf8, int len)
   409 {
   410 	int n;
   411 	wchar_t *utf16;
   412 
   413 	n = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0);
   414 	if (len >= 0 && utf8[len])
   415 		n++;
   416 	utf16 = malloc(n * sizeof(wchar_t));
   417 	(void)MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, n);
   418 	if (len >= 0 && utf8[len])
   419 		utf16[n - 1] = 0;
   420 
   421 	return utf16;
   422 }
   423 
   424 #endif	/* MSWIN_API */