用有限状态机实现INI和XML的转换

  写了个INI转化为XML的小程序,利用有限状态机实现的。很简单,把INI文件中的内容一行一行地读取进一个buffer里面,然后对这个buffer进行解析,最后转化为XML的格式再写进XML文件里面。

代码
#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;
}
测试的一个INI文件为:

;Configuration of http
[http]
domain
=www.mysite.com
port
=8080
cgihome
=/cgi-bin

;Configuration of db
[database]
server
= mysql
user
= myname
password
= toopendatabase
转化后的XML文件为:

代码
<!-- 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

posted @ 2010-08-09 21:40  Linjian  阅读(940)  评论(0编辑  收藏  举报