/* * Quote/unquote a string using shell style quoting */ char * ni_quote(const char *string, const char *sepa) { ni_stringbuf_t buf = NI_STRINGBUF_INIT_DYNAMIC; unsigned int n, m; int cc; if (sepa) m = strcspn(string, sepa); else m = strlen(string); n = strcspn(string, "\"'"); if (m == n && string[n] == '\0') return xstrdup(string); ni_stringbuf_putc(&buf, '"'); while ((cc = *string++) != '\0') { if (cc == '"' || cc == '\'' || cc == '\\') ni_stringbuf_putc(&buf, '\\'); ni_stringbuf_putc(&buf, cc); } ni_stringbuf_putc(&buf, '"'); return buf.string; }
static char * __xpath_node_array_print_short(const xpath_result_t *na) { ni_stringbuf_t buf; unsigned int n; if (na->type == XPATH_BOOLEAN) return xstrdup(__xpath_test_boolean(na)? "[true]" : "[false]"); if (na->count == 0) return xstrdup("[]"); ni_stringbuf_init(&buf); ni_stringbuf_putc(&buf, '['); for (n = 0; n < na->count; ++n) { const char *string; if (n) ni_stringbuf_puts(&buf, ", "); if (n >= 7) { ni_stringbuf_puts(&buf, "..."); break; } switch (na->type) { case XPATH_ELEMENT: string = na->node[n].value.node->name; ni_stringbuf_printf(&buf, "<%s>", string?: "ROOT"); break; case XPATH_INTEGER: ni_stringbuf_printf(&buf, "%ld", na->node[n].value.integer); break; case XPATH_STRING: string = na->node[n].value.string; if (strlen(string) > 32) ni_stringbuf_printf(&buf, "\"%.32s ...\"", string); else ni_stringbuf_printf(&buf, "\"%s\"", string); break; default: ni_stringbuf_puts(&buf, "???"); } } ni_stringbuf_putc(&buf, ']'); return buf.string; }
/* * Expand an XML entity. * For now, we support &<number>; as well as symbolic entities * lt gt amp */ ni_bool_t xml_expand_entity(xml_reader_t *xr, ni_stringbuf_t *res) { char temp[128]; ni_stringbuf_t entity = NI_STRINGBUF_INIT_BUFFER(temp); int cc, expanded; while ((cc = xml_getc(xr)) != ';') { if (cc == EOF) { xml_parse_error(xr, "Unexpenced EOF in entity"); return FALSE; } if (isspace(cc)) continue; if (entity.len + sizeof(char) >= entity.size) { xml_parse_error(xr, "Entity is too long"); return FALSE; } ni_stringbuf_putc(&entity, cc); } if (ni_string_empty(entity.string)) { xml_parse_error(xr, "Empty entity &;"); return FALSE; } if (!strcasecmp(entity.string, "lt")) expanded = '<'; else if (!strcasecmp(entity.string, "gt")) expanded = '>'; else if (!strcasecmp(entity.string, "amp")) expanded = '&'; else { const char *es = entity.string; if (*es == '#') { expanded = strtoul(es + 1, (char **) &es, 0); if (*es == '\0') goto good; } xml_parse_error(xr, "Cannot expand unknown entity &%s;", entity.string); return FALSE; } good: ni_stringbuf_putc(res, expanded); return TRUE; }
char * ni_unquote(const char **stringp, const char *sepa) { ni_stringbuf_t buf = NI_STRINGBUF_INIT_DYNAMIC; const char *src = *stringp; int cc; if (sepa) src += strspn(src, sepa); while ((cc = *src) != '\0') { ++src; if (sepa && strchr(sepa, cc)) break; if (cc == '"') { while ((cc = *src++) != '"') { if (cc == '\0') goto failed; if (cc == '\\') { cc = *src++; if (cc == '\0') goto failed; } ni_stringbuf_putc(&buf, cc); } } else if (cc == '\'') { while ((cc = *src++) != '\'') { if (cc == '\0') goto failed; ni_stringbuf_putc(&buf, cc); } } else { ni_stringbuf_putc(&buf, cc); } } *stringp = src; return buf.string; failed: ni_stringbuf_destroy(&buf); return NULL; }
/* * Skip any space in the input stream, and copy if to @result */ void xml_skip_space(xml_reader_t *xr, ni_stringbuf_t *result) { int cc; while ((cc = xml_getc(xr)) != EOF) { if (!isspace(cc)) { xml_ungetc(xr, cc); break; } if (result) ni_stringbuf_putc(result, cc); } }
static void show_exec_info(int argc, char **argv) { ni_stringbuf_t args = NI_STRINGBUF_INIT_DYNAMIC; int i; for (i = 0; i < argc && argv[i]; ++i) { if (i != 0) ni_stringbuf_putc(&args, ' '); ni_stringbuf_puts(&args, argv[i]); } ni_debug_application("Executing: %s", args.string); ni_stringbuf_destroy(&args); }
xml_token_type_t xml_get_token_tag(xml_reader_t *xr, ni_stringbuf_t *res) { int cc, oc; xml_skip_space(xr, NULL); cc = xml_getc(xr); if (cc == EOF) { xml_parse_error(xr, "Unexpected EOF while parsing tag"); return None; } ni_stringbuf_putc(res, cc); switch (cc) { case '<': goto error; case '?': if ((cc = xml_getc(xr)) != '>') goto error; ni_stringbuf_putc(res, cc); xr->state = Initial; return RightAngleQ; case '>': xr->state = Initial; return RightAngle; case '/': if ((cc = xml_getc(xr)) != '>') goto error; ni_stringbuf_putc(res, cc); xr->state = Initial; return RightAngleSlash; case '=': return Equals; case 'a' ... 'z': case 'A' ... 'Z': case '_': case '!': while ((cc = xml_getc(xr)) != EOF) { if (!isalnum(cc) && cc != '_' && cc != '!' && cc != ':' && cc != '-') { xml_ungetc(xr, cc); break; } ni_stringbuf_putc(res, cc); } return Identifier; case '\'': case '"': ni_stringbuf_clear(res); oc = cc; while (1) { cc = xml_getc(xr); if (cc == EOF) { xml_parse_error(xr, "Unexpected EOF while parsing quoted string"); return None; } if (cc == oc) break; ni_stringbuf_putc(res, cc); } return QuotedString; default: break; } error: xml_parse_error(xr, "Unexpected character %c in XML document", cc); return None; }
/* * While in state Initial, obtain the next token */ xml_token_type_t xml_get_token_initial(xml_reader_t *xr, ni_stringbuf_t *res) { xml_token_type_t token; int cc; restart: /* Eat initial white space and store it in @res */ xml_skip_space(xr, res); cc = xml_getc(xr); if (cc == EOF) { ni_stringbuf_clear(res); return EndOfDocument; } if (cc == '<') { /* Discard the white space in @res - we're not interested in that. */ ni_stringbuf_clear(res); ni_stringbuf_putc(res, cc); if (xr->state != Initial) { xml_parse_error(xr, "Unexpected < in XML stream (state %s)", xml_parser_state_name(xr->state)); return None; } /* tag is legal here */ xr->state = Tag; cc = xml_getc(xr); switch (cc) { case '/': ni_stringbuf_putc(res, cc); return LeftAngleSlash; case '?': ni_stringbuf_putc(res, cc); return LeftAngleQ; case '!': ni_stringbuf_putc(res, cc); /* If it's <!IDENTIFIER, return LeftAngleExclam */ cc = xml_getc(xr); if (cc != '-') { xml_ungetc(xr, cc); return LeftAngleExclam; } token = xml_skip_comment(xr); if (token == Comment) { xr->state = Initial; ni_stringbuf_clear(res); goto restart; } return token; default: xml_ungetc(xr, cc); break; } return LeftAngle; } // Looks like CDATA. // Ignore initial newline, then scan to next < do { if (cc == '<') { /* Looks like we're done. * FIXME: handle comments within CDATA? */ xml_ungetc(xr, cc); break; } else if (cc == '&') { if (!xml_expand_entity(xr, res)) return None; } else { ni_stringbuf_putc(res, cc); } cc = xml_getc(xr); } while (cc != EOF); ni_stringbuf_trim_empty_lines(res); return CData; }
/* * Decode an RFC3397 DNS search order option. */ static int ni_dhcp_decode_dnssearch(ni_buffer_t *optbuf, ni_string_array_t *list, const char *what) { ni_stringbuf_t namebuf = NI_STRINGBUF_INIT_DYNAMIC; unsigned char *base = ni_buffer_head(optbuf); unsigned int base_offset = optbuf->head; size_t len; ni_string_array_destroy(list); while (ni_buffer_count(optbuf) && !optbuf->underflow) { ni_buffer_t *bp = optbuf; ni_buffer_t jumpbuf; while (1) { unsigned int pos = bp->head - base_offset; unsigned int pointer; char label[64]; int length; if ((length = ni_buffer_getc(bp)) < 0) goto failure; /* unexpected EOF */ if (length == 0) break; /* end of this name */ switch (length & 0xC0) { case 0: /* Plain name component */ if (ni_buffer_get(bp, label, length) < 0) goto failure; label[length] = '\0'; if (!ni_stringbuf_empty(&namebuf)) ni_stringbuf_putc(&namebuf, '.'); ni_stringbuf_puts(&namebuf, label); break; case 0xC0: /* Pointer */ pointer = (length & 0x3F) << 8; if ((length = ni_buffer_getc(bp)) < 0) goto failure; pointer |= length; if (pointer >= pos) goto failure; ni_buffer_init_reader(&jumpbuf, base, pos); jumpbuf.head = pointer; bp = &jumpbuf; break; default: goto failure; } } if (!ni_stringbuf_empty(&namebuf)) { len = ni_string_len(namebuf.string); if (ni_check_domain_name(namebuf.string, len, 0)) { ni_string_array_append(list, namebuf.string); } else { ni_debug_dhcp("Discarded suspect %s: %s", what, ni_print_suspect(namebuf.string, len)); } } ni_stringbuf_destroy(&namebuf); } return 0; failure: ni_stringbuf_destroy(&namebuf); ni_string_array_destroy(list); return -1; }