/** * Reads in key/value pairs of the form Key = Value <newline> * Note that there is little error handling here, so make sure everything is formatted correctly * * For nested sections, note that if you have another section at the same level, it must be signified by * "}{", do NOT put a newline between the closing brace of the last section and the opening brace of the * next one. This is due to the fragility of the parser, but since it's a test function, it's really not * worth fixing it. */ char* read_in_dictionary(ngt_dictionary* d, char* in_ptr, int *line, int in_dictionary) { // TODO: This is one big hack of a function. We should clean this up some time char marker[MAXMARKERLENGTH]; char value[MAXVALUELENGTH]; char *ptr; int ch, after_equals, escaped, in_comment, found_dictionary; memset(marker, 0, MAXMARKERLENGTH); memset(value, 0, MAXVALUELENGTH); escaped = 0; after_equals = 0; in_comment = 0; ptr = marker; if (!in_ptr) { return 0; } found_dictionary = in_dictionary; while (!found_dictionary && *in_ptr) { if (*in_ptr == '{' && *(in_ptr+1) == '{' && *(in_ptr+2) == '!' && *(in_ptr+3) == '#') { found_dictionary = 1; in_ptr+=4; // Skip over those starting characters break; } in_ptr++; } if (!found_dictionary) { return 0; } while (*in_ptr) { if (*in_ptr == '#' && *(in_ptr+1) == '!' && *(in_ptr+2) == '}' && *(in_ptr+3) == '}') { // Found the end return 0; } ch = (int)*in_ptr++; if (!in_comment && ch == '#') { // Start comment until newline in_comment = 1; continue; } else if (in_comment) { if (ch == '\r' || ch == '\n') { // Done with comment in_comment = 0; } else { continue; } } if (ch == '\\') { // We have an escape character coming ch = (int)*in_ptr++; if (ch == EOF) { fprintf(stderr, "Unexpected End of File after escape character on line %d\n", *line); exit(-1); } if (ch != '{' && ch != '}' && ch != '!' && ch != '=' && ch != '#') { fprintf(stderr, "Unrecognized escape character ('\\%c') on line %d\n", ch, *line); exit(-1); } escaped = 1; } else { escaped = 0; } if (!escaped && ch == '{') { if (!after_equals) { fprintf(stderr, "Unexpected '{' before '=' on line %d\n", *line); exit(-1); } ngt_dictionary* child = ngt_dictionary_new(); ngt_add_dictionary(d, marker, child, NGT_SECTION_VISIBLE); in_ptr = read_in_dictionary(child, in_ptr, line, 1); continue; } if (!escaped && ch == '}') { if (ptr != marker && !after_equals) { fprintf(stderr, "Unexpected '}' before '=' on line %d\n", *line); exit(-1); } if (!(d->parent)) { fprintf(stderr, "Unexpected '}' before '{' on line %d\n", *line); exit(-1); } // If we got here, it means that we were a recursive read_in_dictionary call and it's // time for us to exit return in_ptr; } if (ch == '\r' || ch == '\n') { if (ptr != marker && ptr != value) { // We have a valid pair (we hope) ngt_set_string(d, marker, value); } memset(marker, 0, MAXMARKERLENGTH); memset(value, 0, MAXVALUELENGTH); ptr = marker; after_equals = 0; (*line)++; continue; } if (!after_equals && (ch == ' ' || ch == '\t')) { // Skip whitespace continue; } if (!escaped && ch == '=') { if (ptr == marker) { fprintf(stderr, "Null marker on line %d\n", *line); exit(-1); } ptr = value; after_equals = 1; continue; } *(ptr++) = ch; } return in_ptr; }
/** * ngt_embed - Turn one or more template files into C code for embedding into programs */ int ngt_embed(const char* code_template, FILE* out, int argc, char** argv) { int i; ngt_template* tpl; ngt_dictionary* dict; char* output; char file[PATH_MAX]; char name[PATH_MAX]; if (argc == 1) { fprintf(stderr, "USAGE: ngtembed file1[=name1] file2[=name2] ... fileN[=nameN] [>out_file]\n"); return -1; } tpl = ngt_new(); dict = ngt_dictionary_new(); ngt_add_modifier(tpl, "breakup_lines", _breakup_lines_modifier_cb); ngt_set_delimiters(tpl, "@", "@"); ngt_set_dictionary(tpl, dict); tpl->tmpl = (char*)code_template; for (i = 1; i < argc; i++) { char* p; int m, has_name; p = argv[i]; m = 0; has_name = 0; while (*p) { if (m < PATH_MAX && *p == '=') { // Setting an explicit name. Throw out what we've done so far has_name = 1; m = 0; p++; continue; } if (*p == '.' || *p == '\\' || *p == '/') { name[m] = '_'; } else { name[m] = *p; } if (!has_name) { file[m] = *p; file[m+1] = '\0'; } p++; m++; } name[m] = '\0'; if (m) { stringbuilder* sb; FILE* fd; int ch; fd = fopen(file, "r"); if (!fd) { fprintf(stderr, "Could not open '%s' for reading\n", file); return -1; } ngt_dictionary* section = ngt_dictionary_new(); ngt_set_string(section, "TemplateName", name); sb = sb_new(); while ((ch = fgetc(fd)) != EOF) { sb_append_ch(sb, (char)ch); } ngt_set_string(section, "TemplateBody", sb_cstring(sb)); sb_destroy(sb, 1); ngt_add_dictionary(dict, "Template", section, NGT_SECTION_VISIBLE); fclose(fd); } } ngt_expand(tpl, &output); fprintf(out, "%s\n", output); ngt_destroy(tpl); ngt_dictionary_destroy(dict); free(output); }