用有限状态机实现INI和XML的转换
写了个INI转化为XML的小程序,利用有限状态机实现的。很简单,把INI文件中的内容一行一行地读取进一个buffer里面,然后对这个buffer进行解析,最后转化为XML的格式再写进XML文件里面。
代码
测试的一个INI文件为:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 512
#define TRUE 1
#define FALSE 0
typedef enum _state
{
STATE_NONE = 0,
STATE_COMMENT,
STATE_SECTION,
STATE_SECTION_END,
STATE_KEY,
} stateType;
char gSection[BUFFER_SIZE];
static int gSectionIsEmpty(void)
{
for (int index = 0; index < BUFFER_SIZE; ++index)
{
if (gSection[index] != 0x00)
{
return FALSE;
}
}
return TRUE;
}
static stateType getStateType(const char ch)
{
stateType state = STATE_NONE;
if (ch == ';')
state = STATE_COMMENT;
else if (ch == '[')
state = STATE_SECTION;
else if (ch == '\0' || ch == '\n' || ch == ' ' || ch == '\t')
state = STATE_SECTION_END;
else
state = STATE_KEY;
return state;
}
#define KEY_LEN 128
#define VALUE_LEN 256
static void parse_key_and_value(const char *line, char *buffer)
{
char key[KEY_LEN] = {0};
char value[VALUE_LEN] = {0};
for (int index = 0; *line != '\0'; ++line)
{
if (*line != '\t' && *line != ' ' && *line != '=')
{
key[index++] = *line;
}
else
{
key[index] = '\0';
break;
}
}
for (; *line != '\0'; ++line)
{
if (*line == '\t' || *line == ' ' || *line == '=')
continue;
else
break;
}
for (int index = 0; *line != '\0'; ++line)
{
if (*line != '\t' && *line != ' ' && *line != '=')
{
value[index++] = *line;
}
else
{
value[index] = '\0';
break;
}
}
sprintf(buffer, "\t<%s>%s</%s>\n", key, value, key);
return;
}
static void iniParse(const char *line, FILE *fpXML)
{
char writeBuffer[BUFFER_SIZE] = {0};
stateType state = getStateType(*line);
switch (state)
{
case STATE_COMMENT:
line++;
sprintf(writeBuffer, "<!-- %s -->\n", line);
fwrite(writeBuffer, strlen(writeBuffer), 1, fpXML);
break;
case STATE_SECTION:
line++;
for (int index = 0; index < BUFFER_SIZE && *line != '\0'; ++line)
{
if (*line != ']')
{
gSection[index++] = *line;
}
else
{
gSection[index] = '\0';
sprintf(writeBuffer, "<%s>\n", gSection);
fwrite(writeBuffer, strlen(writeBuffer), 1, fpXML);
}
}
break;
case STATE_SECTION_END:
if (gSectionIsEmpty() == FALSE)
{
sprintf(writeBuffer, "</%s>\n\n", gSection);
fwrite(writeBuffer, strlen(writeBuffer), 1, fpXML);
memset(gSection, 0x00, sizeof(gSection));
}
break;
case STATE_KEY:
parse_key_and_value(line, writeBuffer);
fwrite(writeBuffer, strlen(writeBuffer), 1, fpXML);
break;
default:
break;
}
return;
}
static void createXML(const char *iniName, char *xml)
{
for (int index = 0; index < 20; ++index)
{
if (iniName[index] != '.' && iniName[index] != '\0')
{
xml[index] = iniName[index];
}
else
{
strcat(xml, ".xml");
break;
}
}
return;
}
static void writeTheLastSectionEnd(FILE *fpXML)
{
char writeBuffer[BUFFER_SIZE] = {0};
sprintf(writeBuffer, "</%s>\n\n", gSection);
fwrite(writeBuffer, strlen(writeBuffer), 1, fpXML);
return;
}
static void iniToxml(const char *iniName)
{
char xmlName[20] = {0};
createXML(iniName, xmlName);
FILE *fpINI = fopen(iniName, "r");
FILE *fpXML = fopen(xmlName, "a+");
if (fpINI == NULL || fpXML == NULL)
{
fprintf(stderr, "open ini/xml file failed.\n");
return;
}
char line[BUFFER_SIZE] = {0};
while (fgets(line, BUFFER_SIZE, fpINI))
{
line[strlen(line) - 1] = '\0';
iniParse(line, fpXML);
memset(line, 0x00, sizeof(line) );
}
writeTheLastSectionEnd(fpXML);
fclose(fpINI);
fclose(fpXML);
return;
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
fprintf(stdout, "usage: ./iniToxml <*.ini> (<*.ini>, ...)");
return -1;
}
for (int i = 1; i < argc; ++i)
{
iniToxml(argv[i]);
}
return 0;
}
;Configuration of http
[http]
domain=www.mysite.com
port=8080
cgihome=/cgi-bin
;Configuration of db
[database]
server = mysql
user = myname
password = toopendatabase
代码
<!-- Configuration of http -->
<http>
<domain>www.mysite.com</domain>
<port>8080</port>
<cgihome>/cgi-bin</cgihome>
</http>
<!-- Configuration of db -->
<database>
<server>mysql</server>
<user>myname</user>
<password>toopendatabase</password>
</database>
END