altprintf 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
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,6 @@
1
+ #ifndef ALTPRINTF_H_
2
+ #define ALTPRINTF_H_
3
+ #define ALTPRINTF_VERSION "0.2.4"
4
+ #include "parsef.h"
5
+ #include "fmt.h"
6
+ #endif
@@ -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
@@ -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
@@ -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
+ }
@@ -0,0 +1,9 @@
1
+ #ifndef FMT_H_
2
+ #define FMT_H_
3
+ #include "syntax.h"
4
+ #include "strbuf.h"
5
+ #include "fmte.h"
6
+ #include "log.h"
7
+
8
+ wchar_t *assemble_fmt(struct fmte *);
9
+ #endif
@@ -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
@@ -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,10 @@
1
+ #ifndef PARSEF_H_
2
+ #define PARSEF_H_
3
+ #include "fmte.h"
4
+ #include "syntax.h"
5
+ #include "log.h"
6
+
7
+ void get_longarg(wchar_t **, wchar_t **, wchar_t, size_t *);
8
+ struct fmte *parsef(wchar_t **);
9
+
10
+ #endif
@@ -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
@@ -0,0 +1,2 @@
1
+ require_relative 'altprintf/altprintf'
2
+ require_relative 'altprintf/version'
Binary file
Binary file
@@ -0,0 +1,3 @@
1
+ module Altprintf
2
+ VERSION = [0, 2, 4]
3
+ end
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: []