ksgi
/
kcgixml.c
287 строк · 6.0 Кб
1/* $Id$ */
2/*
3* Copyright (c) 2015, 2017, 2020 Kristaps Dzonsons <kristaps@bsd.lv>
4*
5* Permission to use, copy, modify, and distribute this software for any
6* purpose with or without fee is hereby granted, provided that the above
7* copyright notice and this permission notice appear in all copies.
8*
9* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*/
17#include "config.h"18
19#include <assert.h>20#include <inttypes.h>21#include <stdarg.h>22#include <stdint.h>23#include <stdio.h>24#include <stdlib.h>25#include <string.h>26
27#include "kcgi.h"28#include "kcgixml.h"29
30enum kcgi_err31kxml_open(struct kxmlreq *r, struct kreq *req,32const char *const *elems, size_t elemsz)33{
34
35memset(r, 0, sizeof(struct kxmlreq));36if (NULL == (r->arg = kcgi_writer_get(req, 0)))37return(KCGI_ENOMEM);38r->elems = elems;39r->elemsz = elemsz;40return(KCGI_OK);41}
42
43enum kcgi_err44kxml_prologue(struct kxmlreq *r)45{
46
47return kcgi_writer_puts(r->arg,48"<?xml version=\"1.0\" "49"encoding=\"utf-8\" ?>");50}
51
52enum kcgi_err53kxml_close(struct kxmlreq *r)54{
55enum kcgi_err er;56
57er = kxml_popall(r);58kcgi_writer_free(r->arg);59r->arg = NULL;60return er;61}
62
63enum kcgi_err64kxml_push(struct kxmlreq *r, size_t elem)65{
66enum kcgi_err er;67
68if (r->stackpos >= KXML_STACK_MAX) {69kutil_warnx(NULL, NULL,70"maximum xml stack size exceeded");71return KCGI_ENOMEM;72} else if (elem >= r->elemsz)73return KCGI_WRITER;74
75if ((er = kcgi_writer_putc(r->arg, '<')) != KCGI_OK)76return er;77if ((er = kcgi_writer_puts(r->arg, r->elems[elem])) != KCGI_OK)78return er;79if ((er = kcgi_writer_putc(r->arg, '>')) != KCGI_OK)80return er;81
82r->stack[r->stackpos++] = elem;83return KCGI_OK;84}
85
86enum kcgi_err87kxml_pushnull(struct kxmlreq *r, size_t elem)88{
89enum kcgi_err er;90
91if (r->stackpos >= KXML_STACK_MAX) {92kutil_warnx(NULL, NULL,93"maximum xml stack size exceeded");94return KCGI_ENOMEM;95} else if (elem >= r->elemsz)96return KCGI_WRITER;97
98if ((er = kcgi_writer_putc(r->arg, '<')) != KCGI_OK)99return er;100if ((er = kcgi_writer_puts(r->arg, r->elems[elem])) != KCGI_OK)101return er;102
103return kcgi_writer_puts(r->arg, " />");104}
105
106enum kcgi_err107kxml_putc(struct kxmlreq *r, char c)108{
109enum kcgi_err er;110
111switch (c) {112case ('<'):113er = kcgi_writer_puts(r->arg, "<");114break;115case ('>'):116er = kcgi_writer_puts(r->arg, ">");117break;118case ('"'):119er = kcgi_writer_puts(r->arg, """);120break;121case ('&'):122er = kcgi_writer_puts(r->arg, "&");123break;124default:125er = kcgi_writer_putc(r->arg, c);126break;127}128
129return(er);130}
131
132enum kcgi_err133kxml_write(const char *p, size_t sz, void *arg)134{
135struct kxmlreq *r = arg;136size_t i;137enum kcgi_err er;138
139if (p == NULL || sz == 0)140return KCGI_OK;141
142for (i = 0; i < sz; i++)143if ((er = kxml_putc(r, p[i])) != KCGI_OK)144return er;145
146return KCGI_OK;147}
148
149enum kcgi_err150kxml_puts(struct kxmlreq *r, const char *p)151{
152
153if (p == NULL)154return KCGI_OK;155return kxml_write(p, strlen(p), r);156}
157
158enum kcgi_err159kxml_pushattrs(struct kxmlreq *r, size_t elem, ...)160{
161va_list ap;162const char *key, *val;163enum kcgi_err er = KCGI_OK;164
165if (r->stackpos >= KXML_STACK_MAX) {166kutil_warnx(NULL, NULL,167"maximum xml stack size exceeded");168return KCGI_ENOMEM;169} else if (elem >= r->elemsz)170return KCGI_WRITER;171
172if ((er = kcgi_writer_putc(r->arg, '<')) != KCGI_OK)173return er;174if ((er = kcgi_writer_puts(r->arg, r->elems[elem])) != KCGI_OK)175return er;176va_start(ap, elem);177for (;;) {178if ((key = va_arg(ap, char *)) == NULL)179break;180val = va_arg(ap, char *);181if ((er = kcgi_writer_putc(r->arg, ' ')) != KCGI_OK)182goto out;183if ((er = kcgi_writer_puts(r->arg, key)) != KCGI_OK)184goto out;185if ((er = kcgi_writer_puts(r->arg, "=\"")) != KCGI_OK)186goto out;187if ((er = kxml_puts(r, val)) != KCGI_OK)188goto out;189if ((er = kcgi_writer_putc(r->arg, '"')) != KCGI_OK)190goto out;191}192va_end(ap);193r->stack[r->stackpos++] = elem;194return kcgi_writer_putc(r->arg, '>');195out:196va_end(ap);197return er;198}
199
200enum kcgi_err201kxml_pushnullattrs(struct kxmlreq *r, size_t elem, ...)202{
203va_list ap;204const char *key, *val;205enum kcgi_err er;206
207if (r->stackpos >= KXML_STACK_MAX) {208kutil_warnx(NULL, NULL,209"maximum xml stack size exceeded");210return KCGI_ENOMEM;211} else if (elem >= r->elemsz)212return KCGI_WRITER;213
214if ((er = kcgi_writer_putc(r->arg, '<')) != KCGI_OK)215return er;216if ((er = kcgi_writer_puts(r->arg, r->elems[elem])) != KCGI_OK)217return er;218va_start(ap, elem);219for (;;) {220if ((key = va_arg(ap, char *)) == NULL)221break;222val = va_arg(ap, char *);223if ((er = kcgi_writer_putc(r->arg, ' ')) != KCGI_OK)224goto out;225if ((er = kcgi_writer_puts(r->arg, key)) != KCGI_OK)226goto out;227if ((er = kcgi_writer_puts(r->arg, "=\"")) != KCGI_OK)228goto out;229if ((er = kxml_puts(r, val)) != KCGI_OK)230goto out;231if ((er = kcgi_writer_putc(r->arg, '"')) != KCGI_OK)232goto out;233}234va_end(ap);235return kcgi_writer_puts(r->arg, " />");236out:237va_end(ap);238return er;239}
240
241static int242kxml_pop_inner(struct kxmlreq *r, enum kcgi_err *er)243{
244
245if (r->stackpos == 0)246return 0;247
248*er = kcgi_writer_puts(r->arg, "</");249if (*er != KCGI_OK)250return (-1);251
252*er = kcgi_writer_puts(r->arg,253r->elems[r->stack[--r->stackpos]]);254if (*er != KCGI_OK)255return (-1);256
257*er = kcgi_writer_putc(r->arg, '>');258if (*er != KCGI_OK)259return (-1);260
261return 1;262}
263
264enum kcgi_err265kxml_popall(struct kxmlreq *r)266{
267enum kcgi_err er = KCGI_OK;268
269while (kxml_pop_inner(r, &er) > 0)270/* Spin. */ ;271
272return er;273}
274
275enum kcgi_err276kxml_pop(struct kxmlreq *r)277{
278enum kcgi_err er;279int c;280
281if ((c = kxml_pop_inner(r, &er)) < 0)282return er;283else if (c == 0)284return KCGI_WRITER;285
286return KCGI_OK;287}
288