altprintf 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/altprintf.gemspec +24 -0
- data/ext/altprintf/altprintf.h +6 -0
- data/ext/altprintf/enums.h +15 -0
- data/ext/altprintf/ext.c +270 -0
- data/ext/altprintf/extconf.h +1 -0
- data/ext/altprintf/extconf_helper.rb +35 -0
- data/ext/altprintf/fmt.c +243 -0
- data/ext/altprintf/fmt.h +9 -0
- data/ext/altprintf/fmte.c +98 -0
- data/ext/altprintf/fmte.h +37 -0
- data/ext/altprintf/log.h +12 -0
- data/ext/altprintf/parsef.c +127 -0
- data/ext/altprintf/parsef.h +10 -0
- data/ext/altprintf/strbuf.c +178 -0
- data/ext/altprintf/strbuf.h +38 -0
- data/ext/altprintf/syntax.h +35 -0
- data/lib/altprintf.rb +2 -0
- data/lib/altprintf/alt_printf.so +0 -0
- data/lib/altprintf/altprintf.so +0 -0
- data/lib/altprintf/version.rb +3 -0
- data/readme.md +16 -0
- metadata +91 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: df338e1fe04766f80321b04dc0380e6c022ae06c8e4d13cbaea05522630b7463
|
4
|
+
data.tar.gz: 9b7c74147e5ef03e947467d2c4c89e7471c873a56410d2aa00f4015680352c96
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ba342f2d892020efc12b7e0489a376b005fb2161b81ae235ac9021d04f7d594c9bda20e0c8c1a332a607a4897688faa34143c2bd1dcb100f6b71611992eeaa30
|
7
|
+
data.tar.gz: c19648ebefd35dbdf6b00760e92567be3f42c042227ba3e49d32f9595dcec29ce67ca47169c2f64ca1c164b199e3050c8a912403a1a28855c89b54084026a49d
|
data/altprintf.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'date'
|
2
|
+
require_relative 'lib/altprintf/version'
|
3
|
+
|
4
|
+
Altprintf::SPEC = Gem::Specification.new do |s|
|
5
|
+
s.name = 'altprintf'
|
6
|
+
s.version = Altprintf::VERSION.join('.')
|
7
|
+
s.date = Date.today.strftime('%Y-%m-%d')
|
8
|
+
s.summary = 'A powerful printf-like template language'
|
9
|
+
s.authors = ['Stone Tickle']
|
10
|
+
s.email = 'lattis@mochiro.moe'
|
11
|
+
s.homepage = 'https://github.com/annacrombie/altprintf/tree/master/gem'
|
12
|
+
s.license = 'MIT'
|
13
|
+
|
14
|
+
s.files = Dir['{**/*}'] - ['Rakefile']
|
15
|
+
|
16
|
+
s.platform = Gem::Platform::RUBY
|
17
|
+
s.extensions = Dir["ext/**/extconf.rb"]
|
18
|
+
s.require_paths = ['lib']
|
19
|
+
|
20
|
+
s.required_ruby_version = '>= 2.5.5'
|
21
|
+
|
22
|
+
s.add_development_dependency 'rake-compiler', '~> 1.0'
|
23
|
+
s.add_development_dependency 'rake', '~> 12.3'
|
24
|
+
end unless Altprintf.const_defined?(:'SPEC')
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#ifndef ARGTYPE_H_
|
2
|
+
#define ARGTYPE_H_
|
3
|
+
enum arg_type { FMul, FTern, FAlign, FInt, FChar, FDouble, FString, FRaw, FNone,
|
4
|
+
FEnd };
|
5
|
+
enum align { Left, Right, Center };
|
6
|
+
|
7
|
+
enum altprintf_err {
|
8
|
+
apfe_none,
|
9
|
+
apfe_invalid_token,
|
10
|
+
apfe_missing_argument
|
11
|
+
};
|
12
|
+
|
13
|
+
extern enum altprintf_err apf_err;
|
14
|
+
|
15
|
+
#endif
|
data/ext/altprintf/ext.c
ADDED
@@ -0,0 +1,270 @@
|
|
1
|
+
#ifdef _FORTIFY_SOURCE
|
2
|
+
#undef _FORTIFY_SOURCE
|
3
|
+
#endif
|
4
|
+
|
5
|
+
#ifdef RUBY_EXTCONF_H
|
6
|
+
#undef RUBY_EXTCONF_H
|
7
|
+
#endif
|
8
|
+
|
9
|
+
#include "extconf.h"
|
10
|
+
#include <stdio.h>
|
11
|
+
#include <locale.h>
|
12
|
+
#include <wchar.h>
|
13
|
+
#include <ruby.h>
|
14
|
+
#include <ruby/encoding.h>
|
15
|
+
#include "altprintf.h"
|
16
|
+
#include "log.h"
|
17
|
+
|
18
|
+
#define MODNAME "Altprintf"
|
19
|
+
|
20
|
+
rb_encoding *enc;
|
21
|
+
|
22
|
+
wchar_t *rbstowcs(VALUE str)
|
23
|
+
{
|
24
|
+
const char *cstr;
|
25
|
+
wchar_t *wstr;
|
26
|
+
size_t len;
|
27
|
+
|
28
|
+
cstr = StringValueCStr(str);
|
29
|
+
|
30
|
+
len = mbsrtowcs(NULL, &cstr, 0, NULL);
|
31
|
+
wstr = calloc(len + 1, sizeof(wchar_t));
|
32
|
+
len = mbsrtowcs(wstr, &cstr, len, NULL);
|
33
|
+
|
34
|
+
LOG("rbs to wcs, len: %d, cstr: '%s'\n", len, cstr);
|
35
|
+
LOG("wide string: '%ls'\n", wstr);
|
36
|
+
|
37
|
+
return wstr;
|
38
|
+
}
|
39
|
+
|
40
|
+
VALUE wcstorbs(const wchar_t *wstr)
|
41
|
+
{
|
42
|
+
size_t len;
|
43
|
+
char *cstr;
|
44
|
+
VALUE str;
|
45
|
+
|
46
|
+
LOG("converting wcs to rbs\n");
|
47
|
+
LOG("wcs: '%ls'\n\n", wstr);
|
48
|
+
|
49
|
+
len = wcsrtombs(NULL, &wstr, 0, NULL);
|
50
|
+
LOG("len: %d\n", len);
|
51
|
+
cstr = calloc(len, sizeof(wchar_t));
|
52
|
+
wcsrtombs(cstr, &wstr, len, NULL);
|
53
|
+
LOG("cstr: '%s'\n", cstr);
|
54
|
+
|
55
|
+
LOG("wcs to rbs, len: %d, wcs: %ls, mbs: '%s'\n", len, wstr, cstr);
|
56
|
+
|
57
|
+
if (len == (size_t)-1)
|
58
|
+
return Qnil;
|
59
|
+
|
60
|
+
str = rb_external_str_new_with_enc(cstr, len, enc);
|
61
|
+
free(cstr);
|
62
|
+
|
63
|
+
return str;
|
64
|
+
}
|
65
|
+
|
66
|
+
VALUE get_entry(struct fmte *f, size_t argc, size_t *argi, VALUE *argv, VALUE *hash)
|
67
|
+
{
|
68
|
+
VALUE sym, entry;
|
69
|
+
size_t len;
|
70
|
+
const wchar_t *tmpw;
|
71
|
+
char *cstr;
|
72
|
+
|
73
|
+
LOG("getting entry\n");
|
74
|
+
|
75
|
+
if (f->anglearg_len == 0) {
|
76
|
+
LOG("getting from argv[%d] (argc: %d)\n", *argi, argc);
|
77
|
+
if (*argi >= argc)
|
78
|
+
rb_raise(rb_eArgError, "too few arguments");
|
79
|
+
entry = rb_ary_entry(*argv, *argi);
|
80
|
+
(*argi)++;
|
81
|
+
return entry;
|
82
|
+
}
|
83
|
+
|
84
|
+
LOG("getting from hash\n");
|
85
|
+
|
86
|
+
tmpw = f->anglearg_start;
|
87
|
+
len = wcsnrtombs(NULL, &tmpw, f->anglearg_len, 0, NULL);
|
88
|
+
LOG("allocating %d, maxlen %d\n", len, f->anglearg_len);
|
89
|
+
|
90
|
+
cstr = calloc(len + 1, sizeof(char));
|
91
|
+
wcsnrtombs(cstr, &tmpw, f->anglearg_len, len, NULL);
|
92
|
+
LOG("wrote cstr %s\n", cstr);
|
93
|
+
|
94
|
+
LOG("symbol | cstr: '%s', len %d\n", cstr, len);
|
95
|
+
|
96
|
+
sym = rb_check_symbol_cstr(cstr, len, enc);
|
97
|
+
entry = rb_hash_lookup2(*hash, sym, Qnil);
|
98
|
+
if (entry == Qnil)
|
99
|
+
rb_raise(rb_eKeyError, "missing key :%s", cstr);
|
100
|
+
free(cstr);
|
101
|
+
|
102
|
+
return entry;
|
103
|
+
}
|
104
|
+
|
105
|
+
wchar_t *rb_apformat(wchar_t *fmt, size_t argc, size_t *argi, VALUE *argv, VALUE *hash)
|
106
|
+
{
|
107
|
+
struct fmte *f, *head;
|
108
|
+
wchar_t *final;
|
109
|
+
int loop = 1;
|
110
|
+
long *tmpi;
|
111
|
+
wint_t *tmpc;
|
112
|
+
wchar_t *tmps;
|
113
|
+
double *tmpd;
|
114
|
+
void *tmp;
|
115
|
+
VALUE entry;
|
116
|
+
|
117
|
+
head = f = parsef(&fmt);
|
118
|
+
|
119
|
+
while (loop) {
|
120
|
+
if (apf_err != apfe_none)
|
121
|
+
rb_raise(rb_eArgError, "malformed format string");
|
122
|
+
|
123
|
+
LOG("scanned type: %d\n", f->type);
|
124
|
+
|
125
|
+
if (f->type != FEnd && f->type != FRaw)
|
126
|
+
entry = get_entry(f, argc, argi, argv, hash);
|
127
|
+
else
|
128
|
+
entry = Qnil;
|
129
|
+
|
130
|
+
switch (f->type) {
|
131
|
+
case FString:
|
132
|
+
Check_Type(entry, T_STRING);
|
133
|
+
|
134
|
+
tmp = rbstowcs(entry);
|
135
|
+
goto match;
|
136
|
+
case FTern:
|
137
|
+
tmpi = malloc(sizeof(long));
|
138
|
+
|
139
|
+
*tmpi = (entry == Qfalse || entry == Qnil) ? 0 : 1;
|
140
|
+
|
141
|
+
tmp = tmpi;
|
142
|
+
goto match;
|
143
|
+
case FMul:
|
144
|
+
case FAlign:
|
145
|
+
case FInt:
|
146
|
+
Check_Type(entry, T_FIXNUM);
|
147
|
+
|
148
|
+
tmpi = malloc(sizeof(long));
|
149
|
+
*tmpi = FIX2LONG(entry);
|
150
|
+
tmp = tmpi;
|
151
|
+
goto match;
|
152
|
+
case FChar:
|
153
|
+
Check_Type(entry, T_STRING);
|
154
|
+
|
155
|
+
tmpc = malloc(sizeof(wint_t));
|
156
|
+
tmps = rbstowcs(entry);
|
157
|
+
*tmpc = btowc(tmps[0]);
|
158
|
+
tmp = tmpc;
|
159
|
+
goto match;
|
160
|
+
case FDouble:
|
161
|
+
Check_Type(entry, T_FLOAT);
|
162
|
+
|
163
|
+
tmpd = malloc(sizeof(double));
|
164
|
+
*tmpd = RFLOAT_VALUE(entry);
|
165
|
+
tmp = tmpd;
|
166
|
+
match:
|
167
|
+
f->value = tmp;
|
168
|
+
break;
|
169
|
+
case FRaw:
|
170
|
+
break;
|
171
|
+
case FEnd:
|
172
|
+
LOG("EOS (end of string)\n");
|
173
|
+
loop = 0;
|
174
|
+
break;
|
175
|
+
case FNone:
|
176
|
+
LOG("error! shouldn' t be none\n");
|
177
|
+
break;
|
178
|
+
}
|
179
|
+
|
180
|
+
LOG("pushing fmt\n");
|
181
|
+
#ifdef DEBUG
|
182
|
+
fmte_inspect(f);
|
183
|
+
#endif
|
184
|
+
fmte_push(head, f);
|
185
|
+
if (loop)
|
186
|
+
f = parsef(&fmt);
|
187
|
+
}
|
188
|
+
|
189
|
+
LOG("got all fmt elements\n");
|
190
|
+
final = assemble_fmt(head);
|
191
|
+
fmte_destroy(head);
|
192
|
+
return final;
|
193
|
+
}
|
194
|
+
|
195
|
+
VALUE rb_altprintf(long passes, size_t argc, VALUE *argv, VALUE self)
|
196
|
+
{
|
197
|
+
VALUE fmt, args, hash, final;
|
198
|
+
wchar_t *wfmt;
|
199
|
+
wchar_t *formatted;
|
200
|
+
size_t argi;
|
201
|
+
|
202
|
+
apf_err = apfe_none;
|
203
|
+
rb_scan_args(argc, argv, "1*:", &fmt, &args, &hash);
|
204
|
+
argc--;
|
205
|
+
|
206
|
+
if (hash == Qnil && RB_TYPE_P(argv[argc - 1], T_HASH)) {
|
207
|
+
hash = argv[argc - 1];
|
208
|
+
argc--;
|
209
|
+
}
|
210
|
+
|
211
|
+
if (passes == 0)
|
212
|
+
return fmt;
|
213
|
+
|
214
|
+
wfmt = rbstowcs(fmt);
|
215
|
+
formatted = NULL;
|
216
|
+
|
217
|
+
argi = 0;
|
218
|
+
for (; passes > 0; passes--) {
|
219
|
+
LOG("wfmt: %ls\n", wfmt);
|
220
|
+
|
221
|
+
formatted = rb_apformat(wfmt, argc, &argi, &args, &hash);
|
222
|
+
|
223
|
+
LOG("formatted result: '%ls'\n", formatted);
|
224
|
+
|
225
|
+
free(wfmt);
|
226
|
+
wfmt = formatted;
|
227
|
+
}
|
228
|
+
|
229
|
+
|
230
|
+
LOG("final: '%ls'\n", formatted);
|
231
|
+
final = wcstorbs(formatted);
|
232
|
+
|
233
|
+
free(formatted);
|
234
|
+
|
235
|
+
return final;
|
236
|
+
}
|
237
|
+
|
238
|
+
VALUE rb_altprintf_single_pass(size_t argc, VALUE *argv, VALUE self)
|
239
|
+
{
|
240
|
+
return rb_altprintf(1, argc, argv, self);
|
241
|
+
}
|
242
|
+
|
243
|
+
VALUE rb_altprintf_multi_pass(size_t argc, VALUE *argv, VALUE self)
|
244
|
+
{
|
245
|
+
long passes;
|
246
|
+
|
247
|
+
Check_Type(argv[0], T_FIXNUM);
|
248
|
+
passes = FIX2LONG(argv[0]);
|
249
|
+
if (passes < 0)
|
250
|
+
rb_raise(rb_eArgError, "expected positive number of passes");
|
251
|
+
|
252
|
+
LOG("passes: %ld\n", passes);
|
253
|
+
return rb_altprintf(passes, argc - 1, &argv[1], self);
|
254
|
+
}
|
255
|
+
|
256
|
+
void Init_altprintf()
|
257
|
+
{
|
258
|
+
VALUE mod, ver;
|
259
|
+
size_t len;
|
260
|
+
|
261
|
+
enc = rb_enc_find("UTF-8");
|
262
|
+
mod = rb_define_module(MODNAME);
|
263
|
+
|
264
|
+
len = strlen(ALTPRINTF_VERSION);
|
265
|
+
ver = rb_external_str_new_with_enc(ALTPRINTF_VERSION, len, enc);
|
266
|
+
rb_define_const(mod, "LIB_VERSION", ver);
|
267
|
+
|
268
|
+
rb_define_module_function(mod, "fmt", rb_altprintf_single_pass, -1);
|
269
|
+
rb_define_module_function(mod, "fmtm", rb_altprintf_multi_pass, -1);
|
270
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
module ExtconfHelper
|
4
|
+
BASE_DIR = File.join(__dir__, '../../../')
|
5
|
+
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def dev_header
|
9
|
+
find_header('altprintf.h', File.join(BASE_DIR, 'src'))
|
10
|
+
end
|
11
|
+
|
12
|
+
def dev_objs(folder = 'release')
|
13
|
+
$objs = Dir[File.join(BASE_DIR, "target/#{folder}/*.o")] + ['ext.o']
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup(mode = 'release')
|
17
|
+
puts "extconf setting up #{mode}"
|
18
|
+
case mode
|
19
|
+
when 'release'
|
20
|
+
# do nothing
|
21
|
+
when 'dev'
|
22
|
+
dev_header
|
23
|
+
dev_objs('release')
|
24
|
+
when 'debug'
|
25
|
+
dev_header
|
26
|
+
$defs.push("-DDEBUG")
|
27
|
+
dev_objs('debug')
|
28
|
+
else
|
29
|
+
raise(ArgumentError, "invalid mode #{mode}")
|
30
|
+
end
|
31
|
+
|
32
|
+
create_header
|
33
|
+
create_makefile('altprintf')
|
34
|
+
end
|
35
|
+
end
|
data/ext/altprintf/fmt.c
ADDED
@@ -0,0 +1,243 @@
|
|
1
|
+
#include "fmt.h"
|
2
|
+
|
3
|
+
#define BUFNUM 25
|
4
|
+
|
5
|
+
#define CHECKNULL(p) if (p == NULL) { apf_err = apfe_missing_argument; return; }
|
6
|
+
|
7
|
+
enum altprintf_err apf_err;
|
8
|
+
|
9
|
+
void fmt_mul(struct strbuf *sb, struct fmte *f)
|
10
|
+
{
|
11
|
+
CHECKNULL(f->value);
|
12
|
+
|
13
|
+
long *i;
|
14
|
+
|
15
|
+
i = f->value;
|
16
|
+
if (f->parenarg_start == NULL)
|
17
|
+
strbuf_pad(sb, f->chararg, *i);
|
18
|
+
else
|
19
|
+
for (int j = 0; j < *i; j++)
|
20
|
+
strbuf_append_str(sb, f->parenarg_start, -f->parenarg_len);
|
21
|
+
}
|
22
|
+
|
23
|
+
void fmt_tern(struct strbuf *sb, struct fmte *f)
|
24
|
+
{
|
25
|
+
CHECKNULL(f->parenarg_start);
|
26
|
+
CHECKNULL(f->value);
|
27
|
+
|
28
|
+
long int *b = f->value;
|
29
|
+
int first_half = 1;
|
30
|
+
wchar_t sep = f->chararg;
|
31
|
+
wchar_t *p = f->parenarg_start;
|
32
|
+
for (; p <= f->parenarg_end; p++) {
|
33
|
+
LOG("*p: %lc, first half? %d, bool: %ld, sep: %lc\n", (wint_t)*p, first_half, *b, (wint_t)sep);
|
34
|
+
if (*p == sep)
|
35
|
+
first_half = 0;
|
36
|
+
else if (*b && first_half)
|
37
|
+
strbuf_append_char(sb, p);
|
38
|
+
else if (!*b && !first_half)
|
39
|
+
strbuf_append_char(sb, p);
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
wchar_t process_escape_seq(wchar_t seq)
|
44
|
+
{
|
45
|
+
switch (seq) {
|
46
|
+
case FS_ESC_NL:
|
47
|
+
return L'\n';
|
48
|
+
case FS_ESC_ESC:
|
49
|
+
return L'\e';
|
50
|
+
case 'a':
|
51
|
+
return L'\a';
|
52
|
+
case 'b':
|
53
|
+
return L'\b';
|
54
|
+
case 'f':
|
55
|
+
return L'\f';
|
56
|
+
case 'r':
|
57
|
+
return L'\r';
|
58
|
+
case 't':
|
59
|
+
return L'\t';
|
60
|
+
case 'v':
|
61
|
+
return L'\v';
|
62
|
+
default:
|
63
|
+
return seq;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
void fmt_raw(struct strbuf *sb, struct fmte *f)
|
68
|
+
{
|
69
|
+
CHECKNULL(f->parenarg_start);
|
70
|
+
|
71
|
+
wchar_t *p;
|
72
|
+
wchar_t c;
|
73
|
+
long i;
|
74
|
+
|
75
|
+
p = f->parenarg_start;
|
76
|
+
i = f->parenarg_len;
|
77
|
+
|
78
|
+
for (; i > 0; i--) {
|
79
|
+
LOG("p is '%lc' (%ld)\n", (wint_t)*p, (long)*p);
|
80
|
+
c = (i > 1 && *p == FS_ESC) ? process_escape_seq(*++p) : *p;
|
81
|
+
|
82
|
+
strbuf_append(sb, c);
|
83
|
+
p++;
|
84
|
+
if (*p == EOS)
|
85
|
+
break;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
void fmt_string(struct strbuf *sb, struct fmte *f)
|
90
|
+
{
|
91
|
+
CHECKNULL(f->value);
|
92
|
+
|
93
|
+
int prec = f->prec == -1 ? 100000000 : f->prec;
|
94
|
+
strbuf_append_str(sb, f->value, prec);
|
95
|
+
}
|
96
|
+
|
97
|
+
void fmt_char(struct strbuf *sb, struct fmte *f)
|
98
|
+
{
|
99
|
+
CHECKNULL(f->value);
|
100
|
+
strbuf_append_char(sb, f->value);
|
101
|
+
}
|
102
|
+
|
103
|
+
void fmt_int(struct strbuf *sb, struct fmte *f)
|
104
|
+
{
|
105
|
+
CHECKNULL(f->value);
|
106
|
+
strbuf_append_int(sb, f->value);
|
107
|
+
}
|
108
|
+
|
109
|
+
void fmt_double(struct strbuf *sb, struct fmte *f)
|
110
|
+
{
|
111
|
+
CHECKNULL(f->value);
|
112
|
+
int prec = f->prec == -1 ? 3 : f->prec;
|
113
|
+
strbuf_append_double(sb, f->value, prec);
|
114
|
+
}
|
115
|
+
|
116
|
+
void fmt(struct strbuf *sb, struct fmte *f, void (*fmtr)(struct strbuf *, struct fmte *))
|
117
|
+
{
|
118
|
+
struct strbuf *tmp = strbuf_new();
|
119
|
+
|
120
|
+
fmtr(tmp, f);
|
121
|
+
|
122
|
+
if (tmp->len == 0) {
|
123
|
+
strbuf_destroy(tmp);
|
124
|
+
return;
|
125
|
+
}
|
126
|
+
|
127
|
+
int pad = f->pad > 0 ? f->pad - strbuf_width(tmp) : 0;
|
128
|
+
|
129
|
+
if (pad > 0) {
|
130
|
+
LOG("padding: %d\n", pad);
|
131
|
+
switch (f->align) {
|
132
|
+
case Right:
|
133
|
+
strbuf_append_strbuf(sb, tmp);
|
134
|
+
strbuf_pad(sb, f->padchar, pad);
|
135
|
+
break;
|
136
|
+
case Left:
|
137
|
+
strbuf_pad(sb, f->padchar, pad);
|
138
|
+
strbuf_append_strbuf(sb, tmp);
|
139
|
+
break;
|
140
|
+
case Center:
|
141
|
+
strbuf_pad(sb, f->padchar, pad / 2);
|
142
|
+
strbuf_append_strbuf(sb, tmp);
|
143
|
+
strbuf_pad(sb, f->padchar, pad / 2 + pad % 2);
|
144
|
+
break;
|
145
|
+
}
|
146
|
+
} else {
|
147
|
+
strbuf_append_strbuf(sb, tmp);
|
148
|
+
}
|
149
|
+
|
150
|
+
strbuf_destroy(tmp);
|
151
|
+
}
|
152
|
+
|
153
|
+
wchar_t *assemble_fmt(struct fmte *head)
|
154
|
+
{
|
155
|
+
struct fmte *f = head;
|
156
|
+
struct strbuf *bufs[BUFNUM];
|
157
|
+
struct fmte *splits[BUFNUM];
|
158
|
+
size_t buf = 0, i;
|
159
|
+
size_t w, tw, rw;
|
160
|
+
wchar_t *final;
|
161
|
+
|
162
|
+
void (*fmtr)(struct strbuf *, struct fmte *) = NULL;
|
163
|
+
int loop = 1;
|
164
|
+
|
165
|
+
bufs[buf] = strbuf_new();
|
166
|
+
|
167
|
+
LOG("assembling elements\n");
|
168
|
+
while (loop) {
|
169
|
+
switch (f->type) {
|
170
|
+
case FMul:
|
171
|
+
fmtr = fmt_mul;
|
172
|
+
break;
|
173
|
+
case FTern:
|
174
|
+
fmtr = fmt_tern;
|
175
|
+
break;
|
176
|
+
case FInt:
|
177
|
+
fmtr = fmt_int;
|
178
|
+
break;
|
179
|
+
case FChar:
|
180
|
+
fmtr = fmt_char;
|
181
|
+
break;
|
182
|
+
case FDouble:
|
183
|
+
fmtr = fmt_double;
|
184
|
+
break;
|
185
|
+
case FString:
|
186
|
+
fmtr = fmt_string;
|
187
|
+
break;
|
188
|
+
case FRaw:
|
189
|
+
fmtr = fmt_raw;
|
190
|
+
break;
|
191
|
+
|
192
|
+
case FAlign:
|
193
|
+
buf++;
|
194
|
+
splits[buf] = f;
|
195
|
+
bufs[buf] = strbuf_new();
|
196
|
+
fmtr = NULL;
|
197
|
+
break;
|
198
|
+
case FEnd:
|
199
|
+
loop = 0;
|
200
|
+
fmtr = NULL;
|
201
|
+
break;
|
202
|
+
case FNone:
|
203
|
+
fmtr = NULL;
|
204
|
+
break;
|
205
|
+
}
|
206
|
+
|
207
|
+
if (fmtr != NULL)
|
208
|
+
fmt(bufs[buf], f, fmtr);
|
209
|
+
f = f->next;
|
210
|
+
}
|
211
|
+
|
212
|
+
// Assemble splits
|
213
|
+
LOG("assembling %d splits\n", buf);
|
214
|
+
if (buf > 0)
|
215
|
+
tw = strbuf_width(bufs[0]);
|
216
|
+
for (i = 1; i <= buf; i++) {
|
217
|
+
rw = *(long*)splits[i]->value;
|
218
|
+
|
219
|
+
if (tw > rw) {
|
220
|
+
LOG("trimming first half to width\n");
|
221
|
+
strbuf_destroy(bufs[i]);
|
222
|
+
bufs[i] = bufs[0];
|
223
|
+
bufs[0] = strbuf_new();
|
224
|
+
strbuf_appendw_strbuf(bufs[0], bufs[i], rw);
|
225
|
+
} else {
|
226
|
+
if (rw > strbuf_width(bufs[i]) + tw) {
|
227
|
+
w = rw - (strbuf_width(bufs[i]) + tw);
|
228
|
+
LOG("padding %d\n", w);
|
229
|
+
strbuf_pad(bufs[0], splits[i]->chararg, w);
|
230
|
+
strbuf_append_strbuf(bufs[0], bufs[i]);
|
231
|
+
} else {
|
232
|
+
LOG("%d %d %d\n", w, rw, tw);
|
233
|
+
strbuf_appendw_strbuf(bufs[0], bufs[i], rw - tw);
|
234
|
+
}
|
235
|
+
}
|
236
|
+
|
237
|
+
tw = rw;
|
238
|
+
}
|
239
|
+
|
240
|
+
final = strbuf_cstr(bufs[0]);
|
241
|
+
for (i = 0; i <= buf; i++) strbuf_destroy(bufs[i]);
|
242
|
+
return final;
|
243
|
+
}
|
data/ext/altprintf/fmt.h
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
#include "fmte.h"
|
2
|
+
|
3
|
+
struct fmte *fmte_ini()
|
4
|
+
{
|
5
|
+
struct fmte *f = malloc(sizeof(struct fmte));
|
6
|
+
|
7
|
+
f->parenarg_start = NULL;
|
8
|
+
f->parenarg_end = NULL;
|
9
|
+
f->parenarg_len = 0;
|
10
|
+
|
11
|
+
f->anglearg_start = NULL;
|
12
|
+
f->anglearg_end = NULL;
|
13
|
+
f->anglearg_len = 0;
|
14
|
+
|
15
|
+
f->chararg = L' ';
|
16
|
+
f->padchar = L' ';
|
17
|
+
f->type = FNone;
|
18
|
+
f->align = Right;
|
19
|
+
f->prec = -1;
|
20
|
+
f->pad = 0;
|
21
|
+
f->value = NULL;
|
22
|
+
|
23
|
+
f->next = NULL;
|
24
|
+
|
25
|
+
return f;
|
26
|
+
}
|
27
|
+
|
28
|
+
void fmte_push(struct fmte *a, struct fmte *b)
|
29
|
+
{
|
30
|
+
if (a == b)
|
31
|
+
return; // refuse to create an infinite loop
|
32
|
+
|
33
|
+
while (a->next != NULL) a = a->next;
|
34
|
+
|
35
|
+
a->next = b;
|
36
|
+
}
|
37
|
+
|
38
|
+
void fmte_destroy(struct fmte *f)
|
39
|
+
{
|
40
|
+
struct fmte *j;
|
41
|
+
|
42
|
+
while (f != NULL) {
|
43
|
+
j = f->next;
|
44
|
+
free(f->value);
|
45
|
+
free(f);
|
46
|
+
f = j;
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
void fmte_inspect(struct fmte *f)
|
51
|
+
{
|
52
|
+
wchar_t *parenarg = calloc(f->parenarg_len + 1, sizeof(wchar_t));
|
53
|
+
wchar_t *anglearg = calloc(f->anglearg_len + 1, sizeof(wchar_t));
|
54
|
+
size_t i;
|
55
|
+
|
56
|
+
for (i = 0; i < f->parenarg_len; i++) parenarg[i] = f->parenarg_start[i];
|
57
|
+
for (i = 0; i < f->anglearg_len; i++) anglearg[i] = f->anglearg_start[i];
|
58
|
+
|
59
|
+
printf(
|
60
|
+
"Format@%p {\n\
|
61
|
+
parenarg_start: %p,\n\
|
62
|
+
parenarg_end: %p,\n\
|
63
|
+
parenarg_len: %ld,\n\
|
64
|
+
(parenarg): %ls,\n\
|
65
|
+
anglearg_start: %p,\n\
|
66
|
+
anglearg_end: %p,\n\
|
67
|
+
anglearg_len: %ld,\n\
|
68
|
+
(anglearg): %ls,\n\
|
69
|
+
chararg: %lc,\n\
|
70
|
+
padchar: %lc,\n\
|
71
|
+
type: %d,\n\
|
72
|
+
align: %d,\n\
|
73
|
+
prec: %ld,\n\
|
74
|
+
pad: %ld,\n\
|
75
|
+
value: %p,\n\
|
76
|
+
next: %p\n\
|
77
|
+
}\n",
|
78
|
+
f,
|
79
|
+
f->parenarg_start,
|
80
|
+
f->parenarg_end,
|
81
|
+
(unsigned long)f->parenarg_len,
|
82
|
+
parenarg,
|
83
|
+
f->anglearg_start,
|
84
|
+
f->anglearg_end,
|
85
|
+
(unsigned long)f->anglearg_len,
|
86
|
+
anglearg,
|
87
|
+
f->chararg,
|
88
|
+
f->padchar,
|
89
|
+
f->type,
|
90
|
+
f->align,
|
91
|
+
f->prec,
|
92
|
+
f->pad,
|
93
|
+
f->value,
|
94
|
+
f->next);
|
95
|
+
|
96
|
+
free(parenarg);
|
97
|
+
free(anglearg);
|
98
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#ifndef FMTE_H_
|
2
|
+
#define FMTE_H_
|
3
|
+
#include <wchar.h>
|
4
|
+
#include <stdlib.h>
|
5
|
+
#include <stdio.h>
|
6
|
+
#include "enums.h"
|
7
|
+
#include "log.h"
|
8
|
+
|
9
|
+
struct fmte {
|
10
|
+
wchar_t *parenarg_start;
|
11
|
+
wchar_t *parenarg_end;
|
12
|
+
size_t parenarg_len;
|
13
|
+
|
14
|
+
wchar_t *anglearg_start;
|
15
|
+
wchar_t *anglearg_end;
|
16
|
+
size_t anglearg_len;
|
17
|
+
|
18
|
+
wint_t chararg;
|
19
|
+
|
20
|
+
wint_t padchar;
|
21
|
+
|
22
|
+
enum arg_type type;
|
23
|
+
enum align align;
|
24
|
+
|
25
|
+
long prec;
|
26
|
+
long pad;
|
27
|
+
|
28
|
+
void *value;
|
29
|
+
|
30
|
+
struct fmte *next;
|
31
|
+
};
|
32
|
+
|
33
|
+
struct fmte *fmte_ini();
|
34
|
+
void fmte_inspect(struct fmte *);
|
35
|
+
void fmte_push(struct fmte *, struct fmte *);
|
36
|
+
void fmte_destroy(struct fmte *);
|
37
|
+
#endif
|
data/ext/altprintf/log.h
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#ifndef LOG_H
|
2
|
+
#define LOG_H
|
3
|
+
|
4
|
+
#ifdef DEBUG
|
5
|
+
#define LOG(...) printf("%s:%d [\e[35m%s\e[0m] ", __FILE__, __LINE__, __func__); printf(__VA_ARGS__);
|
6
|
+
#define FLOG(msg, ...) fprintf(stderr, "%s[%d] - "msg, __FILE__, __LINE__ __VA_OPT__(, ) __VA_ARGS__)
|
7
|
+
#else
|
8
|
+
#define LOG(msg, ...)
|
9
|
+
#define FLOG(msg, ...)
|
10
|
+
#endif
|
11
|
+
|
12
|
+
#endif
|
@@ -0,0 +1,127 @@
|
|
1
|
+
#include "parsef.h"
|
2
|
+
|
3
|
+
wchar_t *altprintf_pct = L"%";
|
4
|
+
|
5
|
+
struct fmte *parsef(wchar_t **fmt)
|
6
|
+
{
|
7
|
+
wchar_t *w_c;
|
8
|
+
wchar_t **w_a = &w_c;
|
9
|
+
struct fmte *f = fmte_ini();
|
10
|
+
long *l_a = &f->pad;
|
11
|
+
|
12
|
+
LOG("processing %ld (%lc)\n", **fmt, (wint_t)**fmt);
|
13
|
+
|
14
|
+
if (**fmt != FS_START) {
|
15
|
+
if (**fmt == EOS) {
|
16
|
+
f->type = FEnd;
|
17
|
+
goto return_format;
|
18
|
+
}
|
19
|
+
|
20
|
+
LOG("building raw format\n");
|
21
|
+
f->type = FRaw;
|
22
|
+
|
23
|
+
f->parenarg_start = *fmt;
|
24
|
+
LOG("scanning long arg\n");
|
25
|
+
get_longarg(fmt, &f->parenarg_end, FS_START, &f->parenarg_len);
|
26
|
+
|
27
|
+
f->parenarg_end++;
|
28
|
+
f->parenarg_len++;
|
29
|
+
(*fmt)--;
|
30
|
+
|
31
|
+
goto return_format;
|
32
|
+
} else {
|
33
|
+
LOG("building format\n");
|
34
|
+
(*fmt)++;
|
35
|
+
}
|
36
|
+
|
37
|
+
for (; **fmt != L'\0'; (*fmt)++) {
|
38
|
+
LOG("scanned char '%lc'\n", (wint_t)(**fmt));
|
39
|
+
switch (**fmt) {
|
40
|
+
case FS_A_CHARARG:
|
41
|
+
(*fmt)++;
|
42
|
+
f->chararg = **fmt;
|
43
|
+
break;
|
44
|
+
case FS_A_ANGLEARG_S:
|
45
|
+
f->anglearg_start = *fmt + 1;
|
46
|
+
get_longarg(fmt, &f->anglearg_end, FS_A_ANGLEARG_E, &f->anglearg_len);
|
47
|
+
break;
|
48
|
+
case FS_A_PARENARG_S:
|
49
|
+
f->parenarg_start = *fmt + 1;
|
50
|
+
get_longarg(fmt, &f->parenarg_end, FS_A_PARENARG_E, &f->parenarg_len);
|
51
|
+
break;
|
52
|
+
case FS_A_LALIGN:
|
53
|
+
f->align = Left;
|
54
|
+
break;
|
55
|
+
case FS_A_CALIGN:
|
56
|
+
f->align = Center;
|
57
|
+
break;
|
58
|
+
case FS_A_SPAD:
|
59
|
+
f->padchar = FS_A_SPAD;
|
60
|
+
break;
|
61
|
+
case FS_A_ZPAD:
|
62
|
+
f->padchar = '0';
|
63
|
+
break;
|
64
|
+
case FS_A_PREC:
|
65
|
+
l_a = &f->prec;
|
66
|
+
break;
|
67
|
+
case '1': case '2': case '3': case '4': case '5':
|
68
|
+
case '6': case '7': case '8': case '9':
|
69
|
+
LOG("l_a: %p %ld\n", l_a, *l_a);
|
70
|
+
*l_a = wcstol(*fmt, w_a, 10);
|
71
|
+
*fmt = *w_a - 1;
|
72
|
+
break;
|
73
|
+
// Psuedo-type
|
74
|
+
case FS_START:
|
75
|
+
f->type = FRaw;
|
76
|
+
f->parenarg_start = &altprintf_pct[0];
|
77
|
+
f->parenarg_end = &altprintf_pct[1];
|
78
|
+
f->parenarg_len = 1;
|
79
|
+
goto return_format;
|
80
|
+
// Types
|
81
|
+
case FS_T_STRING:
|
82
|
+
f->type = FString;
|
83
|
+
goto return_format;
|
84
|
+
case FS_T_MUL:
|
85
|
+
f->type = FMul;
|
86
|
+
goto return_format;
|
87
|
+
case FS_T_TERN:
|
88
|
+
f->type = FTern;
|
89
|
+
goto return_format;
|
90
|
+
case FS_T_ALIGN:
|
91
|
+
f->type = FAlign;
|
92
|
+
goto return_format;
|
93
|
+
case FS_T_INT:
|
94
|
+
f->type = FInt;
|
95
|
+
goto return_format;
|
96
|
+
case FS_T_CHAR:
|
97
|
+
f->type = FChar;
|
98
|
+
goto return_format;
|
99
|
+
case FS_T_DOUBLE:
|
100
|
+
f->type = FDouble;
|
101
|
+
goto return_format;
|
102
|
+
default:
|
103
|
+
apf_err = apfe_invalid_token;
|
104
|
+
f->type = FRaw;
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
f->type = FEnd;
|
109
|
+
return_format:
|
110
|
+
(*fmt)++;
|
111
|
+
return f;
|
112
|
+
}
|
113
|
+
|
114
|
+
void get_longarg(wchar_t **s, wchar_t **e, wchar_t stop, size_t *size)
|
115
|
+
{
|
116
|
+
*size = 0;
|
117
|
+
|
118
|
+
while (**s != EOS && **s != stop) {
|
119
|
+
LOG("checking (%lc)\n", (wint_t)**s);
|
120
|
+
(*s)++;
|
121
|
+
(*size)++;
|
122
|
+
}
|
123
|
+
|
124
|
+
(*size)--;
|
125
|
+
if (*size > 0)
|
126
|
+
*e = *s - 1;
|
127
|
+
}
|
@@ -0,0 +1,178 @@
|
|
1
|
+
#include "strbuf.h"
|
2
|
+
|
3
|
+
extern struct lconv *locale_info;
|
4
|
+
|
5
|
+
struct strbuf *strbuf_new()
|
6
|
+
{
|
7
|
+
struct strbuf *sb = malloc(sizeof(struct strbuf));
|
8
|
+
|
9
|
+
if (NULL == sb) {
|
10
|
+
LOG("can't alloc memory for new strbuf\n");
|
11
|
+
exit(1);
|
12
|
+
}
|
13
|
+
|
14
|
+
sb->start = sb->end = calloc(STRBUF_INI_SIZE, sizeof(wchar_t));
|
15
|
+
|
16
|
+
if (NULL == sb->start) {
|
17
|
+
LOG("can't alloc memory for new strbuf string\n");
|
18
|
+
exit(1);
|
19
|
+
}
|
20
|
+
|
21
|
+
sb->len = 0;
|
22
|
+
sb->cap = STRBUF_INI_SIZE;
|
23
|
+
sb->width = 0;
|
24
|
+
return sb;
|
25
|
+
}
|
26
|
+
|
27
|
+
size_t strbuf_width(struct strbuf *sb)
|
28
|
+
{
|
29
|
+
if (sb->width == 0)
|
30
|
+
sb->width = wcswidth(sb->start, sb->len);
|
31
|
+
|
32
|
+
return sb->width;
|
33
|
+
}
|
34
|
+
|
35
|
+
void strbuf_destroy(struct strbuf *sb)
|
36
|
+
{
|
37
|
+
free(sb->start);
|
38
|
+
free(sb);
|
39
|
+
}
|
40
|
+
|
41
|
+
void strbuf_append(struct strbuf *sb, wchar_t c)
|
42
|
+
{
|
43
|
+
wchar_t *ns;
|
44
|
+
|
45
|
+
if (sb->cap < sb->len + 2) {
|
46
|
+
ns = calloc(sb->cap + STRBUF_GROW_STEP, sizeof(wchar_t));
|
47
|
+
|
48
|
+
if (ns == NULL) {
|
49
|
+
LOG("can't increase size of strbuf to %d\n", sb->cap + STRBUF_GROW_STEP);
|
50
|
+
exit(1);
|
51
|
+
}
|
52
|
+
|
53
|
+
wcscpy(ns, sb->start);
|
54
|
+
free(sb->start);
|
55
|
+
|
56
|
+
sb->start = ns;
|
57
|
+
sb->cap += STRBUF_GROW_STEP;
|
58
|
+
}
|
59
|
+
|
60
|
+
sb->start[sb->len] = c;
|
61
|
+
sb->start[sb->len + 1] = L'\0';
|
62
|
+
LOG("string so far: %ls\n", sb->start);
|
63
|
+
sb->end = &sb->start[sb->len];
|
64
|
+
sb->len++;
|
65
|
+
}
|
66
|
+
|
67
|
+
void strbuf_append_strbuf(struct strbuf *sb, void *sbuf)
|
68
|
+
{
|
69
|
+
wchar_t *pos;
|
70
|
+
struct strbuf *frm = sbuf;
|
71
|
+
|
72
|
+
LOG("frm->start: %p | frm->end: %p\n", frm->start, frm->end);
|
73
|
+
|
74
|
+
for (pos = frm->start; pos <= frm->end; pos++)
|
75
|
+
strbuf_append(sb, *pos);
|
76
|
+
}
|
77
|
+
|
78
|
+
void strbuf_appendw_strbuf(struct strbuf *sb, void *sbuf, long w)
|
79
|
+
{
|
80
|
+
wchar_t *pos;
|
81
|
+
long ws = 0;
|
82
|
+
struct strbuf *frm = sbuf;
|
83
|
+
|
84
|
+
LOG("frm->start: %p | frm->end: %p\n", frm->start, frm->end);
|
85
|
+
|
86
|
+
for (pos = frm->start; pos <= frm->end; pos++) {
|
87
|
+
ws += wcwidth(*pos);
|
88
|
+
LOG("new width would be: %ld, requested width: %ld\n", ws, w);
|
89
|
+
if (ws > w)
|
90
|
+
break;
|
91
|
+
strbuf_append(sb, *pos);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
void strbuf_append_char(struct strbuf *sb, void *chr)
|
96
|
+
{
|
97
|
+
wint_t *c = chr;
|
98
|
+
|
99
|
+
strbuf_append(sb, *c);
|
100
|
+
}
|
101
|
+
|
102
|
+
void strbuf_append_str(struct strbuf *sb, void *str, int maxwidth)
|
103
|
+
{
|
104
|
+
wchar_t *s = str;
|
105
|
+
wchar_t *end = &s[wcslen(s)];
|
106
|
+
int width = 0;
|
107
|
+
int maxlen = -1;
|
108
|
+
|
109
|
+
if (maxwidth < 0)
|
110
|
+
maxlen = maxwidth * -1;
|
111
|
+
|
112
|
+
for (; s < end; s++) {
|
113
|
+
if (maxlen >= 0) {
|
114
|
+
width++;
|
115
|
+
if (width > maxlen)
|
116
|
+
return;
|
117
|
+
} else {
|
118
|
+
width += wcwidth(*s);
|
119
|
+
if (width > maxwidth)
|
120
|
+
return;
|
121
|
+
}
|
122
|
+
|
123
|
+
strbuf_append(sb, *s);
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
void strbuf_append_int(struct strbuf *sb, void *in)
|
128
|
+
{
|
129
|
+
long int *i = in;
|
130
|
+
wchar_t wcs[TMPLEN];
|
131
|
+
long len = swprintf(wcs, TMPLEN - 1, L"%ld", *i);
|
132
|
+
|
133
|
+
if (len < 0)
|
134
|
+
strbuf_append_str(sb, L"error adding int", 16);
|
135
|
+
else
|
136
|
+
strbuf_append_str(sb, wcs, -1 * len);
|
137
|
+
}
|
138
|
+
|
139
|
+
void strbuf_append_double(struct strbuf *sb, void *dub, int prec)
|
140
|
+
{
|
141
|
+
double *d = dub;
|
142
|
+
wchar_t wcs[TMPLEN];
|
143
|
+
wchar_t format[TMPLEN];
|
144
|
+
int rprec = prec;
|
145
|
+
|
146
|
+
if (rprec > MAXPREC)
|
147
|
+
rprec = MAXPREC;
|
148
|
+
|
149
|
+
swprintf(format, TMPLEN - 1, L"%%.%ldf", rprec);
|
150
|
+
|
151
|
+
LOG("format: %ls\n", format);
|
152
|
+
|
153
|
+
long len = swprintf(wcs, TMPLEN - 1, format, *d);
|
154
|
+
if (len < 0) {
|
155
|
+
strbuf_append_str(sb, L"error adding float", 18);
|
156
|
+
} else {
|
157
|
+
LOG("inserting double: len: %ld\n", len);
|
158
|
+
strbuf_append_str(sb, wcs, len);
|
159
|
+
|
160
|
+
if (rprec < prec)
|
161
|
+
strbuf_pad(sb, L'0', rprec - prec);
|
162
|
+
}
|
163
|
+
}
|
164
|
+
|
165
|
+
void strbuf_pad(struct strbuf *sb, wchar_t pc, int amnt)
|
166
|
+
{
|
167
|
+
for (; amnt > 0; amnt--) strbuf_append(sb, pc);
|
168
|
+
}
|
169
|
+
|
170
|
+
wchar_t *strbuf_cstr(struct strbuf *sb)
|
171
|
+
{
|
172
|
+
wchar_t *str;
|
173
|
+
|
174
|
+
str = calloc(sb->len + 1, sizeof(wchar_t));
|
175
|
+
wcscpy(str, sb->start);
|
176
|
+
|
177
|
+
return str;
|
178
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#ifndef STRBUF_H
|
2
|
+
#define STRBUF_H
|
3
|
+
|
4
|
+
#ifndef _XOPEN_SOURCE
|
5
|
+
#define _XOPEN_SOURCE
|
6
|
+
#endif
|
7
|
+
|
8
|
+
#include <wchar.h>
|
9
|
+
#include <stdlib.h>
|
10
|
+
#include <stdio.h>
|
11
|
+
#include "log.h"
|
12
|
+
|
13
|
+
#define STRBUF_INI_SIZE 5
|
14
|
+
#define STRBUF_GROW_STEP 100
|
15
|
+
#define TMPLEN 50
|
16
|
+
#define MAXPREC 25
|
17
|
+
|
18
|
+
struct strbuf *strbuf_new();
|
19
|
+
void strbuf_destroy(struct strbuf *sb);
|
20
|
+
void strbuf_append(struct strbuf *sb, wchar_t);
|
21
|
+
void strbuf_append_char(struct strbuf *sb, void *);
|
22
|
+
void strbuf_append_str(struct strbuf *, void *, int);
|
23
|
+
void strbuf_append_int(struct strbuf *sb, void *);
|
24
|
+
void strbuf_append_double(struct strbuf *, void *, int);
|
25
|
+
void strbuf_append_strbuf(struct strbuf *, void *);
|
26
|
+
void strbuf_appendw_strbuf(struct strbuf *, void *, long);
|
27
|
+
void strbuf_pad(struct strbuf *, wchar_t, int);
|
28
|
+
wchar_t *strbuf_cstr(struct strbuf *);
|
29
|
+
size_t strbuf_width(struct strbuf *);
|
30
|
+
|
31
|
+
struct strbuf {
|
32
|
+
wchar_t *start;
|
33
|
+
wchar_t *end;
|
34
|
+
size_t len;
|
35
|
+
size_t width;
|
36
|
+
size_t cap;
|
37
|
+
};
|
38
|
+
#endif
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#ifndef SYNTAX_H
|
2
|
+
#define SYNTAX_H
|
3
|
+
|
4
|
+
#define FS_START '%'
|
5
|
+
#define FS_DOUBLE_SEP '.'
|
6
|
+
|
7
|
+
#define FS_ESC L'\\'
|
8
|
+
#define FS_ESC_NL 'n'
|
9
|
+
#define FS_ESC_ESC 'e'
|
10
|
+
|
11
|
+
#define FS_T_STRING 's'
|
12
|
+
#define FS_T_CHAR 'c'
|
13
|
+
#define FS_T_DOUBLE 'f'
|
14
|
+
#define FS_T_INT 'd'
|
15
|
+
#define FS_T_MUL '*'
|
16
|
+
#define FS_T_TERN '?'
|
17
|
+
#define FS_T_ALIGN '='
|
18
|
+
|
19
|
+
#define FS_A_PARENARG_S '('
|
20
|
+
#define FS_A_PARENARG_E ')'
|
21
|
+
#define FS_A_ANGLEARG_S '<'
|
22
|
+
#define FS_A_ANGLEARG_E '>'
|
23
|
+
|
24
|
+
#define FS_A_CHARARG '~'
|
25
|
+
#define FS_A_LALIGN '-'
|
26
|
+
#define FS_A_CALIGN '^'
|
27
|
+
#define FS_A_SPAD ' '
|
28
|
+
#define FS_A_ZPAD '0'
|
29
|
+
#define FS_A_PREC '.'
|
30
|
+
|
31
|
+
#define FS_D_PREC 100
|
32
|
+
|
33
|
+
#define EOS L'\0'
|
34
|
+
|
35
|
+
#endif
|
data/lib/altprintf.rb
ADDED
Binary file
|
Binary file
|
data/readme.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Altprintf
|
2
|
+
|
3
|
+
[rubygems.org/gems/altprintf](https://rubygems.org/gems/altprintf)
|
4
|
+
|
5
|
+
altprintf is a gem that wraps `../altprintf`.
|
6
|
+
|
7
|
+
It exposes the following module functions
|
8
|
+
|
9
|
+
+ `Altprintf#fmt(format_string, *args, **kwargs)`
|
10
|
+
+ `Altprintf#fmtm(passes, format_string, *args, **kwargs)`
|
11
|
+
|
12
|
+
In addition to the syntax of vanilla altprintf, the following additional
|
13
|
+
argument is accepted:
|
14
|
+
|
15
|
+
+ `<val>` - access the value of the given hash with key `val` rather than
|
16
|
+
try to read the next argument.
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: altprintf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stone Tickle
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-08-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake-compiler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '12.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '12.3'
|
41
|
+
description:
|
42
|
+
email: lattis@mochiro.moe
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- altprintf.gemspec
|
48
|
+
- ext/altprintf/altprintf.h
|
49
|
+
- ext/altprintf/enums.h
|
50
|
+
- ext/altprintf/ext.c
|
51
|
+
- ext/altprintf/extconf.h
|
52
|
+
- ext/altprintf/extconf_helper.rb
|
53
|
+
- ext/altprintf/fmt.c
|
54
|
+
- ext/altprintf/fmt.h
|
55
|
+
- ext/altprintf/fmte.c
|
56
|
+
- ext/altprintf/fmte.h
|
57
|
+
- ext/altprintf/log.h
|
58
|
+
- ext/altprintf/parsef.c
|
59
|
+
- ext/altprintf/parsef.h
|
60
|
+
- ext/altprintf/strbuf.c
|
61
|
+
- ext/altprintf/strbuf.h
|
62
|
+
- ext/altprintf/syntax.h
|
63
|
+
- lib/altprintf.rb
|
64
|
+
- lib/altprintf/alt_printf.so
|
65
|
+
- lib/altprintf/altprintf.so
|
66
|
+
- lib/altprintf/version.rb
|
67
|
+
- readme.md
|
68
|
+
homepage: https://github.com/annacrombie/altprintf/tree/master/gem
|
69
|
+
licenses:
|
70
|
+
- MIT
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 2.5.5
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubygems_version: 3.0.3
|
88
|
+
signing_key:
|
89
|
+
specification_version: 4
|
90
|
+
summary: A powerful printf-like template language
|
91
|
+
test_files: []
|