project_files/frontlib/util/util.c
author dag10 <gottlieb.drew@gmail.com>
Wed, 16 Jan 2013 18:34:43 -0500
changeset 8393 85bd6c7b2641
parent 7316 f7b49b2c5d84
child 8094 6c5b4e69f03d
child 10017 de822cd3df3a
permissions -rw-r--r--
Can now change theme for static and mission maps. Fixed mission map descriptions that had commas which broke them. Now, you must escape commas in map descriptions. Made bgwidget repaint on animation tick to avoid buffer-not-clearing issue with widgets that change overtop the background leaving a ghost image of the widget's previous state. Generated map is now the default map in the mapconfig widget.

/*
 * Hedgewars, a free turn based strategy game
 * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "util.h"
#include "logging.h"

#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>

char *flib_asprintf(const char *fmt, ...) {
	va_list argp;
	va_start(argp, fmt);
	char *result = flib_vasprintf(fmt, argp);
	va_end(argp);
	return result;
}

char *flib_vasprintf(const char *fmt, va_list args) {
	char *result = NULL;
	if(!log_badargs_if(fmt==NULL)) {
		int requiredSize = vsnprintf(NULL, 0, fmt, args)+1;					// Figure out how much memory we need,
		if(!log_e_if(requiredSize<0, "Error formatting string with template \"%s\"", fmt)) {
			char *tmpbuf = flib_malloc(requiredSize);						// allocate it
			if(tmpbuf && vsnprintf(tmpbuf, requiredSize, fmt, args)>=0) {	// and then do the actual formatting.
				result = tmpbuf;
				tmpbuf = NULL;
			}
			free(tmpbuf);
		}
	}
	return result;
}

char *flib_join(char **parts, int partCount, const char *delimiter) {
	char *result = NULL;
	if(!log_badargs_if2(parts==NULL, delimiter==NULL)) {
		size_t totalSize = 1;
		size_t delimLen = strlen(delimiter);
		for(int i=0; i<partCount; i++) {
			totalSize += strlen(parts[i]) + delimLen;
		}
		result = flib_malloc(totalSize);

		if(result) {
			size_t outpos = 0;
			for(int i=0; i<partCount; i++) {
				if(i>0) {
					strcpy(result+outpos, delimiter);
					outpos += delimLen;
				}
				strcpy(result+outpos, parts[i]);
				outpos += strlen(parts[i]);
			}
		}
	}
	return result;
}

char *flib_strdupnull(const char *str) {
	return str==NULL ? NULL : flib_asprintf("%s", str);
}

void *flib_bufdupnull(const void *buf, size_t size) {
	void *result = NULL;
	if(!log_badargs_if(buf==NULL && size>0)) {
		result = flib_malloc(size);
		if(result) {
			memcpy(result, buf, size);
		}
	}
	return result;
}

void *flib_malloc(size_t size) {
	void *result = malloc(size);
	if(!result && size>0) {
		flib_log_e("Out of memory trying to malloc %zu bytes.", size);
	}
	return result;
}

void *flib_calloc(size_t count, size_t elementsize) {
	void *result = calloc(count, elementsize);
	if(!result && count>0 && elementsize>0) {
		flib_log_e("Out of memory trying to calloc %zu objects of %zu bytes each.", count, elementsize);
	}
	return result;
}

void *flib_realloc(void *ptr, size_t size) {
	void *result = realloc(ptr, size);
	if(!result && size>0) {
		flib_log_e("Out of memory trying to realloc %zu bytes.", size);
	}
	return result;
}

static bool isAsciiAlnum(char c) {
	return (c>='0' && c<='9') || (c>='a' && c <='z') || (c>='A' && c <='Z');
}

char *flib_urlencode(const char *inbuf) {
	return flib_urlencode_pred(inbuf, isAsciiAlnum);
}

static size_t countCharsToEscape(const char *inbuf, bool (*needsEscaping)(char c)) {
	size_t result = 0;
	for(const char *c=inbuf; *c; c++) {
		if(needsEscaping(*c)) {
			result++;
		}
	}
	return result;
}

char *flib_urlencode_pred(const char *inbuf, bool (*needsEscaping)(char c)) {
	char *result = NULL;
	if(inbuf && !log_badargs_if(needsEscaping == NULL)) {
		size_t insize = strlen(inbuf);
		if(!log_e_if(insize > SIZE_MAX/4, "String too long: %zu bytes.", insize)) {
			size_t escapeCount = countCharsToEscape(inbuf, needsEscaping);
			result = flib_malloc(insize + escapeCount*2 + 1);
		}
		if(result) {
			char *out = result;
			for(const char *in = inbuf; *in; in++) {
				if(!needsEscaping(*in)) {
					*out = *in;
					out++;
				} else {
					snprintf(out, 4, "%%%02x", (unsigned)(*(uint8_t*)in));
					out += 3;
				}
			}
			*out = 0;
		}
	}
	return result;
}

char *flib_urldecode(const char *inbuf) {
	if(!inbuf) {
		return NULL;
	}
	char *outbuf = flib_malloc(strlen(inbuf)+1);
	if(!outbuf) {
		return NULL;
	}

    size_t inpos = 0, outpos = 0;
    while(inbuf[inpos]) {
        if(inbuf[inpos] == '%' && isxdigit(inbuf[inpos+1]) && isxdigit(inbuf[inpos+2])) {
            char temp[3] = {inbuf[inpos+1],inbuf[inpos+2],0};
            outbuf[outpos++] = strtol(temp, NULL, 16);
            inpos += 3;
        } else {
        	outbuf[outpos++] = inbuf[inpos++];
        }
    }
    outbuf[outpos] = 0;
    char *shrunk = realloc(outbuf, outpos+1);
    return shrunk ? shrunk : outbuf;
}

bool flib_contains_dir_separator(const char *str) {
	if(!log_badargs_if(!str)) {
		for(;*str;str++) {
			if(*str=='\\' || *str=='/') {
				return true;
			}
		}
	}
	return false;
}

bool flib_strempty(const char *str) {
	return !str || !*str;
}

int flib_gets(char *str, size_t strlen) {
	if(fgets(str, strlen, stdin)) {
		for(char *s=str; *s; s++) {
			if(*s=='\r' || *s=='\n') {
				*s = 0;
				break;
			}
		}
		return 0;
	}
	return -1;
}