steed/src/steed/util.c

525 lines
8.8 KiB
C

#include "externals.h"
#include "config.h"
#include "util.h"
#include "idf.h"
void tolow(char *p)
{
while (*p) {
if (*p >= 'A' && *p <= 'Z')
*p |= 0x20;
p ++;
}
}
int strlowcmp(const char *s, const char *d)
{
int rc;
char *ss = NULL;
char *dd = NULL;
ss = strdup(s);
dd = strdup(d);
if (!ss || !dd) {
rc = strcmp(s, d);
goto err;
}
tolow(ss);
tolow(dd);
rc = strcmp(ss, dd);
err:
if (ss)
free(ss);
if (dd)
free(dd);
return rc;
}
char *getfilepath(const char *d, const char *n)
{
int i = ((d)?strlen(d):0) + ((n)?strlen(n):0) + 3;
char *p = malloc(i);
if (p) {
p[0] = 0;
if (d) {
strcpy(p, d);
strcat(p, "/");
}
strcat(p, n);
unix_path(p);
}
return p;
}
char *getpath(const char *d, const char *n)
{
char *p = getfilepath(d, n);
strcat(p, "/");
return p;
}
int is_space(int c)
{
return (c == ' ' || c == '\t');
}
int is_empty(const char *str)
{
if (!str || !*str)
return 1;
while (*str && !is_space(*str++))
return 0;
return 1;
}
char *strip(char *s)
{
char *e;
while (is_space(*s))
s ++;
if (!*s)
return s;
e = s + strlen(s) - 1;
while (e != s && is_space(*e)) {
*e = 0;
e --;
}
return s;
}
int process_cmd(char *n, char *v, struct parser *cmd_parser)
{
int i;
n = strip(n);
v = strip(v);
for (i = 0; cmd_parser[i].cmd; i++) {
if (!strcmp(cmd_parser[i].cmd, n)) {
return cmd_parser[i].fn(v, cmd_parser[i].p);
}
}
return -1;
}
static int fgetsesc(char *oline, size_t size, char *(*getl)(void *p, char *s, int size), void *fp)
{
int nr = 0;
char line[4096];
*oline = 0;
*line = 0;
while (getl(fp, line, sizeof(line))) {
int i;
nr ++;
i = strcspn(line, "\n\r");
if (!i || !line[i])
break;
line[i] = 0;
if (line[i - 1] == '\\') {
line[i - 1] = 0;
strncat(oline, line, size);
line[0] = 0;
size -= strlen(line);
if (size <= 0)
return nr;
} else {
break;
}
}
strncat(oline, line, size);
return nr;
}
char *find_in_esc(const char *l, const char *s)
{
int esc = 0;
for (; *l; l++) {
if (esc) {
esc = 0;
continue;
}
l += strcspn(l, s);
if (*l == '\\') {
esc = 1;
continue;
}
if (!esc)
return (char*)l;
}
return NULL;
}
static void comments_zap(char *p)
{
char *l = find_in_esc(p, "\\;\n");
if (l)
*l = 0;
}
int parse_all(void *fp, char *(*getl)(void *p, char *s, int size), const char *path, struct parser *cmd_parser)
{
int nr;
int rc = 0;
int line_nr = 1;
char line[4096];
if (!fp)
return -1;
while ((nr = fgetsesc(line, sizeof(line), getl, fp))) {
char *p = line;
char *val;
int len;
line_nr += nr;
p += strspn(p, " \t");
if (*p == ';')
continue;
len = strcspn(p, "=");
if (p[len] != '=') /* just ignore it */
continue;
p[len] = 0;
val = p + len + 1;
len = strcspn(p, " \t");
p[len] = 0;
// printf("%s\n", p);
val += strspn(val, " \t");
comments_zap(val);
// val[strcspn(val, ";\n")] = 0;
if (process_cmd(p, val, cmd_parser)) {
rc = -1;
fprintf(stderr, "Can't process cmd '%s' on line %d in '%s': %s\n", p, line_nr - nr, path, strerror(errno));
}
}
return rc;
}
static char *file_gets(void *fd, char *s, int size)
{
return fgets(s, size, (FILE *)fd);
}
static char *idff_gets(void *fd, char *s, int size)
{
return idf_gets((idff_t)fd, s, size);
}
int parse_ini(const char *path, struct parser *cmd_parser)
{
int rc = 0;
FILE *fp;
fp = fopen(path, "rb");
if (!fp)
return -1;
rc = parse_all(fp, file_gets, path, cmd_parser);
fclose(fp);
return rc;
}
int parse_idff(idff_t idff, const char *path, struct parser *cmd_parser)
{
if (!idff)
return -1;
return parse_all(idff, idff_gets, path, cmd_parser);
}
int parse_string(const char *v, void *data)
{
char **p = ((char **)data);
if (*p)
free(*p);
*p = strdup(v);
if (!*p)
return -1;
return 0;
}
char *encode_esc_string(const char *v)
{
char *r, *p;
if (!v)
return NULL;
p = r = malloc((strlen(v)*2) + 1);
if (!r)
return NULL;
while (*v) {
switch (*v) {
case ' ':
*p ++ = '\\';
*p ++ = ' ';
break;
case '"':
*p ++ = '\\';
*p ++ = '"';
break;
case '\'':
*p ++ = '\\';
*p ++ = '\'';
break;
case '\\':
*p ++ = '\\';
*p ++ = '\\';
break;
case '\n':
*p ++ ='\\';
*p ++ ='\n';
break;
default:
*p ++ = *v;
}
v ++;
}
*p ++ = 0;
return r;
}
int parse_esc_string(const char *v, void *data)
{
int esc = 0;
char *ptr;
char **p = ((char **)data);
if (*p)
free(*p);
*p = strdup(v);
if (!*p)
return -1;
for (ptr = *p; *v; v ++) {
if (esc) {
switch (*v) {
case 'n':
*ptr = '\n';
break;
case '$':
*ptr = '$';
break;
case '\\':
*ptr = '\\';
break;
case ';':
*ptr = ';';
break;
case 'r':
*ptr = '\n';
break;
default:
*ptr = *v;
break;
}
esc = 0;
ptr ++;
continue;
} else if (*v != '\\') {
*ptr = *v;
ptr ++;
continue;
} else
esc = 1;
}
*ptr = 0;
return 0;
}
int parse_int(const char *v, void *data)
{
int *i = (int *)data;
char *eptr = NULL;
*i = strtol(v, &eptr, 0);
if (!eptr || *eptr)
return -1;
return 0;
}
int parse_float(const char *v, void *data)
{
float *f = (float *)data;
if (sscanf(v, "%f", f) != 1)
return -1;
return 0;
}
static int parse_path(const char *v, void *data)
{
char **p = ((char **)data);
if (*p)
free(*p);
if (!v[0]) {
*p = strdup("");
return (*p)?0:-1;
}
*p = strdup(v);
if (!*p)
return -1;
*p = sdl_path(*p);
return 0;
}
extern int theme_relative; /* hack, theme layer here :( */
int parse_full_path(const char *v, void *data)
{
char cwd[PATH_MAX];
char **p = ((char **)data);
if (theme_relative ||
!strncmp(v, "blank:", 6) ||
!strncmp(v, "box:", 4) ||
!strncmp(v, "spr:", 4)) /* hack for special files*/
return parse_path(v, data);
if (*p)
free(*p);
if (!v[0]) {
*p = strdup("");
return (*p)?0:-1;
}
getdir(cwd, sizeof(cwd));
*p = malloc(strlen(v) + strlen(cwd) + 2);
if (!*p)
return -1;
strcpy(*p, cwd);
strcat(*p,"/");
strcat(*p, v);
*p = sdl_path(*p);
return 0;
}
void unix_path(char *path)
{
char *p = path;
if (!path)
return;
while (*p) { /* bad bad Windows!!! */
if (*p == '\\')
*p = '/';
p ++;
}
return;
}
static char *lookup_tag_all(const char *tag, const char *comm, char *(*getl)(void *p, char *s, int size), void *fp)
{
int brk = 0;
char *l; char line[1024];
while ((l = getl(fp, line, sizeof(line))) && !brk) {
l = parse_tag(l, tag, comm, &brk);
if (l)
return l;
}
return NULL;
}
char *lookup_tag(const char *fname, const char *tag, const char *comm)
{
char *l;
FILE *fd = fopen(fname, "rb");
if (!fd)
return NULL;
l = lookup_tag_all(tag, comm, file_gets, fd);
fclose(fd);
return l;
}
char *lookup_lang_tag(const char *fname, const char *tag, const char *comm)
{
char lang_tag[1024];
char *l;
snprintf(lang_tag, sizeof(lang_tag), "%s(%s)", tag, opt_lang);
l = lookup_tag(fname, lang_tag, comm);
if (!l)
l = lookup_tag(fname, tag, comm);
return l;
}
char *lookup_lang_tag_idf(idff_t idf, const char *tag, const char *comm)
{
char lang_tag[1024];
char *l;
if (!idf)
return NULL;
snprintf(lang_tag, sizeof(lang_tag), "%s(%s)", tag, opt_lang);
l = lookup_tag_all(lang_tag, comm, idff_gets, idf);
if (!l) {
idf_seek(idf, 0, SEEK_SET);
l = lookup_tag_all(tag, comm, idff_gets, idf);
}
return l;
}
char *parse_tag(char *line, const char *tag, const char *comm, int *brk)
{
char *l = line;
char *ns = NULL;
char ftag[1024];
snprintf(ftag, sizeof(ftag), "$%s:", tag);
l += strspn(l, " \t");
if (strncmp(l, comm, strlen(comm))) { /* non coment block */
*brk = 1;
return NULL;
}
l += strlen(comm); l += strspn(l, " \t");
if (strncmp(l, ftag, strlen(ftag)))
return NULL;
l += strlen(ftag);
l += strspn(l, " \t");
ns = l;
l = find_in_esc(l, "\\$");
if (l)
*l = 0;
l = ns; ns = NULL;
if (parse_esc_string(l, &ns))
return NULL;
ns[strcspn(ns, "\n\r")] = 0;
return ns;
}
#ifdef _HAVE_ICONV
#define CHAR_MAX_LEN 4
char *decode(iconv_t hiconv, const char *s)
{
size_t s_size, chs_size, outsz, insz;
char *inbuf, *outbuf, *chs_buf;
if (!s || hiconv == (iconv_t)(-1))
return NULL;
s_size = strlen(s) + 1;
chs_size = s_size * CHAR_MAX_LEN;
if ((chs_buf = malloc(chs_size + CHAR_MAX_LEN))==NULL)
goto exitf;
outsz = chs_size;
outbuf = chs_buf;
insz = s_size;
inbuf = (char*)s;
while (insz) {
if (iconv(hiconv, &inbuf, &insz, &outbuf, &outsz)
== (size_t)(-1))
goto exitf;
}
*outbuf++ = 0;
return chs_buf;
exitf:
if(chs_buf)
free(chs_buf);
return NULL;
}
#endif
int remove_dir(const char *path)
{
DIR *d;
struct dirent *de;
if (!path)
return 0;
d = opendir(path);
if (!d) {
if (!access(path, F_OK)) {
unlink(path);
}
return -1;
}
while ((de = readdir(d))) {
char *p;
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
p = getfilepath(path, de->d_name);
if (p) {
remove_dir(p);
free(p);
}
}
closedir(d);
rmdir(path);
return 0;
}