aboutsummaryrefslogtreecommitdiff
path: root/src/pack.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pack.c')
-rw-r--r--src/pack.c588
1 files changed, 588 insertions, 0 deletions
diff --git a/src/pack.c b/src/pack.c
new file mode 100644
index 0000000..a6ee933
--- /dev/null
+++ b/src/pack.c
@@ -0,0 +1,588 @@
1/* This file is part of vmod-binlog
2 Copyright (C) 2013 Sergey Poznyakoff
3
4 Vmod-binlog is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 Vmod-binlog is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with vmod-binlog. If not, see <http://www.gnu.org/licenses/>.
16*/
17#include <config.h>
18#include <stdint.h>
19#include <stdlib.h>
20#include <stdio.h>
21#include <string.h>
22#include <ctype.h>
23#include "pack.h"
24
25/* Data format specification is a simplified form of Perl pack() template.
26 It consists of a series of template letters optionally followed by
27 numeric repeat count (which may be enclosed in square brackets). The
28 valid template letters are:
29
30 Z A null-terminated (ASCIZ) string of at most N-1 characters, will be
31 null padded. This letter must be followed by repeat count.
32
33 c A signed char (8-bit) value.
34 C An unsigned char (octet) value.
35
36 s A signed short (16-bit) value.
37 S An unsigned short value.
38
39 l A signed long (32-bit) value.
40 L An unsigned long value.
41
42 q A signed quad (64-bit) value.
43 Q An unsigned quad value.
44
45 i A signed integer value.
46 I A unsigned integer value.
47
48 x A null byte (a.k.a ASCII NUL, "\000", chr(0))
49 X Back up a byte.
50 @ Null-fill or truncate to absolute position, counted from the
51 current position.
52 . Null-fill or truncate to absolute position specified by
53 the repeat count.
54*/
55
56#define F_REP 0x01
57
58struct packspec {
59 int ch;
60 size_t size;
61 int flags;
62 void (*packer)(struct packenv *, struct packspec *, int);
63 void (*unpacker)(struct packenv *, struct packspec *, int);
64};
65
66struct packinst {
67 struct packinst *next;
68 struct packspec *spec;
69 int rep;
70};
71
72static char *
73packenv_get(struct packenv *env)
74{
75 if (env->argi == env->argc)
76 return NULL;
77 return env->argv[env->argi++];
78}
79
80static void
81printunum(FILE *fp, uintmax_t num)
82{
83 char numbuf[512];
84 char *p = numbuf + sizeof(numbuf);
85 *--p = 0;
86 do
87 *--p = num % 10 + '0';
88 while (num /= 10);
89 fputs(p, fp);
90}
91
92static void
93printsnum(FILE *fp, intmax_t num)
94{
95 if (num < 0) {
96 fputc('-', fp);
97 num = - num;
98 }
99 printunum(fp, num);
100}
101
102static void
103Z_packer(struct packenv *env, struct packspec *spec, int rep)
104{
105 if (env->buf_base) {
106 char *arg = packenv_get(env);
107
108 memset(env->buf_base + env->buf_pos, 0, rep);
109 if (arg) {
110 size_t len = strlen(arg);
111 if (len > rep - 1)
112 len = rep - 1;
113 memcpy(env->buf_base + env->buf_pos, arg, len);
114 }
115 }
116 env->buf_pos += rep;
117}
118
119static void
120Z_unpacker(struct packenv *env, struct packspec *spec, int rep)
121{
122 fprintf(env->fp, "%-*.*s", rep, rep, env->buf_base + env->buf_pos);
123 env->buf_pos += rep;
124}
125
126static void
127c_packer(struct packenv *env, struct packspec *spec, int rep)
128{
129 if (env->buf_base) {
130 char *arg = packenv_get(env);
131 if (arg)
132 env->buf_base[env->buf_pos] = *arg;
133 }
134 env->buf_pos++;
135}
136
137static void
138c_unpacker(struct packenv *env, struct packspec *spec, int rep)
139{
140 fprintf(env->fp, "%c", env->buf_base[env->buf_pos++]);
141}
142
143static void
144s_packer(struct packenv *env, struct packspec *spec, int rep)
145{
146 if (env->buf_base) {
147 char *arg = packenv_get(env);
148 if (arg) {
149 int16_t v = atoi(arg);
150 memcpy(env->buf_base + env->buf_pos, &v, sizeof(v));
151 }
152 }
153 env->buf_pos += spec->size;
154}
155
156static void
157s_unpacker(struct packenv *env, struct packspec *spec, int rep)
158{
159 printsnum(env->fp, *(int16_t *) (env->buf_base + env->buf_pos));
160 env->buf_pos += spec->size;
161}
162
163static void
164S_packer(struct packenv *env, struct packspec *spec, int rep)
165{
166 if (env->buf_base) {
167 char *arg = packenv_get(env);
168 if (arg) {
169 uint16_t v = atoi(arg);
170 memcpy(env->buf_base + env->buf_pos, &v, sizeof(v));
171 }
172 }
173 env->buf_pos += spec->size;
174}
175
176static void
177S_unpacker(struct packenv *env, struct packspec *spec, int rep)
178{
179 printunum(env->fp, *(uint16_t *)(env->buf_base + env->buf_pos));
180 env->buf_pos += spec->size;
181}
182
183static void
184l_packer(struct packenv *env, struct packspec *spec, int rep)
185{
186 if (env->buf_base) {
187 char *arg = packenv_get(env);
188 if (arg) {
189 int32_t v = atoi(arg);
190 memcpy(env->buf_base + env->buf_pos, &v, sizeof(v));
191 }
192 }
193 env->buf_pos += spec->size;
194}
195
196static void
197l_unpacker(struct packenv *env, struct packspec *spec, int rep)
198{
199 printsnum(env->fp, *(int32_t *)(env->buf_base + env->buf_pos));
200 env->buf_pos += spec->size;
201}
202
203static void
204L_packer(struct packenv *env, struct packspec *spec, int rep)
205{
206 if (env->buf_base) {
207 char *arg = packenv_get(env);
208 if (arg) {
209 uint32_t v = atoi(arg);
210 memcpy(env->buf_base + env->buf_pos, &v, sizeof(v));
211 }
212 }
213 env->buf_pos += spec->size;
214}
215
216static void
217L_unpacker(struct packenv *env, struct packspec *spec, int rep)
218{
219 printunum(env->fp, *(uint32_t *)(env->buf_base + env->buf_pos));
220 env->buf_pos += spec->size;
221}
222
223static void
224q_packer(struct packenv *env, struct packspec *spec, int rep)
225{
226 if (env->buf_base) {
227 char *arg = packenv_get(env);
228 if (arg) {
229 int64_t v = atoi(arg);
230 memcpy(env->buf_base + env->buf_pos, &v, sizeof(v));
231 }
232 }
233 env->buf_pos += spec->size;
234}
235
236static void
237q_unpacker(struct packenv *env, struct packspec *spec, int rep)
238{
239 printsnum(env->fp, *(int64_t *)(env->buf_base + env->buf_pos));
240 env->buf_pos += spec->size;
241}
242
243static void
244Q_packer(struct packenv *env, struct packspec *spec, int rep)
245{
246 if (env->buf_base) {
247 char *arg = packenv_get(env);
248 if (arg) {