200 lines
4.8 KiB
C
200 lines
4.8 KiB
C
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <string.h>
|
||
|
#include "tag_table.h"
|
||
|
|
||
|
#define PUTCH(out, c) fprintf(out, "%c", c)
|
||
|
extern struct tag_info legal_tags[];
|
||
|
/* dump "count" args to output replacing '|' with ',' except after the last count.
|
||
|
* return the amount of chars read. (start+return will be after the last | )
|
||
|
*/
|
||
|
int dump_arg(FILE* out, const char* start, int count, bool close)
|
||
|
{
|
||
|
int l = 0;
|
||
|
while (count)
|
||
|
{
|
||
|
if (start[l] == '|')
|
||
|
{
|
||
|
if (count > 1)
|
||
|
{
|
||
|
printf(",");
|
||
|
} else if (close) {
|
||
|
printf(")");
|
||
|
}
|
||
|
count--;
|
||
|
} else {
|
||
|
PUTCH(out, start[l]);
|
||
|
}
|
||
|
l++;
|
||
|
}
|
||
|
return l;
|
||
|
}
|
||
|
#define MATCH(s) (!strcmp(tag->name, s))
|
||
|
int parse_tag(FILE* out, const char* start)
|
||
|
{
|
||
|
struct tag_info *tag;
|
||
|
int len = 0;
|
||
|
for(tag = legal_tags;
|
||
|
tag->name[0] && strncmp(start, tag->name, strlen(tag->name)) != 0;
|
||
|
tag++) ;
|
||
|
if (!tag->name[0])
|
||
|
return -1;
|
||
|
if (tag->params[0] == '\0')
|
||
|
{
|
||
|
fprintf(out, "%s", tag->name);
|
||
|
return strlen(tag->name);
|
||
|
}
|
||
|
fprintf(out, "%s", tag->name);
|
||
|
len += strlen(tag->name);
|
||
|
start += len;
|
||
|
/* handle individual tags which accept params */
|
||
|
if (MATCH("bl") || MATCH("pb") || MATCH("pv"))
|
||
|
{
|
||
|
start++; len++;
|
||
|
if (*start == '|')
|
||
|
{
|
||
|
PUTCH(out, '(');
|
||
|
/* TODO: need to verify that we are actually using the long form... */
|
||
|
len += dump_arg(out, start, 5, true);
|
||
|
}
|
||
|
}
|
||
|
else if (MATCH("d") || MATCH("D") || MATCH("mv") || MATCH("pS") || MATCH("pE") || MATCH("t") || MATCH("Tl"))
|
||
|
{
|
||
|
char temp[8] = {'\0'};
|
||
|
int i = 0;
|
||
|
/* tags which maybe have a number after them */
|
||
|
while ((*start >= '0' && *start <= '9') || *start == '.')
|
||
|
{
|
||
|
temp[i++] = *start++;
|
||
|
}
|
||
|
if (i!= 0)
|
||
|
{
|
||
|
fprintf(out, "(%s)", temp);
|
||
|
len += i;
|
||
|
}
|
||
|
}
|
||
|
else if (MATCH("xl"))
|
||
|
{
|
||
|
PUTCH(out, '(');
|
||
|
len += 1+dump_arg(out, start+1, 5, true);
|
||
|
}
|
||
|
else if (MATCH("xd"))
|
||
|
{
|
||
|
/* NOTE: almost certainly needs work */
|
||
|
PUTCH(out, '(');
|
||
|
PUTCH(out, *start++); len++;
|
||
|
if ((*start >= 'a' && *start <= 'z') ||
|
||
|
(*start >= 'A' && *start <= 'Z'))
|
||
|
PUTCH(out, *start); len++;
|
||
|
PUTCH(out, ')');
|
||
|
}
|
||
|
else if (MATCH("x"))
|
||
|
{
|
||
|
PUTCH(out, '(');
|
||
|
len += 1+dump_arg(out, start+1, 4, true);
|
||
|
}
|
||
|
else if (MATCH("Fl"))
|
||
|
{
|
||
|
PUTCH(out, '(');
|
||
|
len += 1+dump_arg(out, start+1, 2, true);
|
||
|
}
|
||
|
else if (MATCH("Cl"))
|
||
|
{
|
||
|
PUTCH(out, '(');
|
||
|
len += 1+dump_arg(out, start+1, 4, true);
|
||
|
}
|
||
|
else if (MATCH("Vd") || MATCH("VI"))
|
||
|
{
|
||
|
PUTCH(out, '(');
|
||
|
PUTCH(out, *start); len++;
|
||
|
PUTCH(out, ')');
|
||
|
}
|
||
|
else if (MATCH("Vp"))
|
||
|
{
|
||
|
/* NOTE: almost certainly needs work */
|
||
|
PUTCH(out, '(');
|
||
|
len += 1+dump_arg(out, start+1, 3, true);
|
||
|
}
|
||
|
else if (MATCH("Vl") || MATCH("Vi"))
|
||
|
{
|
||
|
PUTCH(out, '(');
|
||
|
len += 1+dump_arg(out, start+1, 8, true);
|
||
|
}
|
||
|
else if (MATCH("V"))
|
||
|
{
|
||
|
PUTCH(out, '(');
|
||
|
len += 1+dump_arg(out, start+1, 7, true);
|
||
|
}
|
||
|
else if (MATCH("X"))
|
||
|
{
|
||
|
if (*start+1 == 'd')
|
||
|
{
|
||
|
fprintf(out, "(d)");
|
||
|
len ++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PUTCH(out, '(');
|
||
|
len += 1+dump_arg(out, start+1, 1, true);
|
||
|
}
|
||
|
}
|
||
|
else if (MATCH("St") || MATCH("Sx"))
|
||
|
{
|
||
|
PUTCH(out, '(');
|
||
|
len += 1+dump_arg(out, start+1, 1, true);
|
||
|
}
|
||
|
|
||
|
else if (MATCH("T"))
|
||
|
{
|
||
|
PUTCH(out, '(');
|
||
|
len += 1+dump_arg(out, start+1, 5, true);
|
||
|
}
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
void parse_text(const char* in, FILE* out)
|
||
|
{
|
||
|
const char* end = in+strlen(in);
|
||
|
top:
|
||
|
while (in < end && *in)
|
||
|
{
|
||
|
if (*in == '%')
|
||
|
{
|
||
|
PUTCH(out, *in++);
|
||
|
switch(*in)
|
||
|
{
|
||
|
|
||
|
case '%':
|
||
|
case '<':
|
||
|
case '|':
|
||
|
case '>':
|
||
|
case ';':
|
||
|
case '#':
|
||
|
PUTCH(out, *in++);
|
||
|
goto top;
|
||
|
break;
|
||
|
case '?':
|
||
|
PUTCH(out, *in++);
|
||
|
break;
|
||
|
}
|
||
|
in += parse_tag(out, in);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PUTCH(out, *in++);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int main(int argc, char* argv[])
|
||
|
{
|
||
|
parse_text("%s%?it<%?in<%in. |>%it|%fn>\n"
|
||
|
"%s%?ia<%ia|%?d2<%d2|(root)>>\n"
|
||
|
"%s%?id<%id|%?d1<%d1|(root)>> %?iy<(%iy)|>\n\n"
|
||
|
"%al%pc/%pt%ar[%pp:%pe]\n"
|
||
|
"%fbkBit %?fv<avg|> %?iv<(id3v%iv)|(no id3)>\n"
|
||
|
"%pb\n%pm\n", stdout);
|
||
|
return 0;
|
||
|
}
|