#include "cgi.h"
static void cgi_copy(FILE *out, FILE *in, int element, char term);
static void cgi_puts(const char *s, FILE *out);
void
cgiCopyTemplateFile(FILE *out,
const char *tmpl)
{
FILE *in;
if ((in = fopen(tmpl, "r")) == NULL)
return;
cgi_copy(out, in, 0, 0);
fclose(in);
}
void
cgiCopyTemplateLang(FILE *out,
const char *directory,
const char *tmpl,
const char *lang)
{
int i;
char filename[1024],
locale[16];
FILE *in;
if (lang != NULL)
{
for (i = 0; lang[i] && i < 15; i ++)
if (isalnum(lang[i] & 255))
locale[i] = tolower(lang[i]);
else
locale[i] = '_';
locale[i] = '\0';
}
else
locale[0] = '\0';
snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
if (access(filename, 0))
{
locale[2] = '\0';
snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
if (access(filename, 0))
snprintf(filename, sizeof(filename), "%s/%s", directory, tmpl);
}
if ((in = fopen(filename, "r")) == NULL)
return;
cgi_copy(out, in, 0, 0);
fclose(in);
}
static void
cgi_copy(FILE *out,
FILE *in,
int element,
char term)
{
int ch;
char op;
char name[255],
*nameptr,
innername[255],
*innerptr,
*s;
const char *value;
const char *innerval;
const char *outptr;
char outval[1024],
compare[1024];
int result;
while ((ch = getc(in)) != EOF)
if (ch == term)
break;
else if (ch == '{')
{
for (s = name; (ch = getc(in)) != EOF;)
if (strchr("}]<>=! \t\n", ch))
break;
else if (s > name && ch == '?')
break;
else if (s < (name + sizeof(name) - 1))
*s++ = ch;
*s = '\0';
if (s == name && isspace(ch & 255))
{
if (out)
{
putc('{', out);
putc(ch, out);
}
continue;
}
if (name[0] == '?')
{
if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1] & 255))
{
*nameptr++ = '\0';
if ((value = cgiGetArray(name + 1, atoi(nameptr) - 1)) != NULL)
outptr = value;
else
{
outval[0] = '\0';
outptr = outval;
}
}
else if ((value = cgiGetArray(name + 1, element)) != NULL)
outptr = value;
else
{
outval[0] = '\0';
outptr = outval;
}
}
else if (name[0] == '#')
{
if (name[1])
sprintf(outval, "%d", cgiGetSize(name + 1));
else
sprintf(outval, "%d", element + 1);
outptr = outval;
}
else if (name[0] == '[')
{
int i;
long pos;
int count;
if (isdigit(name[1] & 255))
count = atoi(name + 1);
else
count = cgiGetSize(name + 1);
pos = ftell(in);
if (count > 0)
{
for (i = 0; i < count; i ++)
{
fseek(in, pos, SEEK_SET);
cgi_copy(out, in, i, '}');
}
}
else
cgi_copy(NULL, in, 0, '}');
continue;
}
else
{
if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1] & 255))
{
*nameptr++ = '\0';
if ((value = cgiGetArray(name, atoi(nameptr) - 1)) == NULL)
{
snprintf(outval, sizeof(outval), "{%s}", name);
outptr = outval;
}
else
outptr = value;
}
else if ((value = cgiGetArray(name, element)) == NULL)
{
snprintf(outval, sizeof(outval), "{%s}", name);
outptr = outval;
}
else
outptr = value;
}
if (ch == '}')
{
if (out)
cgi_puts(outptr, out);
continue;
}
if (ch == '?')
{
result = cgiGetArray(name, element) != NULL && outptr[0];
}
else
{
op = ch;
for (s = compare; (ch = getc(in)) != EOF;)
if (ch == '?')
break;
else if (s >= (compare + sizeof(compare) - 1))
continue;
else if (ch == '#')
{
sprintf(s, "%d", element + 1);
s += strlen(s);
}
else if (ch == '{')
{
innerptr = innername;
while ((ch = getc(in)) != EOF && ch != '}')
if (innerptr < (innername + sizeof(innername) - 1))
*innerptr++ = ch;
*innerptr = '\0';
if (innername[0] == '#')
sprintf(s, "%d", cgiGetSize(innername + 1));
else if ((innerptr = strrchr(innername, '-')) != NULL &&
isdigit(innerptr[1] & 255))
{
*innerptr++ = '\0';
if ((innerval = cgiGetArray(innername, atoi(innerptr) - 1)) == NULL)
*s = '\0';
else
strlcpy(s, innerval, sizeof(compare) - (s - compare));
}
else if (innername[0] == '?')
{
if ((innerval = cgiGetArray(innername + 1, element)) == NULL)
*s = '\0';
else
strlcpy(s, innerval, sizeof(compare) - (s - compare));
}
else if ((innerval = cgiGetArray(innername, element)) == NULL)
snprintf(s, sizeof(compare) - (s - compare), "{%s}", innername);
else
strlcpy(s, innerval, sizeof(compare) - (s - compare));
s += strlen(s);
}
else if (ch == '\\')
*s++ = getc(in);
else
*s++ = ch;
*s = '\0';
if (ch != '?')
return;
switch (op)
{
case '<' :
result = strcasecmp(outptr, compare) < 0;
break;
case '>' :
result = strcasecmp(outptr, compare) > 0;
break;
case '=' :
result = strcasecmp(outptr, compare) == 0;
break;
case '!' :
result = strcasecmp(outptr, compare) != 0;
break;
default :
result = 1;
break;
}
}
if (result)
{
cgi_copy(out, in, element, ':');
cgi_copy(NULL, in, element, '}');
}
else
{
cgi_copy(NULL, in, element, ':');
cgi_copy(out, in, element, '}');
}
}
else if (ch == '\\')
{
if (out)
putc(getc(in), out);
else
getc(in);
}
else if (out)
putc(ch, out);
if (out)
fflush(out);
}
static void
cgi_puts(const char *s,
FILE *out)
{
while (*s)
{
if (s[0] == '<')
fputs("<", out);
else if (s[0] == '>')
fputs(">", out);
else if (*s == '\"')
fputs(""", out);
else if (s[0] == '&')
fputs("&", out);
else
putc(*s, out);
s ++;
}
}