librazor/util.c
author ali <j.a.harlow@letterboxes.org>
Thu Apr 14 11:59:56 2016 +0100 (2016-04-14)
changeset 467 4b7270fd3201
parent 455 df914f383f5c
child 475 008c75a5e08d
permissions -rw-r--r--
Release version 0.6.1
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@458
    65
#if HAVE_SYS_MMAN_H
ali@458
    66
#define OPEN_FILE_USED		(1U<<0)
ali@458
    67
#define OPEN_FILE_MMAPPED	(1U<<1)
ali@458
    68
ali@458
    69
struct open_file {
ali@458
    70
	void *addr;
ali@458
    71
	size_t length;
ali@458
    72
	uint32_t flags;
ali@458
    73
};
ali@458
    74
ali@458
    75
struct array open_files = { 0, };
ali@458
    76
#endif	/* HAVE_SYS_MMAN_H */
ali@458
    77
ali@424
    78
void *
ali@424
    79
razor_file_get_contents(const char *filename, size_t *length, int private,
ali@424
    80
			struct razor_error **error)
ali@322
    81
{
ali@322
    82
	int fd;
ali@322
    83
	struct stat st;
ali@424
    84
	void *addr = NULL;
ali@322
    85
	size_t nb;
ali@322
    86
	ssize_t res;
ali@458
    87
#if HAVE_SYS_MMAN_H
ali@458
    88
	struct open_file *of, *ofend;
ali@458
    89
#endif
ali@322
    90
ali@322
    91
	fd = open(filename, O_RDONLY | O_BINARY);
ali@424
    92
	if (fd < 0) {
ali@447
    93
		razor_set_error_posix(error, filename);
ali@322
    94
		return NULL;
ali@424
    95
	}
ali@322
    96
ali@322
    97
	if (fstat(fd, &st) < 0) {
ali@447
    98
		razor_set_error_posix(error, filename);
ali@322
    99
		close(fd);
ali@322
   100
		return NULL;
ali@322
   101
	}
ali@322
   102
ali@322
   103
	*length = st.st_size;
ali@458
   104
ali@322
   105
#if HAVE_SYS_MMAN_H
ali@458
   106
	ofend = open_files.data + open_files.size;
ali@458
   107
	for (of = open_files.data; of < ofend; of++)
ali@458
   108
		if (!(of->flags & OPEN_FILE_USED))
ali@458
   109
			break;
ali@458
   110
	if (of == ofend) {
ali@458
   111
		of = array_add(&open_files, sizeof *of);
ali@458
   112
		of->flags = 0;
ali@458
   113
	}
ali@458
   114
ali@424
   115
	if (!private) {
ali@424
   116
		addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
ali@424
   117
		if (addr == MAP_FAILED)
ali@424
   118
			addr = NULL;
ali@458
   119
		else
ali@458
   120
			of->flags = OPEN_FILE_USED | OPEN_FILE_MMAPPED;
ali@322
   121
	}
ali@458
   122
#endif	/* HAVE_SYS_MMAN_H */
ali@424
   123
	if (!addr) {
ali@424
   124
		addr = malloc(st.st_size);
ali@424
   125
		if (addr) {
ali@458
   126
#if HAVE_SYS_MMAN_H
ali@458
   127
			of->flags = OPEN_FILE_USED;
ali@458
   128
#endif
ali@424
   129
			nb = 0;
ali@424
   130
			while(nb < st.st_size) {
ali@424
   131
				res = read(fd, addr + nb, st.st_size - nb);
ali@424
   132
				if (res <= 0) {
ali@447
   133
					razor_set_error_posix(error, filename);
ali@424
   134
					free(addr);
ali@424
   135
					addr = NULL;
ali@424
   136
					break;
ali@424
   137
				}
ali@424
   138
				nb += res;
ali@424
   139
			}
ali@424
   140
		} else
ali@447
   141
			razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
ali@447
   142
					"Not enough memory");
ali@424
   143
	}
ali@322
   144
	close(fd);
ali@322
   145
ali@458
   146
#if HAVE_SYS_MMAN_H
ali@458
   147
	of->addr = addr;
ali@458
   148
	of->length = st.st_size;
ali@458
   149
#endif
ali@458
   150
ali@322
   151
	return addr;
ali@322
   152
}
ali@322
   153
ali@424
   154
int razor_file_free_contents(void *addr, size_t length)
ali@322
   155
{
ali@322
   156
#if HAVE_SYS_MMAN_H
ali@458
   157
	int retval, mmapped;
ali@458
   158
	struct open_file *of, *ofend;
ali@458
   159
ali@458
   160
	ofend = open_files.data + open_files.size;
ali@458
   161
	for (of = open_files.data; of < ofend; of++)
ali@458
   162
		if ((of->flags & OPEN_FILE_USED) && of->addr == addr)
ali@458
   163
			break;
ali@458
   164
ali@458
   165
	if (of == ofend)
ali@458
   166
		return 1;
ali@458
   167
ali@458
   168
	length = of->length;
ali@458
   169
	mmapped = of->flags & OPEN_FILE_MMAPPED;
ali@458
   170
	of->flags &= ~OPEN_FILE_USED;
ali@458
   171
ali@458
   172
	for (of = open_files.data; of < ofend; of++)
ali@458
   173
		if (of->flags & OPEN_FILE_USED)
ali@458
   174
			break;
ali@458
   175
ali@458
   176
	if (of == ofend) {
ali@458
   177
		array_release(&open_files);
ali@458
   178
		array_init(&open_files);
ali@458
   179
	}
ali@458
   180
ali@458
   181
	if (mmapped)
ali@458
   182
		return munmap(addr, length);
ali@458
   183
#endif
ali@458
   184
ali@322
   185
	free(addr);
ali@322
   186
	return 0;
ali@322
   187
}
ali@322
   188
rhughes@241
   189
struct qsort_context {
rhughes@241
   190
	size_t size;
rhughes@241
   191
	razor_compare_with_data_func_t compare;
rhughes@241
   192
	void *data;
rhughes@241
   193
};
rhughes@241
   194
rhughes@241
   195
static void
rhughes@241
   196
qsort_swap(void *p1, void *p2, size_t size)
rhughes@241
   197
{
rhughes@241
   198
	char buffer[size];
rhughes@241
   199
ali@406
   200
	if (p1 != p2) {
ali@406
   201
		memcpy(buffer, p1, size);
ali@406
   202
		memcpy(p1, p2, size);
ali@406
   203
		memcpy(p2, buffer, size);
ali@406
   204
	}
rhughes@241
   205
}
rhughes@241
   206
rhughes@241
   207
static void
rhughes@241
   208
__qsort_with_data(void *base, size_t nelem, uint32_t *map,
rhughes@241
   209
		  struct qsort_context *ctx)
rhughes@241
   210
{
rhughes@241
   211
	void *p, *start, *end, *pivot;
rhughes@241
   212
	uint32_t *mp, *mstart, *mend, tmp;
rhughes@241
   213
	int left, right, result;
rhughes@241
   214
	size_t size = ctx->size;
rhughes@241
   215
rhughes@241
   216
	p = base;
rhughes@241
   217
	start = base;
rhughes@241
   218
	end = base + nelem * size;
rhughes@241
   219
	mp = map;
rhughes@241
   220
	mstart = map;
rhughes@241
   221
	mend = map + nelem;
ali@337
   222
	pivot = base + (rand() % nelem) * size;
rhughes@241
   223
rhughes@241
   224
	while (p < end) {
rhughes@241
   225
		result = ctx->compare(p, pivot, ctx->data);
rhughes@241
   226
		if (result < 0) {
rhughes@241
   227
			qsort_swap(p, start, size);
rhughes@241
   228
			tmp = *mp;
rhughes@241
   229
			*mp = *mstart;
rhughes@241
   230
			*mstart = tmp;
rhughes@241
   231
			if (start == pivot)
rhughes@241
   232
				pivot = p;
rhughes@241
   233
			start += size;
rhughes@241
   234
			mstart++;
rhughes@241
   235
			p += size;
rhughes@241
   236
			mp++;
rhughes@241
   237
		} else if (result == 0) {
rhughes@241
   238
			p += size;
rhughes@241
   239
			mp++;
rhughes@241
   240
		} else {
rhughes@241
   241
 			end -= size;
rhughes@241
   242
			mend--;
rhughes@241
   243
			qsort_swap(p, end, size);
rhughes@241
   244
			tmp = *mp;
rhughes@241
   245
			*mp = *mend;
rhughes@241
   246
			*mend = tmp;
rhughes@241
   247
			if (end == pivot)
rhughes@241
   248
				pivot = p;
rhughes@241
   249
		}
rhughes@241
   250
	}
rhughes@241
   251
rhughes@241
   252
	left = (start - base) / size;
rhughes@241
   253
	right = (base + nelem * size - end) / size;
rhughes@241
   254
	if (left > 1)
rhughes@241
   255
		__qsort_with_data(base, left, map, ctx);
rhughes@241
   256
	if (right > 1)
rhughes@241
   257
		__qsort_with_data(end, right, mend, ctx);
rhughes@241
   258
}
rhughes@241
   259
rhughes@241
   260
uint32_t *
rhughes@241
   261
razor_qsort_with_data(void *base, size_t nelem, size_t size,
rhughes@241
   262
		      razor_compare_with_data_func_t compare, void *data)
rhughes@241
   263
{
rhughes@241
   264
	struct qsort_context ctx;
rhughes@241
   265
	uint32_t *map;
rhughes@241
   266
	int i;
rhughes@241
   267
rhughes@241
   268
	if (nelem == 0)
rhughes@241
   269
		return NULL;
rhughes@241
   270
rhughes@241
   271
	ctx.size = size;
rhughes@241
   272
	ctx.compare = compare;
rhughes@241
   273
	ctx.data = data;
rhughes@241
   274
rhughes@241
   275
	map = malloc(nelem * sizeof (uint32_t));
rhughes@241
   276
	for (i = 0; i < nelem; i++)
rhughes@241
   277
		map[i] = i;
rhughes@241
   278
rhughes@241
   279
	__qsort_with_data(base, nelem, map, &ctx);
rhughes@241
   280
rhughes@241
   281
	return map;
rhughes@241
   282
}
ali@372
   283
ali@372
   284
void environment_init(struct environment *env)
ali@372
   285
{
ali@372
   286
	env->is_set = 0;
ali@372
   287
	array_init(&env->string_pool);
ali@372
   288
	array_init(&env->vars);
ali@372
   289
}
ali@372
   290
ali@372
   291
void environment_add_variable(struct environment *env,
ali@372
   292
			      const char *variable, const char *value)
ali@372
   293
{
ali@372
   294
	char *s;
ali@372
   295
	uint32_t *r;
ali@372
   296
	assert(!env->is_set);
ali@372
   297
ali@372
   298
	s = array_add(&env->string_pool,
ali@372
   299
		      strlen(variable) + strlen(value) + 2);
ali@372
   300
	sprintf(s, "%s=%s", variable, value);
ali@372
   301
	r = array_add(&env->vars, sizeof *r);
ali@372
   302
	*r = s - (char *)env->string_pool.data;
ali@372
   303
}
ali@372
   304
ali@372
   305
void environment_set(struct environment *env)
ali@372
   306
{
ali@372
   307
	int i, count;
ali@442
   308
	char *s;
ali@442
   309
#ifndef WIN32
ali@442
   310
	char *t;
ali@442
   311
#endif
ali@372
   312
        uint32_t *r;
ali@372
   313
ali@372
   314
	if (!env->is_set) {
ali@372
   315
		count = env->vars.size / sizeof(uint32_t);
ali@372
   316
		r = (uint32_t *)env->vars.data;
ali@372
   317
		for (i = 0; i < count; i++) {
ali@372
   318
			s = env->string_pool.data + *r++;
ali@406
   319
#ifdef WIN32
ali@372
   320
			putenv(s);
ali@406
   321
#else
ali@406
   322
			t = strchr(s, '=');
ali@406
   323
			*t = '\0';
ali@406
   324
			setenv(s, t + 1, 1);
ali@406
   325
			*t = '=';
ali@406
   326
#endif
ali@372
   327
		}
ali@372
   328
ali@372
   329
		env->is_set = 1;
ali@372
   330
	}
ali@372
   331
}
ali@372
   332
ali@372
   333
void environment_unset(struct environment *env)
ali@372
   334
{
ali@372
   335
	int i, count;
ali@372
   336
	char c, *s, *t;
ali@372
   337
        uint32_t *r;
ali@372
   338
ali@372
   339
	if (env->is_set) {
ali@372
   340
		count = env->vars.size / sizeof(uint32_t);
ali@372
   341
		r = (uint32_t *)env->vars.data;
ali@372
   342
		for (i = 0; i < count; i++) {
ali@372
   343
			s = env->string_pool.data + *r++;
ali@406
   344
			t = strchr(s, '=');
ali@406
   345
#ifdef WIN32
ali@406
   346
			t++;
ali@372
   347
			c = *t;
ali@372
   348
			*t = '\0';
ali@372
   349
			putenv(s);
ali@372
   350
			*t = c;
ali@406
   351
#else
ali@406
   352
			c = *t;
ali@406
   353
			*t = '\0';
ali@406
   354
			unsetenv(s);
ali@406
   355
			*t = c;
ali@406
   356
#endif
ali@372
   357
		}
ali@372
   358
ali@372
   359
		env->is_set = 0;
ali@372
   360
	}
ali@372
   361
}
ali@372
   362
ali@372
   363
void environment_release(struct environment *env)
ali@372
   364
{
ali@372
   365
	environment_unset(env);
ali@372
   366
	array_release(&env->string_pool);
ali@372
   367
	array_release(&env->vars);
ali@372
   368
}
ali@403
   369
ali@403
   370
RAZOR_EXPORT char *razor_concat(const char *s, ...)
ali@403
   371
{
ali@403
   372
	va_list args;
ali@403
   373
	const char *string;
ali@403
   374
	char *concat;
ali@403
   375
	size_t n, len;
ali@403
   376
ali@403
   377
	va_start(args, s);
ali@403
   378
ali@403
   379
	len = strlen(s);
ali@403
   380
	while((string = va_arg(args, const char *)))
ali@403
   381
		len += strlen(string);
ali@403
   382
ali@403
   383
	va_end(args);
ali@403
   384
ali@403
   385
	concat = malloc(len + 1);
ali@403
   386
ali@403
   387
	if (!concat)
ali@403
   388
		return NULL;
ali@403
   389
ali@403
   390
	va_start(args, s);
ali@403
   391
ali@403
   392
	len = strlen(s);
ali@403
   393
	memcpy(concat, s, len);
ali@403
   394
	n = len;
ali@403
   395
	while((string = va_arg(args, const char *))) {
ali@403
   396
		len = strlen(string);
ali@403
   397
		memcpy(concat + n, string, len);
ali@403
   398
		n += len;
ali@403
   399
	}
ali@403
   400
ali@403
   401
	va_end(args);
ali@403
   402
ali@403
   403
	concat[n] = '\0';
ali@403
   404
ali@403
   405
	return concat;
ali@403
   406
}
ali@403
   407
ali@403
   408
RAZOR_EXPORT const char *razor_system_arch(void)
ali@403
   409
{
ali@403
   410
#ifdef MSWIN_API
ali@403
   411
	SYSTEM_INFO si;
ali@403
   412
ali@403
   413
	GetNativeSystemInfo(&si);
ali@403
   414
	switch(si.wProcessorArchitecture)
ali@403
   415
	{
ali@403
   416
		case PROCESSOR_ARCHITECTURE_INTEL:
ali@403
   417
			return "i686";
ali@403
   418
		case PROCESSOR_ARCHITECTURE_AMD64:
ali@403
   419
			return "x86_64";
ali@403
   420
		default:
ali@403
   421
			return NULL;
ali@403
   422
	}
ali@403
   423
#else
ali@403
   424
	static struct utsname un;
ali@403
   425
ali@403
   426
	if (uname(&un))
ali@403
   427
		return NULL;
ali@403
   428
	else
ali@403
   429
		return un.machine;
ali@403
   430
#endif
ali@403
   431
}
ali@416
   432
ali@416
   433
#ifdef MSWIN_API
ali@416
   434
ali@416
   435
char *razor_utf16_to_utf8(const wchar_t *utf16, int len)
ali@416
   436
{
ali@416
   437
	int n;
ali@416
   438
	char *utf8;
ali@416
   439
ali@455
   440
	if (len == 0)
ali@455
   441
		return strdup("");
ali@455
   442
ali@416
   443
	n = WideCharToMultiByte(CP_UTF8, 0, utf16, len, NULL, 0, NULL, NULL);
ali@455
   444
	if (len > 0)
ali@416
   445
		n++;
ali@416
   446
	utf8 = malloc(n);
ali@416
   447
	(void)WideCharToMultiByte(CP_UTF8, 0, utf16, len, utf8, n, NULL, NULL);
ali@455
   448
	if (len > 0)
ali@416
   449
		utf8[n - 1] = 0;
ali@416
   450
ali@416
   451
	return utf8;
ali@416
   452
}
ali@416
   453
ali@416
   454
wchar_t *razor_utf8_to_utf16(const char *utf8, int len)
ali@416
   455
{
ali@416
   456
	int n;
ali@416
   457
	wchar_t *utf16;
ali@416
   458
ali@455
   459
	if (len == 0) {
ali@455
   460
		utf16 = calloc(1, sizeof(wchar_t));
ali@455
   461
		return utf16;
ali@455
   462
	}
ali@455
   463
ali@416
   464
	n = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0);
ali@455
   465
	if (len > 0)
ali@416
   466
		n++;
ali@416
   467
	utf16 = malloc(n * sizeof(wchar_t));
ali@416
   468
	(void)MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, n);
ali@455
   469
	if (len > 0)
ali@416
   470
		utf16[n - 1] = 0;
ali@416
   471
ali@416
   472
	return utf16;
ali@416
   473
}
ali@416
   474
ali@416
   475
#endif	/* MSWIN_API */