static int generate_val (NCDValue *value, ExpString *out_str) { switch (NCDValue_Type(value)) { case NCDVALUE_STRING: { const char *str = NCDValue_StringValue(value); size_t len = NCDValue_StringLength(value); if (!ExpString_AppendChar(out_str, '"')) { goto fail; } for (size_t i = 0; i < len; i++) { if (str[i] == '\0') { char buf[5]; snprintf(buf, sizeof(buf), "\\x%02"PRIx8, (uint8_t)str[i]); if (!ExpString_Append(out_str, buf)) { goto fail; } continue; } if (str[i] == '"' || str[i] == '\\') { if (!ExpString_AppendChar(out_str, '\\')) { goto fail; } } if (!ExpString_AppendChar(out_str, str[i])) { goto fail; } } if (!ExpString_AppendChar(out_str, '"')) { goto fail; } } break; case NCDVALUE_LIST: { if (!ExpString_AppendChar(out_str, '{')) { goto fail; } int is_first = 1; for (NCDValue *e = NCDValue_ListFirst(value); e; e = NCDValue_ListNext(value, e)) { if (!is_first) { if (!ExpString_Append(out_str, ", ")) { goto fail; } } if (!generate_val(e, out_str)) { goto fail; } is_first = 0; } if (!ExpString_AppendChar(out_str, '}')) { goto fail; } } break; case NCDVALUE_MAP: { if (!ExpString_AppendChar(out_str, '[')) { goto fail; } int is_first = 1; for (NCDValue *ekey = NCDValue_MapFirstKey(value); ekey; ekey = NCDValue_MapNextKey(value, ekey)) { NCDValue *eval = NCDValue_MapKeyValue(value, ekey); if (!is_first) { if (!ExpString_Append(out_str, ", ")) { goto fail; } } if (!generate_val(ekey, out_str)) { goto fail; } if (!ExpString_AppendChar(out_str, ':')) { goto fail; } if (!generate_val(eval, out_str)) { goto fail; } is_first = 0; } if (!ExpString_AppendChar(out_str, ']')) { goto fail; } } break; case NCDVALUE_VAR: { if (!ExpString_Append(out_str, NCDValue_VarName(value))) { goto fail; } } break; case NCDVALUE_INVOC: { if (!generate_val(NCDValue_InvocFunc(value), out_str)) { goto fail; } if (!ExpString_AppendChar(out_str, '(')) { goto fail; } if (!generate_val(NCDValue_InvocArg(value), out_str)) { goto fail; } if (!ExpString_AppendChar(out_str, ')')) { goto fail; } } break; default: ASSERT(0); } return 1; fail: return 0; }
void NCDConfigTokenizer_Tokenize (char *str, size_t left, NCDConfigTokenizer_output output, void *user) { size_t line = 1; size_t line_char = 1; while (left > 0) { size_t l; int error = 0; int token; void *token_val = NULL; if (*str == '#') { l = 1; while (l < left && str[l] != '\n') { l++; } token = 0; } else if (l = data_begins_with(str, left, "{")) { token = NCD_TOKEN_CURLY_OPEN; } else if (l = data_begins_with(str, left, "}")) { token = NCD_TOKEN_CURLY_CLOSE; } else if (l = data_begins_with(str, left, "(")) { token = NCD_TOKEN_ROUND_OPEN; } else if (l = data_begins_with(str, left, ")")) { token = NCD_TOKEN_ROUND_CLOSE; } else if (l = data_begins_with(str, left, ";")) { token = NCD_TOKEN_SEMICOLON; } else if (l = data_begins_with(str, left, ".")) { token = NCD_TOKEN_DOT; } else if (l = data_begins_with(str, left, ",")) { token = NCD_TOKEN_COMMA; } else if (l = data_begins_with(str, left, ":")) { token = NCD_TOKEN_COLON; } else if (l = data_begins_with(str, left, "[")) { token = NCD_TOKEN_BRACKET_OPEN; } else if (l = data_begins_with(str, left, "]")) { token = NCD_TOKEN_BRACKET_CLOSE; } else if (l = data_begins_with(str, left, "->")) { token = NCD_TOKEN_ARROW; } else if (is_name_first_char(*str)) { l = 1; while (l < left && is_name_char(str[l])) { l++; } // allocate buffer bsize_t bufsize = bsize_add(bsize_fromsize(l), bsize_fromint(1)); char *buf; if (bufsize.is_overflow || !(buf = malloc(bufsize.value))) { BLog(BLOG_ERROR, "malloc failed"); error = 1; goto out; } // copy and terminate memcpy(buf, str, l); buf[l] = '\0'; if (!strcmp(buf, "process")) { token = NCD_TOKEN_PROCESS; free(buf); } else if (!strcmp(buf, "template")) { token = NCD_TOKEN_TEMPLATE; free(buf); } else { token = NCD_TOKEN_NAME; token_val = buf; } } else if (*str == '"') do { // init string ExpString estr; if (!ExpString_Init(&estr)) { BLog(BLOG_ERROR, "ExpString_Init failed"); goto string_fail0; } // skip start quote l = 1; // decode string while (l < left) { char dec_ch; // get character if (str[l] == '\\') { if (left - l < 2) { BLog(BLOG_ERROR, "escape character found in string but nothing follows"); goto string_fail1; } dec_ch = str[l + 1]; l += 2; } else if (str[l] == '"') { break; } else { dec_ch = str[l]; l++; } // string cannot contain zeros bytes if (dec_ch == '\0') { BLog(BLOG_ERROR, "string contains zero byte"); goto string_fail1; } // append character to string if (!ExpString_AppendChar(&estr, dec_ch)) { BLog(BLOG_ERROR, "ExpString_AppendChar failed"); goto string_fail1; } } // make sure ending quote was found if (l == left) { BLog(BLOG_ERROR, "missing ending quote for string"); goto string_fail1; } // skip ending quote l++; token = NCD_TOKEN_STRING; token_val = ExpString_Get(&estr); break; string_fail1: ExpString_Free(&estr); string_fail0: error = 1; } while (0); else if (is_space_char(*str)) { token = 0; l = 1; } else { BLog(BLOG_ERROR, "unrecognized character"); error = 1; } out: // report error if (error) { output(user, NCD_ERROR, NULL, line, line_char); return; } // output token if (token) { if (!output(user, token, token_val, line, line_char)) { return; } } // update line/char counters for (size_t i = 0; i < l; i++) { if (str[i] == '\n') { line++; line_char = 1; } else { line_char++; } } str += l; left -= l; } output(user, NCD_EOF, NULL, line, line_char); }