Root/eeshow/gui/fmt-pango.c

1/*
2 * gui/fmt-pango.c - Format strings for Pango markup
3 *
4 * Written 2016 by Werner Almesberger
5 * Copyright 2016 by Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#define _GNU_SOURCE /* for asprintf */
15#include <stdarg.h>
16#include <stdlib.h>
17#include <stdio.h>
18#include <ctype.h>
19#include <alloca.h>
20
21#include "misc/util.h"
22#include "misc/diag.h"
23#include "gui/fmt-pango.h"
24
25
26unsigned vsfmt_pango(char *buf, const char *fmt, va_list ap)
27{
28    char *res;
29    const char *p, *q, *s, *t;
30    char *u;
31    char *tmp_fmt;
32    char *tmp, *tmp2;
33    int len;
34    unsigned extra;
35
36    res = buf;
37    for (p = fmt; *p; p++) {
38        if (*p != '%') {
39            if (buf)
40                *res = *p;
41            res++;
42            continue;
43        }
44        for (q = p + 1; isdigit(*q) || *q == '.' || *q == '-'; q++);
45        tmp_fmt = alloca(q - p + 1 + 1);
46        memcpy(tmp_fmt, p, q - p + 1);
47        tmp_fmt[q - p + 1] = 0;
48        switch (*q) {
49        case 's':
50            s = va_arg(ap, const char *);
51            len = asprintf(&tmp, tmp_fmt, s);
52
53            extra = 0;
54            for (t = tmp; *t; t++)
55                switch (*t) {
56                case '<':
57                case '>':
58                    extra += 3;
59                    break;
60                case '&':
61                    extra += 4;
62                    break;
63                default:
64                    break;
65                }
66            
67            if (extra) {
68                tmp2 = u = alloca(len + extra + 1);
69                for (t = tmp; *t; t++) {
70                    switch (*t) {
71                    case '<':
72                        strcpy(u, "&lt;");
73                        u += 4;
74                        break;
75                    case '>':
76                        strcpy(u, "&gt;");
77                        u += 4;
78                        break;
79                    case '&':
80                        strcpy(u, "&amp;");
81                        u += 5;
82                        break;
83                    default:
84                        *u++ = *t;
85                        break;
86                    }
87                }
88                *u = 0;
89                tmp = tmp2;
90            }
91
92            if (buf)
93                memcpy(res, tmp, len + extra);
94            res += len + extra;
95            break;
96        case 'c':
97            /* @@@ we don't filter markup meta-characters */
98        case 'd':
99        case 'x':
100            len = asprintf(&tmp, tmp_fmt, va_arg(ap, int));
101            if (buf)
102                memcpy(res, tmp, len);
103            res += len;
104            break;
105        case 'u':
106            len = asprintf(&tmp, tmp_fmt, va_arg(ap, unsigned));
107            if (buf)
108                memcpy(res, tmp, len);
109            res += len;
110            break;
111        case '%':
112            if (buf)
113                *res = '%';
114            res++;
115            break;
116        default:
117            fatal("unrecognized format '%%%c'\n", *q);
118        }
119        p = q;
120    }
121    if (buf)
122        *res = 0;
123    return res - buf;
124}
125
126
127char *vfmt_pango(const char *fmt, va_list ap)
128{
129    va_list aq;
130    unsigned len;
131    char *buf;
132
133    va_copy(aq, ap);
134    len = vsfmt_pango(NULL, fmt, ap);
135    buf = alloc_size(len + 1);
136    vsfmt_pango(buf, fmt, aq);
137    va_end(aq);
138    return buf;
139}
140
141
142char *fmt_pango(const char *fmt, ...)
143{
144    va_list ap;
145    char *buf;
146
147    va_start(ap, fmt);
148    buf = vfmt_pango(fmt, ap);
149    va_end(ap);
150    return buf;
151}
152

Archive Download this file

Branches:
master



interactive