| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id: tag_table.c 26346 2010-05-28 02:30:27Z jdgordon $ |
| * |
| * Copyright (C) 2010 Jonathan Gordon |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdbool.h> |
| #include <string.h> |
| #include <ctype.h> |
| #include "tag_table.h" |
| |
| #define PUTCH(out, c) fprintf(out, "%c", c) |
| extern struct tag_info legal_tags[]; |
| |
| char images_with_subimages[100]; |
| int image_count = 0; |
| |
| /** Command line setting **/ |
| bool is_mono_display = false; |
| bool use_new_vp_tags = true; |
| |
| |
| /* 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) |
| { |
| PUTCH(out, ','); |
| } else if (close) { |
| PUTCH(out, ')'); |
| } |
| count--; |
| } else { |
| if (find_escape_character(start[l])) |
| { |
| PUTCH(out, '%'); |
| } |
| PUTCH(out, start[l]); |
| } |
| l++; |
| } |
| return l; |
| } |
| |
| int dump_viewport_tags(FILE* out, const char* start) |
| { |
| int len = 0; |
| if (is_mono_display) |
| { |
| return dump_arg(out, start, 5, true); |
| } |
| else |
| { |
| int arg_count = use_new_vp_tags?5:7; |
| len += dump_arg(out, start, arg_count, true); |
| if (!use_new_vp_tags) |
| return len; |
| if (start[len] != '-') |
| { |
| fprintf(out, "%%Vf("); |
| len += dump_arg(out, start+len, 1, true); |
| } |
| else |
| { |
| while (start[len++] != '|'); |
| } |
| if (start[len] != '-') |
| { |
| fprintf(out, "%%Vb("); |
| len += dump_arg(out, start+len, 1, true); |
| } |
| else |
| { |
| while (start[len++] != '|'); |
| } |
| } |
| return len; |
| } |
| |
| #define MATCH(s) (!strcmp(tag->name, s)) |
| int parse_tag(FILE* out, const char* start, bool in_conditional) |
| { |
| 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")) && !in_conditional) |
| { |
| if (*start == '|') |
| { |
| len++; 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")) |
| { |
| char label = start[1]; |
| PUTCH(out, '('); |
| int read = 1+dump_arg(out, start+1, 4, false); |
| len += read; |
| start += read; |
| if (*start>= '0' && *start <= '9') |
| { |
| images_with_subimages[image_count++] = label; |
| PUTCH(out, ','); |
| len += dump_arg(out, start, 1, false); |
| } |
| PUTCH(out, ')'); |
| } |
| else if (MATCH("xd")) |
| { |
| char label = start[0]; |
| int i=0; |
| while (i<image_count) |
| { |
| if (images_with_subimages[i] == label) |
| break; |
| i++; |
| } |
| PUTCH(out, '('); |
| PUTCH(out, *start++); len++; |
| if (i<image_count && |
| ((*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")) |
| { |
| int read; |
| char xalign = '\0', yalign = '\0'; |
| PUTCH(out, '('); |
| read = 1+dump_arg(out, start+1, 2, false); |
| len += read; |
| start += read; |
| switch (tolower(*start)) |
| { |
| case 'l': |
| case 'c': |
| case 'r': |
| case '+': |
| case '-': |
| xalign = *start; |
| len++; |
| start++; |
| break; |
| case 'd': |
| case 'D': |
| case 'i': |
| case 'I': |
| case 's': |
| case 'S': |
| len++; |
| start++; |
| break; |
| } |
| PUTCH(out,','); |
| read = dump_arg(out, start, 1, false); |
| len += read; |
| start += read; |
| switch (tolower(*start)) |
| { |
| case 't': |
| case 'c': |
| case 'b': |
| case '+': |
| case '-': |
| yalign = *start; |
| len++; |
| start++; |
| break; |
| case 'd': |
| case 'D': |
| case 'i': |
| case 'I': |
| case 's': |
| case 'S': |
| len++; |
| start++; |
| break; |
| } |
| PUTCH(out,','); |
| read = dump_arg(out, start, 1, false); |
| if (xalign) |
| { |
| if (xalign == '-') |
| xalign = 'l'; |
| if (xalign == '+') |
| xalign = 'r'; |
| fprintf(out, ",%c", xalign); |
| } |
| if (yalign) |
| { |
| if (yalign == '-') |
| yalign = 't'; |
| if (yalign == '+') |
| yalign = 'b'; |
| fprintf(out, ",%s%c", xalign?"":"-,", yalign); |
| } |
| PUTCH(out, ')'); |
| len += read; |
| } |
| 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")) |
| { |
| int read; |
| PUTCH(out, '('); |
| read = 1+dump_arg(out, start+1, 1, false); |
| PUTCH(out, ','); |
| len += read + dump_viewport_tags(out, start+read); |
| } |
| else if (MATCH("V")) |
| { |
| PUTCH(out, '('); |
| len += 1+dump_viewport_tags(out, start+1); |
| } |
| 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); |
| int level = 0; |
| int len; |
| top: |
| while (in < end && *in) |
| { |
| if (*in == '%') |
| { |
| PUTCH(out, *in++); |
| switch(*in) |
| { |
| |
| case '%': |
| case '<': |
| case '|': |
| case '>': |
| case ';': |
| case '#': |
| case ')': |
| case '(': |
| case ',': |
| PUTCH(out, *in++); |
| goto top; |
| break; |
| case '?': |
| PUTCH(out, *in++); |
| break; |
| } |
| len = parse_tag(out, in, level>0); |
| if (len < 0) |
| { |
| PUTCH(out, *in++); |
| } |
| else |
| { |
| in += len; |
| } |
| } |
| else if (*in == '<') |
| { |
| level++; |
| PUTCH(out, *in++); |
| } |
| else if (*in == '>') |
| { |
| level--; |
| PUTCH(out, *in++); |
| } |
| else if (*in == '|') |
| { |
| if (level == 0) |
| { |
| PUTCH(out, '%'); |
| } |
| PUTCH(out, *in++); |
| } |
| else if (*in == '#') |
| { |
| while (*in && *in != '\n') |
| { |
| PUTCH(out, *in++); |
| } |
| } |
| else |
| { |
| if (find_escape_character(*in)) |
| { |
| PUTCH(out, '%'); |
| } |
| PUTCH(out, *in++); |
| } |
| } |
| } |
| |
| int main(int argc, char* argv[]) |
| { |
| char buffer[10*1024], temp[512]; |
| FILE *in, *out = stdout; |
| int filearg = 1, i=0; |
| if( (argc < 2) || |
| strcmp(argv[1],"-h") == 0 || |
| strcmp(argv[1],"--help") == 0 ) |
| { |
| printf("Usage: %s [OPTIONS] infile [outfile]\n", argv[0]); |
| printf("\nOPTIONS:\n"); |
| printf("\t-c\tDon't use new viewport colour tags (non-mono displays only)\n"); |
| printf("\t-m\tSkin is for a mono display (different viewport tags)\n"); |
| return 0; |
| } |
| |
| while ((argc > filearg) && argv[filearg][0] == '-') |
| { |
| i=1; |
| while (argv[filearg][i]) |
| { |
| switch(argv[filearg][i]) |
| { |
| case 'c': /* disable new colour tags */ |
| use_new_vp_tags = false; |
| break; |
| case 'm': /* skin is for a mono display */ |
| is_mono_display = true; |
| break; |
| } |
| i++; |
| } |
| filearg++; |
| } |
| if (argc == filearg) |
| { |
| printf("Missing input filename\n"); |
| return 1; |
| } |
| |
| in = fopen(argv[filearg], "r"); |
| if (!in) |
| return 1; |
| while (fgets(temp, 512, in)) |
| strcat(buffer, temp); |
| fclose(in); |
| filearg++; |
| |
| if (argc > filearg) |
| { |
| out = fopen(argv[filearg], "w"); |
| if (!out) |
| { |
| printf("Couldn't open %s\n", argv[filearg]); |
| return 1; |
| } |
| } |
| |
| parse_text(buffer, out); |
| if (out != stdout) |
| fclose(out); |
| return 0; |
| } |