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