altprintf 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []