1 : #define VSTR_ADD_NETSTR_C
2 : /*
3 : * Copyright (C) 1999, 2000, 2001, 2002, 2003 James Antill
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Lesser General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Lesser General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public
16 : * License along with this library; if not, write to the Free Software
17 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 : *
19 : * email: james@and.org
20 : */
21 : /* netstr (http://cr.yp.to/proto/netstrings.txt). This is basically
22 : * <num ':' data ','>
23 : * where
24 : * num is an ascii number (base 10)
25 : * data is 8 bit binary data (Ie. any value 0 - 255 is allowed).
26 : */
27 : /* netstr2 like netstr but allows leading '0' characters */
28 :
29 : #include "main.h"
30 :
31 : #ifndef VSTR_AUTOCONF_ULONG_MAX_LEN
32 : /* only used as a variable if can't work i tout at compile time */
33 : size_t vstr__netstr2_ULONG_MAX_len = 0;
34 : #endif
35 :
36 : size_t vstr_add_netstr2_beg(Vstr_base *base, size_t pos)
37 4927 : {
38 4927 : size_t tmp = 0;
39 4927 : size_t ret = 0;
40 :
41 4927 : ASSERT_RET(base, 0);
42 4923 : ASSERT_RET(pos <= base->len, 0);
43 :
44 4919 : ret = pos + 1;
45 : /* number will be overwritten so it's ok in OS/compile default locale */
46 4919 : tmp = vstr_add_sysfmt(base, pos, "%lu%c", ULONG_MAX, VSTR__ASCII_COLON());
47 :
48 4919 : if (!tmp)
49 6 : return (0);
50 :
51 4913 : --tmp; /* remove comma from len */
52 :
53 4913 : assert(!VSTR__ULONG_MAX_LEN || (tmp == VSTR__ULONG_MAX_LEN));
54 : VSTR__ULONG_MAX_SET_LEN(tmp);
55 :
56 4913 : assert(vstr_export_chr(base, ret + VSTR__ULONG_MAX_LEN) ==
57 : VSTR__ASCII_COLON());
58 :
59 4913 : return (ret);
60 : }
61 :
62 : static int vstr__netstr_end_start(Vstr_base *base,
63 : size_t beg_pos, size_t end_pos,
64 : size_t *count, char *buf)
65 4944 : {
66 4944 : size_t len = 0;
67 :
68 4944 : ASSERT(base);
69 4944 : ASSERT(beg_pos);
70 4944 : ASSERT(end_pos);
71 :
72 4944 : ASSERT_RET(VSTR__ULONG_MAX_LEN, FALSE);
73 :
74 4944 : ASSERT_RET(beg_pos < end_pos, FALSE);
75 4928 : ASSERT_RET(end_pos <= base->len, FALSE);
76 4924 : ASSERT_RET(vstr_sc_posdiff(beg_pos, end_pos) > VSTR__ULONG_MAX_LEN, FALSE);
77 :
78 4920 : assert(vstr_export_chr(base, beg_pos + VSTR__ULONG_MAX_LEN) ==
79 : VSTR__ASCII_COLON());
80 :
81 : /* includes the ':' */
82 4920 : len = end_pos - (beg_pos + VSTR__ULONG_MAX_LEN);
83 :
84 4920 : if (!vstr_add_rep_chr(base, end_pos, VSTR__ASCII_COMMA(), 1))
85 2 : return (FALSE);
86 :
87 4918 : *count = VSTR__ULONG_MAX_LEN;
88 10886 : while (len)
89 : {
90 5968 : int off = len % 10;
91 :
92 5968 : buf[--*count] = VSTR__ASCII_DIGIT_0() + off;
93 :
94 5968 : len /= 10;
95 : }
96 :
97 4918 : return (TRUE);
98 : }
99 :
100 : int vstr_add_netstr2_end(Vstr_base *base,
101 : size_t netstr_beg_pos, size_t netstr_end_pos)
102 21 : {
103 21 : size_t count = 0;
104 21 : char buf[BUF_NUM_TYPE_SZ(unsigned long)];
105 :
106 21 : assert(sizeof(buf) >= VSTR__ULONG_MAX_LEN);
107 :
108 21 : if (!vstr__netstr_end_start(base, netstr_beg_pos, netstr_end_pos,
109 : &count, buf))
110 1 : return (FALSE);
111 20 : assert(count <= VSTR__ULONG_MAX_LEN);
112 :
113 : /* must use sub_buf ... as sub_rep_buf isn't as optimised ...
114 : * so it'd be slower _and_ we'd need to check/handle for failure */
115 20 : vstr_wrap_memset(buf, VSTR__ASCII_DIGIT_0(), count);
116 20 : vstr_sub_buf(base, netstr_beg_pos, count, buf, count);
117 :
118 20 : vstr_sub_buf(base, netstr_beg_pos + count, VSTR__ULONG_MAX_LEN - count,
119 : buf + count, VSTR__ULONG_MAX_LEN - count);
120 :
121 20 : return (TRUE);
122 : }
123 :
124 : /* NOTE: might want to use vstr_add_pos_buf()/_ref() eventually */
125 : size_t vstr_add_netstr_beg(Vstr_base *base, size_t pos)
126 4904 : {
127 4904 : return (vstr_add_netstr2_beg(base, pos));
128 : }
129 :
130 : int vstr_add_netstr_end(Vstr_base *base,
131 : size_t netstr_beg_pos, size_t netstr_end_pos)
132 4923 : {
133 4923 : size_t count = 0;
134 4923 : char buf[BUF_NUM_TYPE_SZ(unsigned long)];
135 :
136 4923 : assert(sizeof(buf) >= VSTR__ULONG_MAX_LEN);
137 :
138 4923 : if (!vstr__netstr_end_start(base, netstr_beg_pos, netstr_end_pos,
139 : &count, buf))
140 25 : return (FALSE);
141 4898 : ASSERT(count <= VSTR__ULONG_MAX_LEN);
142 :
143 4898 : if (count == VSTR__ULONG_MAX_LEN)
144 : { /* here we delete, so need to keep something */
145 65 : buf[--count] = VSTR__ASCII_DIGIT_0();
146 : }
147 :
148 4898 : if (count && !vstr_del(base, netstr_beg_pos, count))
149 : {
150 1 : vstr_del(base, netstr_end_pos + 1, 1); /* remove comma, always works */
151 1 : return (FALSE);
152 : }
153 4897 : vstr_sub_buf(base, netstr_beg_pos, VSTR__ULONG_MAX_LEN - count,
154 : buf + count, VSTR__ULONG_MAX_LEN - count);
155 :
156 4897 : return (TRUE);
157 : }
|