162 lines
2.8 KiB
C
162 lines
2.8 KiB
C
|
#include <string.h>
|
||
|
#include "xmlmime.h"
|
||
|
|
||
|
static
|
||
|
const char *getTok(const char **pp)
|
||
|
{
|
||
|
/* inComment means one level of nesting; inComment+1 means two levels etc */
|
||
|
enum { inAtom, inString, init, inComment };
|
||
|
int state = init;
|
||
|
const char *tokStart = 0;
|
||
|
for (;;) {
|
||
|
switch (**pp) {
|
||
|
case '\0':
|
||
|
if (state == inAtom)
|
||
|
return tokStart;
|
||
|
return 0;
|
||
|
case ' ':
|
||
|
case '\r':
|
||
|
case '\t':
|
||
|
case '\n':
|
||
|
if (state == inAtom)
|
||
|
return tokStart;
|
||
|
break;
|
||
|
case '(':
|
||
|
if (state == inAtom)
|
||
|
return tokStart;
|
||
|
if (state != inString)
|
||
|
state++;
|
||
|
break;
|
||
|
case ')':
|
||
|
if (state > init)
|
||
|
--state;
|
||
|
else if (state != inString)
|
||
|
return 0;
|
||
|
break;
|
||
|
case ';':
|
||
|
case '/':
|
||
|
case '=':
|
||
|
if (state == inAtom)
|
||
|
return tokStart;
|
||
|
if (state == init)
|
||
|
return (*pp)++;
|
||
|
break;
|
||
|
case '\\':
|
||
|
++*pp;
|
||
|
if (**pp == '\0')
|
||
|
return 0;
|
||
|
break;
|
||
|
case '"':
|
||
|
switch (state) {
|
||
|
case inString:
|
||
|
++*pp;
|
||
|
return tokStart;
|
||
|
case inAtom:
|
||
|
return tokStart;
|
||
|
case init:
|
||
|
tokStart = *pp;
|
||
|
state = inString;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
if (state == init) {
|
||
|
tokStart = *pp;
|
||
|
state = inAtom;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
++*pp;
|
||
|
}
|
||
|
/* not reached */
|
||
|
}
|
||
|
|
||
|
/* key must be lowercase ASCII */
|
||
|
|
||
|
static
|
||
|
int matchkey(const char *start, const char *end, const char *key)
|
||
|
{
|
||
|
if (!start)
|
||
|
return 0;
|
||
|
for (; start != end; start++, key++)
|
||
|
if (*start != *key && *start != 'A' + (*key - 'a'))
|
||
|
return 0;
|
||
|
return *key == '\0';
|
||
|
}
|
||
|
|
||
|
void getXMLCharset(const char *buf, char *charset)
|
||
|
{
|
||
|
const char *next, *p;
|
||
|
|
||
|
charset[0] = '\0';
|
||
|
next = buf;
|
||
|
p = getTok(&next);
|
||
|
if (matchkey(p, next, "text"))
|
||
|
strcpy(charset, "us-ascii");
|
||
|
else if (!matchkey(p, next, "application"))
|
||
|
return;
|
||
|
p = getTok(&next);
|
||
|
if (!p || *p != '/')
|
||
|
return;
|
||
|
p = getTok(&next);
|
||
|
#if 0
|
||
|
if (!matchkey(p, next, "xml") && charset[0] == '\0')
|
||
|
return;
|
||
|
#endif
|
||
|
p = getTok(&next);
|
||
|
while (p) {
|
||
|
if (*p == ';') {
|
||
|
p = getTok(&next);
|
||
|
if (matchkey(p, next, "charset")) {
|
||
|
p = getTok(&next);
|
||
|
if (p && *p == '=') {
|
||
|
p = getTok(&next);
|
||
|
if (p) {
|
||
|
char *s = charset;
|
||
|
if (*p == '"') {
|
||
|
while (++p != next - 1) {
|
||
|
if (*p == '\\')
|
||
|
++p;
|
||
|
if (s == charset + CHARSET_MAX - 1) {
|
||
|
charset[0] = '\0';
|
||
|
break;
|
||
|
}
|
||
|
*s++ = *p;
|
||
|
}
|
||
|
*s++ = '\0';
|
||
|
}
|
||
|
else {
|
||
|
if (next - p > CHARSET_MAX - 1)
|
||
|
break;
|
||
|
while (p != next)
|
||
|
*s++ = *p++;
|
||
|
*s = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
p = getTok(&next);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef TEST
|
||
|
|
||
|
#include <stdio.h>
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
char buf[CHARSET_MAX];
|
||
|
if (argc <= 1)
|
||
|
return 1;
|
||
|
printf("%s\n", argv[1]);
|
||
|
getXMLCharset(argv[1], buf);
|
||
|
printf("charset=\"%s\"\n", buf);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#endif /* TEST */
|