#ifdef UWSGI_YAML #include "uwsgi.h" extern struct uwsgi_server uwsgi; #ifndef UWSGI_LIBYAML /* yaml file must be read ALL into memory. This memory must not be freed for all the server lifecycle */ void yaml_rstrip(char *line) { off_t i; for (i = strlen(line) - 1; i >= 0; i--) { if (line[i] == ' ' || line[i] == '\t') { line[i] = 0; continue; } break; } } char *yaml_lstrip(char *line) { off_t i; char *ptr = line; for (i = 0; i < (int) strlen(line); i++) { if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r') { ptr++; continue; } break; } return ptr; } int yaml_get_depth(char *line) { off_t i; int depth = 0; for (i = 0; i < (int) strlen(line); i++) { if (line[i] == ' ') { depth++; continue; } else if (line[i] == '\t' || line[i] == '\r') { depth += 8; continue; } break; } return depth; } char *yaml_get_line(char *yaml, size_t size) { size_t i; char *ptr = yaml; int comment = 0; for (i = 0; i < size; i++) { ptr++; if (yaml[i] == '#') { yaml[i] = 0; comment = 1; } else if (yaml[i] == '\n') { yaml[i] = 0; return ptr; } else if (comment) { yaml[i] = 0; } } // check if it is a stupid file without \n at the end if (ptr > yaml) { return ptr; } return NULL; } #else #include #endif void uwsgi_yaml_config(char *file, char *magic_table[]) { size_t len = 0; char *yaml; int in_uwsgi_section = 0; char *key = NULL; char *val = NULL; char *section_asked = "uwsgi"; char *colon; if (uwsgi_check_scheme(file)) { colon = uwsgi_get_last_char(file, '/'); colon = uwsgi_get_last_char(colon, ':'); } else { colon = uwsgi_get_last_char(file, ':'); } if (colon) { colon[0] = 0; if (colon[1] != 0) { section_asked = colon + 1; } } uwsgi_log_initial("[uWSGI] getting YAML configuration from %s\n", file); yaml = uwsgi_open_and_read(file, &len, 1, magic_table); #ifdef UWSGI_LIBYAML yaml_parser_t parser; yaml_token_t token; int status = 0; int parsing = 1; if (!yaml_parser_initialize(&parser)) { uwsgi_log("unable to initialize YAML parser (libyaml)\n"); exit(1); } yaml_parser_set_input_string(&parser, (unsigned char *) yaml, (size_t) len - 1); while (parsing) { if (!yaml_parser_scan(&parser, &token)) { uwsgi_log("error parsing YAML file: %s (%c)\n", parser.problem, yaml[parser.problem_offset]); exit(1); } switch (token.type) { case YAML_STREAM_END_TOKEN: parsing = 0; break; case YAML_KEY_TOKEN: status = 1; break; case YAML_VALUE_TOKEN: status = 2; break; case YAML_FLOW_SEQUENCE_START_TOKEN: case YAML_BLOCK_SEQUENCE_START_TOKEN: if (in_uwsgi_section) in_uwsgi_section++; // fallthrough case YAML_FLOW_ENTRY_TOKEN: case YAML_BLOCK_ENTRY_TOKEN: status = 3; // inside a sequence break; case YAML_BLOCK_MAPPING_START_TOKEN: if (in_uwsgi_section) { in_uwsgi_section++; break; } if (key) { if (!strcmp(section_asked, key)) { in_uwsgi_section = 1; } } break; case YAML_BLOCK_END_TOKEN: case YAML_FLOW_SEQUENCE_END_TOKEN: if (in_uwsgi_section) parsing = !!(--in_uwsgi_section); key = NULL; status = 0; break; case YAML_SCALAR_TOKEN: if (status == 1) { key = (char *) token.data.scalar.value; } else if (status == 2 || status == 3) { val = (char *) token.data.scalar.value; if (key && val && in_uwsgi_section) { add_exported_option(key, val, 0); } // If this was the scalar of a value token, forget the state. if (status == 2) { key = NULL; status = 0; } } else { uwsgi_log("unsupported YAML token %d in %s block\n", token.type, section_asked); parsing = 0; break; } break; default: status = 0; } } #else int depth; int current_depth = 0; int lines = 1; char *yaml_line; char *section = ""; while (len) { yaml_line = yaml_get_line(yaml, len); if (yaml_line == NULL) { break; } lines++; // skip empty line if (yaml[0] == 0) goto next; depth = yaml_get_depth(yaml); if (depth <= current_depth) { current_depth = depth; // end the parsing cycle if (in_uwsgi_section) return; } else if (depth > current_depth && !in_uwsgi_section) { goto next; } key = yaml_lstrip(yaml); // skip empty line if (key[0] == 0) goto next; // skip list and {} defined dict if (key[0] == '-' || key[0] == '[' || key[0] == '{') { if (in_uwsgi_section) return; goto next; } if (!in_uwsgi_section) { section = strchr(key, ':'); if (!section) goto next; section[0] = 0; if (!strcmp(key, section_asked)) { in_uwsgi_section = 1; } } else { // get dict value val = strstr(key, ": "); if (!val) { val = strstr(key, ":\t"); } if (!val) return; // get the right key val[0] = 0; // yeah overengineering.... yaml_rstrip(key); val = yaml_lstrip(val + 2); yaml_rstrip(val); //uwsgi_log("YAML: %s = %s\n", key, val); add_exported_option((char *) key, val, 0); } next: len -= (yaml_line - yaml); yaml += (yaml_line - yaml); } #endif if (colon) colon[0] = ':'; } #endif