alt_printf 0.1.0

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: ca3bfbd5642eb9ee9d75ed799b3cb18708d44c2d1f57eabcf8cf9795cc54e82c
4
+ data.tar.gz: e7d66a6c4770522c112d677de2c3d88df98ddb2a0089ddd784b10063493a21cb
5
+ SHA512:
6
+ metadata.gz: fe5d82f1920848129f2bf490bb49754efd1de8b46dd7c468cc700b6a5e9d76a5b130706bcbfff1d87faa000f8a933247886bff4c2c2fdba17d5f398f7b822dac
7
+ data.tar.gz: 5fe9d231104bcfc0d5fda40924c3f55630c3981427f09ab63985432123f314250b858f2bb7dd946ae58161702abd832e2e81f4a4f06a8b58ab7f56b86a80fcfd
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # AltPrintf
2
+
3
+ AltPrintf is a gem that wraps `altprintf`.
4
+
5
+ It exposes the following module functions
6
+
7
+ + `#fmt(format_string, *args, **kwargs)`
8
+ + `#fmtm(passes, format_string, *args, **kwargs)`
9
+
10
+ In addition to the syntax of vanilla altprintf, the following additional
11
+ argument is accepted:
12
+
13
+ + `<val>` - access the value of the given hash with key `:"#{val}"` rather than
14
+ try to read the next argument.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rake/extensiontask'
2
+ require 'bundler/gem_tasks'
3
+ require 'securerandom'
4
+ require 'fileutils'
5
+
6
+ SRC_DIR = File.join(__dir__, '../src')
7
+
8
+ Rake::ExtensionTask.new('alt_printf') do |ext|
9
+ ext.lib_dir = 'lib/alt_printf'
10
+ ext.config_script = 'extconf_dev.rb'
11
+ end
12
+
13
+ task :build_gem do
14
+ tmp_dir = "/tmp/alt_printf_#{SecureRandom.hex(8)}"
15
+ puts "cloning to #{tmp_dir}"
16
+ FileUtils.mkdir(tmp_dir)
17
+
18
+ Dir[
19
+ 'Gemfile',
20
+ 'README.md',
21
+ 'Rakefile',
22
+ 'alt_printf.gemspec',
23
+ '{ext,lib}/**/*'
24
+ ].each do |f|
25
+ next if File.directory?(f)
26
+
27
+ dir = File.join(tmp_dir, File.dirname(f))
28
+ FileUtils.mkdir_p(dir)
29
+ FileUtils.cp(f, File.join(dir, File.basename(f)))
30
+ end
31
+
32
+ FileUtils.cp_r(
33
+ %w[altprintf list log strbuf syntax].map do |w|
34
+ %w[h c].map { |e| File.join(SRC_DIR, "#{w}.#{e}") }
35
+ .select { |f| File.exist?(f) }
36
+ end.flatten,
37
+ File.join(tmp_dir, 'ext/alt_printf/')
38
+ )
39
+
40
+ FileUtils.cd(tmp_dir)
41
+
42
+ sh "rake build"
43
+
44
+ FileUtils.cp(Dir['pkg/*'], File.join(__dir__, 'pkg'))
45
+ FileUtils.cd(__dir__)
46
+ FileUtils.rm_rf(tmp_dir)
47
+ end
48
+
49
+ task publish: :build_gem do
50
+ load File.join(__dir__, 'alt_printf.gemspec')
51
+ p AltPrintf
52
+ sh "gem push pkg/#{AltPrintf::SPEC.name}-#{AltPrintf::SPEC.version}.gem"
53
+ end
@@ -0,0 +1,24 @@
1
+ require 'date'
2
+ require_relative 'lib/alt_printf/version'
3
+
4
+ AltPrintf::SPEC = Gem::Specification.new do |s|
5
+ s.name = 'alt_printf'
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/alt_printf/gem'
12
+ s.license = 'MIT'
13
+
14
+ s.files = Dir['{**/*}']
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.6.3'
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,222 @@
1
+ #include <stdio.h>
2
+ #include <locale.h>
3
+ #include <wchar.h>
4
+ #include <ruby.h>
5
+ #include <ruby/encoding.h>
6
+ #include "extconf.h"
7
+ #include "list.h"
8
+ #include "altprintf.h"
9
+ #include "log.h"
10
+
11
+ #define CHECKARG \
12
+ if (!use_hash) { \
13
+ if (*argi >= argc) goto no_more_args; \
14
+ entry = rb_ary_entry(*argv, *argi); \
15
+ }
16
+
17
+ #define MODNAME "AltPrintf"
18
+
19
+ rb_encoding *enc;
20
+
21
+ wchar_t *rbstowcs(VALUE str) {
22
+ const char *cstr;
23
+ wchar_t *wstr;
24
+ size_t len;
25
+
26
+ cstr = StringValueCStr(str);
27
+
28
+ len = mbsrtowcs(NULL, &cstr, 0, NULL);
29
+ wstr = calloc(len + 1, sizeof(wchar_t));
30
+ len = mbsrtowcs(wstr, &cstr, len, NULL);
31
+
32
+ LOG("rbs to wcs, len: %d, cstr: '%s'\n", len, cstr);
33
+ LOG("wide string: '%ls'\n", wstr);
34
+
35
+ return wstr;
36
+ }
37
+
38
+ VALUE wcstorbs(const wchar_t *wstr) {
39
+ size_t len;
40
+ char *cstr;
41
+ VALUE str;
42
+
43
+ len = wcsrtombs(NULL, &wstr, 0, NULL);
44
+ cstr = calloc(len, sizeof(wchar_t));
45
+ wcsrtombs(cstr, &wstr, len, NULL);
46
+
47
+ LOG("wcs to rbs, len: %d, cstr: '%s'\n", len, cstr);
48
+
49
+ str = rb_external_str_new_with_enc(cstr, len, enc);
50
+ free(cstr);
51
+
52
+ return str;
53
+ }
54
+
55
+ struct list_elem *rb_altprintf_make_list(const wchar_t *fmt, VALUE *argv, long *argi, VALUE *hash) {
56
+ struct list_elem *le_cur;
57
+ struct list_elem *le_start;
58
+ struct list_elem *le_prev;
59
+ /* create a dummy element as the head */
60
+ le_start = le_prev = list_elem_create();
61
+
62
+ VALUE entry, symbol;
63
+
64
+ long int *tmp_int;
65
+ wint_t *tmp_char;
66
+ double *tmp_double;
67
+ const wchar_t *tmp_str;
68
+
69
+ char *cstr;
70
+ size_t len;
71
+
72
+ int mode = 0;
73
+ long argc = rb_array_len(*argv);
74
+ int use_hash = 0;
75
+
76
+ const wchar_t *end = &fmt[wcslen(fmt)];
77
+
78
+ for (;fmt<end;fmt++) {
79
+ LOG("checking char '%lc', lvl: '%d'\n", (wint_t)(*fmt), mode);
80
+ if (mode == 0) {
81
+ switch(*fmt) {
82
+ case FS_START: mode = 1;
83
+ break;
84
+ }
85
+ } else {
86
+ switch (*fmt) {
87
+ case FS_A_CHARARG:
88
+ fmt++;
89
+ break;
90
+ case FS_A_RBHASHSTART:
91
+ tmp_str = fmt + 1;
92
+
93
+ use_hash = -1;
94
+ while (fmt < end && *fmt != FS_A_RBHASHEND) {
95
+ fmt++;
96
+ use_hash++;
97
+ }
98
+
99
+ len = wcsnrtombs(NULL, &fmt, use_hash, 0, NULL);
100
+ cstr = calloc(len + 1, sizeof(char));
101
+ wcsnrtombs(cstr, &tmp_str, use_hash, len, NULL);
102
+ LOG("cstr: '%s'\n", cstr);
103
+
104
+ symbol = rb_check_symbol_cstr(cstr, len, enc);
105
+ entry = rb_hash_lookup2(*hash, symbol, Qnil);
106
+ free(cstr);
107
+ use_hash = 1;
108
+
109
+ break;
110
+ case FS_A_STRINGSTART:
111
+ while (fmt < end && *fmt != FS_A_STRINGEND) fmt++;
112
+ break;
113
+ case FS_T_STRING:
114
+ CHECKARG;
115
+
116
+ tmp_str = rbstowcs(entry);
117
+ le_cur = list_elem_ini(tmp_str, String);
118
+ goto match;
119
+ case FS_T_MUL:
120
+ case FS_T_TERN:
121
+ case FS_T_ALIGN:
122
+ case FS_T_INT:
123
+ CHECKARG;
124
+
125
+ tmp_int = malloc(sizeof(long int));
126
+ *tmp_int = FIX2LONG(entry);
127
+ LOG("got int %ld\n", *tmp_int);
128
+ le_cur = list_elem_ini(tmp_int, Int);
129
+ goto match;
130
+ case FS_T_CHAR:
131
+ CHECKARG;
132
+
133
+ tmp_char = malloc(sizeof(wint_t));
134
+ tmp_str = rbstowcs(entry);
135
+ *tmp_char = btowc(tmp_str[0]);
136
+ le_cur = list_elem_ini(tmp_char, Char);
137
+ goto match;
138
+ case FS_T_DOUBLE:
139
+ CHECKARG;
140
+
141
+ tmp_double = malloc(sizeof(double));
142
+ *tmp_double = RFLOAT_VALUE(entry);
143
+ le_cur = list_elem_ini(tmp_double, Double);
144
+ goto match;
145
+ match: le_prev->next = le_cur;
146
+ le_prev = le_cur;
147
+ mode = 0;
148
+ (*argi)++;
149
+ break;
150
+ case FS_START:
151
+ mode = 0;
152
+ break;
153
+ }
154
+ }
155
+ }
156
+
157
+ no_more_args:
158
+ if (le_start->next == NULL) return le_start;
159
+
160
+ /* set cur to the 2nd element and destroy the first one */
161
+ le_cur = le_start->next;
162
+ le_start->next = NULL;
163
+ list_elem_destroy(le_start);
164
+
165
+ return le_cur;
166
+ }
167
+
168
+ VALUE rb_alt_printf(long passes, size_t argc, VALUE *argv, VALUE self) {
169
+ VALUE fmt, args, hash, final;
170
+ wchar_t *wfmt;
171
+ wchar_t *formatted;
172
+ struct list_elem *ap;
173
+
174
+ rb_scan_args(argc, argv, "1*:", &fmt, &args, &hash);
175
+
176
+ if (passes == 0) return fmt;
177
+
178
+ wfmt = rbstowcs(fmt);
179
+
180
+ long argi = 0;
181
+ while (passes > 0) {
182
+ ap = rb_altprintf_make_list(wfmt, &args, &argi, &hash);
183
+
184
+ formatted = altsprintf(wfmt, ap);
185
+ LOG("formatted result: '%ls'\n", formatted);
186
+
187
+ free(wfmt);
188
+ list_elem_destroy(ap);
189
+
190
+ wfmt = formatted;
191
+ passes--;
192
+ }
193
+
194
+ final = wcstorbs(formatted);
195
+
196
+ free(formatted);
197
+
198
+ return final;
199
+ }
200
+
201
+ VALUE rb_alt_printf_single_pass(size_t argc, VALUE *argv, VALUE self) {
202
+ VALUE fmt, args, hash, final;
203
+
204
+ return rb_alt_printf(1, argc, argv, self);
205
+ }
206
+
207
+ VALUE rb_alt_printf_multi_pass(size_t argc, VALUE *argv, VALUE self) {
208
+ long passes;
209
+
210
+ passes = FIX2LONG(argv[0]);
211
+
212
+ LOG("passes: %ld\n", passes);
213
+ return rb_alt_printf(passes, argc - 1, &argv[1], self);
214
+ }
215
+
216
+ void Init_alt_printf()
217
+ {
218
+ enc = rb_enc_find("UTF-8");
219
+ VALUE mod = rb_define_module(MODNAME);
220
+ rb_define_module_function(mod, "fmt", rb_alt_printf_single_pass, -1);
221
+ rb_define_module_function(mod, "fmtm", rb_alt_printf_multi_pass, -1);
222
+ }
@@ -0,0 +1,244 @@
1
+ #include "syntax.h"
2
+ #include "altprintf.h"
3
+ #include "log.h"
4
+
5
+ void default_format(struct format *f) {
6
+ struct width width = {.prec = -1, .pad = 0};
7
+ f->stringarg_start = NULL;
8
+ f->stringarg_end = NULL;
9
+ f->chararg = L':';
10
+ f->padchar = L' ';
11
+ f->align = Right;
12
+ f->width = width;
13
+ f->le = NULL;
14
+ }
15
+
16
+ void format_mul(struct strbuf *sb, struct format *f)
17
+ {
18
+ long int *i = f->le->data;
19
+ strbuf_pad(sb, f->chararg, *i);
20
+ }
21
+ void format_tern(struct strbuf *sb, struct format *f)
22
+ {
23
+ long int *b = f->le->data;
24
+ int first_half = 1;
25
+ wchar_t sep = f->chararg;
26
+ wchar_t *p = f->stringarg_start;
27
+ for (;p<=f->stringarg_end;p++) {
28
+ LOG("*p: %lc, first half? %d, bool: %ld, sep: %lc\n", (wint_t)*p, first_half, *b, (wint_t)sep);
29
+ if (*p == sep) first_half = 0;
30
+ else if (*b && first_half) strbuf_append_char(sb, p);
31
+ else if (!*b && !first_half) strbuf_append_char(sb, p);
32
+ }
33
+ }
34
+
35
+ void format_string(struct strbuf *sb, struct format *f)
36
+ {
37
+ int prec = f->width.prec == -1 ? 100000000 : f->width.prec;
38
+ strbuf_append_str(sb, f->le->data, prec);
39
+ }
40
+ void format_char(struct strbuf *sb, struct format *f)
41
+ {
42
+ strbuf_append_char(sb, f->le->data);
43
+ }
44
+ void format_int(struct strbuf *sb, struct format *f)
45
+ {
46
+ strbuf_append_int(sb, f->le->data);
47
+ }
48
+ void format_double(struct strbuf *sb, struct format *f)
49
+ {
50
+ int prec = f->width.prec == -1 ? 3 : f->width.prec;
51
+ strbuf_append_double(sb, f->le->data, prec);
52
+ }
53
+
54
+ void format(struct strbuf *sb, struct format *f, void (*to_s)(struct strbuf *, struct format *))
55
+ {
56
+ struct strbuf *tmp = strbuf_new();
57
+ to_s(tmp, f);
58
+
59
+ if (tmp->len == 0) return;
60
+
61
+ int pad = f->width.pad - tmp->width;
62
+
63
+ if (pad > 0) {
64
+ LOG("padding: %d\n", pad);
65
+ switch(f->align) {
66
+ case Right:
67
+ strbuf_append_strbuf(sb, tmp);
68
+ strbuf_pad(sb, f->padchar, pad);
69
+ break;
70
+ case Left:
71
+ strbuf_pad(sb, f->padchar, pad);
72
+ strbuf_append_strbuf(sb, tmp);
73
+ break;
74
+ case Center:
75
+ strbuf_pad(sb, f->padchar, pad/2);
76
+ strbuf_append_strbuf(sb, tmp);
77
+ strbuf_pad(sb, f->padchar, pad/2 + pad%2);
78
+ break;
79
+ }
80
+ } else {
81
+ strbuf_append_strbuf(sb, tmp);
82
+ }
83
+
84
+ strbuf_destroy(tmp);
85
+ }
86
+
87
+ wchar_t *altsprintf(wchar_t *fmt, struct list_elem *le) {
88
+ int lvl = 0;
89
+ int split = 0;
90
+ struct strbuf *sbs[] = {strbuf_new(), strbuf_new()};
91
+ struct strbuf *sb = sbs[0];
92
+ wchar_t *end = &fmt[wcslen(fmt)];
93
+ wchar_t *jump;
94
+
95
+ void (*append_func)(struct strbuf *, struct format *);
96
+ struct format f;
97
+ long int *number_p = NULL;
98
+ long int *width;
99
+ wint_t split_pad = L' ';
100
+
101
+ for (;fmt<end;fmt++) {
102
+ LOG("checking char '%lc', lvl: '%d'\n", (wint_t)(*fmt), lvl);
103
+ switch (lvl) {
104
+ case 0:
105
+ switch(*fmt) {
106
+ case FS_START:
107
+ default_format(&f);
108
+ lvl = 1;
109
+ break;
110
+ case FS_ESC:
111
+ lvl = 3;
112
+ break;
113
+ default:
114
+ strbuf_append(sb, *fmt);
115
+ break;
116
+ }; break;
117
+ case 1:
118
+ switch(*fmt) {
119
+ /* special arguments */
120
+ case FS_A_STRINGSTART:
121
+ f.stringarg_start = fmt + 1;
122
+ lvl = 2;
123
+ break;
124
+ case FS_A_CHARARG:
125
+ f.chararg = *(fmt+1);
126
+ fmt += 1;
127
+ break;
128
+
129
+ /* standard arguments */
130
+ case FS_A_LALIGN:
131
+ f.align = Left;
132
+ break;
133
+ case FS_A_SPAD:
134
+ f.padchar = FS_A_SPAD;
135
+ break;
136
+ case 0:
137
+ f.padchar = '0';
138
+ break;
139
+ case '.':
140
+ number_p = &f.width.prec;
141
+ fmt++;
142
+ case '1': case '2': case '3': case '4': case '5':
143
+ case '6': case '7': case '8': case '9':
144
+ if (number_p == NULL) number_p = &f.width.pad;
145
+ *number_p = wcstol(fmt, &jump, 10);
146
+ fmt = (jump-1);
147
+ break;
148
+
149
+ /* align operator */
150
+ case FS_T_ALIGN:
151
+ if (le != NULL && le->type != Null) {
152
+ width = le->data;
153
+ le = le->next;
154
+ } else {
155
+ goto no_more_args;
156
+ }
157
+
158
+ split = 1;
159
+ split_pad = f.chararg;
160
+ sb = sbs[1];
161
+ lvl = 0;
162
+ break;
163
+
164
+ /* types */
165
+ case FS_T_STRING:
166
+ append_func = format_string;
167
+ goto match;
168
+ case FS_T_TERN:
169
+ append_func = format_tern;
170
+ goto match;
171
+ case FS_T_INT:
172
+ append_func = format_int;
173
+ goto match;
174
+ case FS_T_MUL:
175
+ append_func = format_mul;
176
+ goto match;
177
+ case FS_T_CHAR:
178
+ append_func = format_char;
179
+ goto match;
180
+ case FS_T_DOUBLE:
181
+ append_func = format_double;
182
+ match:
183
+ if (le != NULL && le->type != Null) {
184
+ f.le = le;
185
+ format(sb, &f, append_func);
186
+ le = le->next;
187
+ }
188
+ lvl = 0;
189
+ break;
190
+ case FS_START:
191
+ strbuf_append(sb, FS_START);
192
+ lvl = 0;
193
+ break;
194
+ }; break;
195
+ case 2:
196
+ if (*fmt == FS_A_STRINGEND) {
197
+ f.stringarg_end = fmt - 1;
198
+ lvl = 1;
199
+ }; break;
200
+ case 3:
201
+ switch(*fmt) {
202
+ case FS_ESC_NL:
203
+ strbuf_append(sb, '\n');
204
+ break;
205
+ case FS_ESC_ESC:
206
+ strbuf_append(sb, '\e');
207
+ break;
208
+ default:
209
+ strbuf_append(sb, *fmt);
210
+ break;
211
+ };
212
+ lvl = 0;
213
+ break;
214
+ }
215
+ }
216
+
217
+ wchar_t *str;
218
+ no_more_args:
219
+ if (split) {
220
+ LOG("splitting string\n");
221
+ lvl = *width - (sbs[0]->width + sbs[1]->width);
222
+ if (lvl >= 0) {
223
+ LOG("padding center\n");
224
+ strbuf_pad(sbs[0], split_pad, lvl);
225
+ strbuf_append_strbuf(sbs[0], sbs[1]);
226
+ } else if (sbs[0]->width > *width) {
227
+ LOG("the first half is longer than the requested with\n");
228
+ strbuf_destroy(sbs[1]);
229
+ sbs[1] = sbs[0];
230
+ sbs[0] = strbuf_new();
231
+ strbuf_appendw_strbuf(sbs[0], sbs[1], *width);
232
+ } else {
233
+ LOG("just shave some off the last half\n");
234
+ strbuf_appendw_strbuf(sbs[0], sbs[1], *width - sbs[0]->width);
235
+ }
236
+ }
237
+
238
+ str = strbuf_cstr(sbs[0]);
239
+
240
+ strbuf_destroy(sbs[0]);
241
+ strbuf_destroy(sbs[1]);
242
+
243
+ return str;
244
+ }
@@ -0,0 +1,42 @@
1
+ #ifndef ALTPRINTF_H
2
+ #define ALTPRINTF_H
3
+
4
+ #ifndef _XOPEN_SOURCE
5
+ #define _XOPEN_SOURCE
6
+ #endif
7
+
8
+ #include <stdio.h>
9
+ #include <stdlib.h>
10
+ #include <stdarg.h>
11
+ #include <string.h>
12
+ #include <math.h>
13
+ #include <limits.h>
14
+ #include <wchar.h>
15
+ #include "strbuf.h"
16
+ #include "list.h"
17
+ #include "syntax.h"
18
+
19
+ wchar_t *altsprintf(wchar_t *fmt, struct list_elem *le);
20
+
21
+ enum align {
22
+ Left,
23
+ Right,
24
+ Center
25
+ };
26
+
27
+ struct width {
28
+ long int prec;
29
+ long int pad;
30
+ };
31
+
32
+ struct format {
33
+ wchar_t *stringarg_start;
34
+ wchar_t *stringarg_end;
35
+ wint_t chararg;
36
+ wint_t padchar;
37
+ enum align align;
38
+ struct width width;
39
+ struct list_elem *le;
40
+ };
41
+
42
+ #endif
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require 'mkmf'
3
+
4
+ create_header
5
+ create_makefile('alt_printf')
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ require 'mkmf'
3
+
4
+ base_dir = File.join(__dir__, '../../../')
5
+ find_header('altprintf.h', File.join(base_dir, 'src'))
6
+ $objs = Dir[File.join(base_dir, 'target/release/*.o')] + ['alt_printf.o']
7
+
8
+ create_header
9
+ create_makefile('alt_printf')
@@ -0,0 +1,81 @@
1
+ #include "list.h"
2
+ #include "log.h"
3
+
4
+ struct list_elem *list_elem_create() {
5
+ void *null = NULL;
6
+ struct list_elem *le = malloc(sizeof(struct list_elem));
7
+ LOG("allocatted %zu %p\n", sizeof(struct list_elem), le);
8
+ le->data = null;
9
+ le->type = Null;
10
+ le->next = null;
11
+ le->heap = 1;
12
+
13
+ return le;
14
+ }
15
+
16
+ void list_elem_destroy(struct list_elem *le) {
17
+ if (le->heap && le->data != NULL) {
18
+ LOG("freeing %p\n", le->data);
19
+ free(le->data);
20
+ }
21
+ if (le->next != NULL) { list_elem_destroy(le->next); }
22
+
23
+ LOG("freeing %p\n", le);
24
+ free(le);
25
+ }
26
+
27
+ struct list_elem *list_elem_ini(void *data, enum type t) {
28
+ struct list_elem *le = list_elem_create();
29
+ le->data = data;
30
+ le->type = t;
31
+ return le;
32
+ }
33
+
34
+ struct list_elem *list_elem_ini_str(wchar_t *str) {
35
+ struct list_elem *le = list_elem_create();
36
+ le->data = str;
37
+ le->type = String;
38
+ return le;
39
+ }
40
+
41
+ struct list_elem *list_elem_ini_int(long int *i) {
42
+ struct list_elem *le = list_elem_create();
43
+ le->data = i;
44
+ le->type = Int;
45
+ return le;
46
+ }
47
+
48
+ struct list_elem *list_elem_ini_dub(double *d) {
49
+ struct list_elem *le = list_elem_create();
50
+ le->data = d;
51
+ le->type = Double;
52
+ return le;
53
+ }
54
+
55
+ void list_elem_inspect(struct list_elem *le) {
56
+ switch (le->type) {
57
+ case Int:
58
+ printf("->Int %ld\n", *(long int *)le->data);
59
+ break;
60
+ case String:
61
+ printf("->String '%ls'\n", (wchar_t *)le->data);
62
+ break;
63
+ case Char:
64
+ printf("->Char %lc\n", *(wint_t *)le->data);
65
+ break;
66
+ case Double:
67
+ printf("->Double %f\n", *(double *)le->data);
68
+ break;
69
+ case Null:
70
+ printf("->Null\n");
71
+ break;
72
+ }
73
+ }
74
+
75
+ void list_elem_inspect_all(struct list_elem *le) {
76
+ while(1) {
77
+ list_elem_inspect(le);
78
+ if (le->next == NULL) { break; }
79
+ le = le->next;
80
+ }
81
+ }
@@ -0,0 +1,24 @@
1
+ #ifndef LIST_H
2
+ #define LIST_H
3
+ #include <stdio.h>
4
+ #include <stdlib.h>
5
+ #include <wchar.h>
6
+
7
+ enum type { Int, String, Char, Double, Null };
8
+
9
+ struct list_elem {
10
+ void *data;
11
+ enum type type;
12
+ struct list_elem *next;
13
+ int heap;
14
+ };
15
+
16
+ struct list_elem *list_elem_create();
17
+ void list_elem_destroy(struct list_elem *le);
18
+ struct list_elem *list_elem_ini(void *data, enum type t);
19
+ struct list_elem *list_elem_ini_int(long int *i);
20
+ struct list_elem *list_elem_ini_str(wchar_t *str);
21
+ struct list_elem *list_elem_ini_dub(double *d);
22
+ void list_elem_inspect(struct list_elem *le);
23
+ void list_elem_inspect_all(struct list_elem *le);
24
+ #endif
@@ -0,0 +1,11 @@
1
+ #ifndef LOG_H
2
+ #define LOG_H
3
+
4
+ #ifdef DEBUG
5
+ #define LOG(...) printf("%s[%d] - ", __FILE__, __LINE__);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
+ #endif
@@ -0,0 +1,142 @@
1
+ #define _XOPEN_SOURCE
2
+ #include <locale.h>
3
+ #include <limits.h>
4
+ #include "strbuf.h"
5
+ #include "log.h"
6
+
7
+ #define STRBUF_INI_SIZE 5
8
+ #define STRBUF_GROW_STEP 100
9
+
10
+ extern struct lconv *locale_info;
11
+
12
+ struct strbuf *strbuf_new() {
13
+ struct strbuf *sb = malloc(sizeof(struct strbuf));
14
+
15
+ if (NULL == sb) {
16
+ LOG("can't alloc memory for new strbuf", NULL);
17
+ exit(1);
18
+ }
19
+
20
+ sb->start = sb->end = calloc(STRBUF_INI_SIZE, sizeof(wchar_t));
21
+
22
+ if (NULL == sb->start) {
23
+ LOG("can't alloc memory for new strbuf string", NULL);
24
+ exit(1);
25
+ }
26
+
27
+ sb->len = 0;
28
+ sb->cap = STRBUF_INI_SIZE;
29
+ sb->width = 0;
30
+ return sb;
31
+ }
32
+
33
+ void strbuf_destroy(struct strbuf *sb) {
34
+ free(sb->start);
35
+ free(sb);
36
+ }
37
+
38
+ void strbuf_append(struct strbuf *sb, wchar_t c)
39
+ {
40
+ wchar_t *ns;
41
+
42
+ if (sb->cap < sb->len + 2) {
43
+ ns = calloc(sb->cap + STRBUF_GROW_STEP, sizeof(wchar_t));
44
+
45
+ if (ns == NULL) {
46
+ LOG("can't increase size of strbuf to %d\n", sb->cap + STRBUF_GROW_STEP);
47
+ exit(1);
48
+ }
49
+
50
+ wcscpy(ns, sb->start);
51
+ free(sb->start);
52
+
53
+ sb->start = ns;
54
+ sb->cap += STRBUF_GROW_STEP;
55
+ }
56
+
57
+ sb->start[sb->len] = c;
58
+ sb->start[sb->len+1] = L'\0';
59
+ LOG("string so far: %ls\n", sb->start);
60
+ sb->end = &sb->start[sb->len];
61
+ sb->len++;
62
+ int w = wcwidth(c);
63
+ if (w >= 0) sb->width += w;
64
+ }
65
+
66
+ void strbuf_append_strbuf(struct strbuf *sb, void *sbuf)
67
+ {
68
+ wchar_t *pos;
69
+ struct strbuf *frm = sbuf;
70
+ LOG("frm->start: %p | frm->end: %p\n", frm->start, frm->end);
71
+
72
+ for (pos = frm->start;pos<=frm->end;pos++) {
73
+ strbuf_append(sb, *pos);
74
+ }
75
+ }
76
+
77
+ void strbuf_appendw_strbuf(struct strbuf *sb, void *sbuf, long w)
78
+ {
79
+ wchar_t *pos;
80
+ long ws = 0;
81
+ struct strbuf *frm = sbuf;
82
+ LOG("frm->start: %p | frm->end: %p\n", frm->start, frm->end);
83
+
84
+ for (pos = frm->start;pos<=frm->end;pos++) {
85
+ ws += wcwidth(*pos);
86
+ LOG("new width would be: %ld, requested width: %ld\n", ws, w);
87
+ if (ws > w) break;
88
+ strbuf_append(sb, *pos);
89
+ }
90
+ }
91
+
92
+ void strbuf_append_char(struct strbuf *sb, void *chr)
93
+ {
94
+ wint_t *c = chr;
95
+ strbuf_append(sb, *c);
96
+ }
97
+
98
+ void strbuf_append_str(struct strbuf *sb, void *str, int maxwidth)
99
+ {
100
+ wchar_t *s = str;
101
+ wchar_t *end = &s[wcslen(s)];
102
+ int width = 0;
103
+
104
+ for (;s<end;s++) {
105
+ width += wcwidth(*s);
106
+ if (width > maxwidth) return;
107
+ strbuf_append(sb, *s);
108
+ }
109
+ }
110
+
111
+ void strbuf_append_int(struct strbuf *sb, void *in)
112
+ {
113
+ long int *i = in;
114
+ wchar_t wcs[50];
115
+ swprintf(wcs, 50, L"%ld", *i);
116
+ strbuf_append_str(sb, wcs, 50);
117
+ }
118
+
119
+ void strbuf_append_double(struct strbuf *sb, void *dub, int prec)
120
+ {
121
+ double *d = dub;
122
+ wchar_t wcs[50];
123
+ wchar_t format[30];
124
+ swprintf(format, 30, L"%%.%ldf", prec);
125
+ LOG("format: %ls\n", format);
126
+ swprintf(wcs, 50, format, *d);
127
+ strbuf_append_str(sb, wcs, 50);
128
+ }
129
+
130
+ void strbuf_pad(struct strbuf *sb, wchar_t pc, int amnt)
131
+ {
132
+ for (;amnt>0;amnt--) strbuf_append(sb, pc);
133
+ }
134
+
135
+ wchar_t *strbuf_cstr(struct strbuf *sb)
136
+ {
137
+ wchar_t *str;
138
+ str = calloc(sb->len + 1, sizeof(wchar_t));
139
+ wcscpy(str, sb->start);
140
+
141
+ return str;
142
+ }
@@ -0,0 +1,28 @@
1
+ #ifndef STRBUF_H
2
+ #define STRBUF_H
3
+ #include <wchar.h>
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+ #include <math.h>
8
+
9
+ struct strbuf *strbuf_new();
10
+ void strbuf_destroy(struct strbuf *sb);
11
+ void strbuf_append(struct strbuf *sb, wchar_t);
12
+ void strbuf_append_char(struct strbuf *sb, void *);
13
+ void strbuf_append_str(struct strbuf *, void *, int);
14
+ void strbuf_append_int(struct strbuf *sb, void *);
15
+ void strbuf_append_double(struct strbuf *, void *, int);
16
+ void strbuf_append_strbuf(struct strbuf *, void *);
17
+ void strbuf_appendw_strbuf(struct strbuf *, void *, long);
18
+ void strbuf_pad(struct strbuf *, wchar_t, int);
19
+ wchar_t *strbuf_cstr(struct strbuf *);
20
+
21
+ struct strbuf {
22
+ wchar_t *start;
23
+ wchar_t *end;
24
+ size_t len;
25
+ size_t width;
26
+ size_t cap;
27
+ };
28
+ #endif
@@ -0,0 +1,30 @@
1
+ #ifndef SYNTAX_H
2
+ #define SYNTAX_H
3
+
4
+ #define FS_START '%'
5
+ #define FS_DOUBLE_SEP '.'
6
+
7
+ #define FS_ESC '\\'
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_STRINGSTART '('
20
+ #define FS_A_STRINGEND ')'
21
+ #define FS_A_CHARARG '~'
22
+ #define FS_A_LALIGN '-'
23
+ #define FS_A_SPAD ' '
24
+
25
+ #define FS_A_RBHASHSTART '<'
26
+ #define FS_A_RBHASHEND '>'
27
+
28
+ #define FS_D_PREC 100
29
+
30
+ #endif
Binary file
@@ -0,0 +1,3 @@
1
+ module AltPrintf
2
+ VERSION = [0, 1, 0]
3
+ end
data/lib/alt_printf.rb ADDED
@@ -0,0 +1,4 @@
1
+ require_relative 'alt_printf/version'
2
+ require_relative 'alt_printf/alt_printf'
3
+
4
+ module AltPrintf end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alt_printf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Stone Tickle
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-08-07 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
+ - ext/alt_printf/extconf.rb
46
+ extra_rdoc_files: []
47
+ files:
48
+ - Gemfile
49
+ - README.md
50
+ - Rakefile
51
+ - alt_printf.gemspec
52
+ - ext/alt_printf/alt_printf.c
53
+ - ext/alt_printf/altprintf.c
54
+ - ext/alt_printf/altprintf.h
55
+ - ext/alt_printf/extconf.rb
56
+ - ext/alt_printf/extconf_dev.rb
57
+ - ext/alt_printf/list.c
58
+ - ext/alt_printf/list.h
59
+ - ext/alt_printf/log.h
60
+ - ext/alt_printf/strbuf.c
61
+ - ext/alt_printf/strbuf.h
62
+ - ext/alt_printf/syntax.h
63
+ - lib/alt_printf.rb
64
+ - lib/alt_printf/alt_printf.so
65
+ - lib/alt_printf/version.rb
66
+ homepage: https://github.com/alt_printf/gem
67
+ licenses:
68
+ - MIT
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 2.6.3
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubygems_version: 3.0.3
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: A powerful printf-like template language
89
+ test_files: []