comparison src/ploki/pp.c @ 4223:ac0403686959

<oerjan> rm -rf src/ploki; mv ploki src
author HackBot
date Fri, 20 Dec 2013 22:18:50 +0000
parents
children
comparison
equal deleted inserted replaced
4222:b0f3e267bb1e 4223:ac0403686959
1 #include "IO.h"
2 #include "Str.h"
3 #include "kork.h"
4 #include "list.h"
5 #include "main_io.h"
6 #include "main_opt.h"
7 #include "match.h"
8 #include "pp.h"
9 #include "re.h"
10 #include "run.h"
11 #include "val.h"
12 #include "xmalloc.h"
13
14 #include <ctype.h>
15 #include <errno.h>
16 #include <float.h>
17 #include <math.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 void pp_abs(struct val *v) {
23 V_NUM(v);
24 v_set_n(v, fabs(v->num));
25 }
26
27 void pp_acos(struct val *v) {
28 V_NUM(v);
29 v_set_n(v, acos(v->num));
30 }
31
32 void pp_asin(struct val *v) {
33 V_NUM(v);
34 v_set_n(v, asin(v->num));
35 }
36
37 void pp_atan(struct val *v) {
38 V_NUM(v);
39 v_set_n(v, atan(v->num));
40 }
41
42 void pp_atan2(struct val *v) {
43 if (!V_LIST_P(v) || li_length(v->magic.list) != 2) {
44 v_set_undef(v);
45 #ifdef EINVAL
46 errno = EINVAL;
47 #endif
48 return;
49 } else {
50 struct val *const a = li_at(v->magic.list, 0);
51 struct val *const b = li_at(v->magic.list, 1);
52 V_NUM(a);
53 V_NUM(b);
54 v_set_n(v, atan2(a->num, b->num));
55 }
56 }
57
58 void pp_chr(struct val *v) {
59 V_NUM(v);
60 V_xxx_OFF(v);
61 ko_cpy_c(v->ko, (unsigned char)(v->num + .5));
62 v->type = V_STR_K;
63 }
64
65 void pp_cos(struct val *v) {
66 V_NUM(v);
67 v_set_n(v, cos(v->num));
68 }
69
70 void pp_defined(struct val *v) {
71 if (v->type != V_UNDEF) {
72 v_set_n(v, 1.0);
73 }
74 }
75
76 void pp_eof(struct val *v) {
77 if (!V_EXT_P(v)) {
78 v_set_undef(v);
79 #ifdef EBADF
80 errno = EBADF;
81 #endif
82 return;
83 }
84 if (io_eof(v->magic.ext)) {
85 v_set_n(v, 1.0);
86 } else {
87 v_set_m(v, "", 0);
88 }
89 }
90
91 void pp_error(struct val *v) {
92 if (!V_EXT_P(v)) {
93 v_set_undef(v);
94 #ifdef EBADF
95 errno = EBADF;
96 #endif
97 return;
98 }
99 if (io_err(v->magic.ext)) {
100 v_set_n(v, 1.0);
101 } else {
102 v_set_m(v, "", 0);
103 }
104 }
105
106 void pp_escape(struct val *v) {
107 String tmp;
108 size_t i;
109
110 V_STR(v);
111 V_xxx_OFF(v);
112 St_init(&tmp);
113 St_cpy(&tmp, ko_str(v->ko));
114 ko_zero(v->ko);
115 for (i = St_len(&tmp); i; ) {
116 --i;
117 if (!(ST_INDEX(&tmp, i) == '_' || isalnum(ST_INDEX(&tmp, i)))) {
118 ko_cat_c(v->ko, '!');
119 }
120 ko_cat_c(v->ko, ST_INDEX(&tmp, i));
121 }
122 St_clear(&tmp);
123 ko_reverse(v->ko);
124 v->type = V_STR_K;
125 }
126
127 void pp_getc(struct val *v) {
128 int c;
129
130 if (!V_EXT_P(v)) {
131 V_xxx_OFF(v);
132 v->type = V_UNDEF;
133 #ifdef EBADF
134 errno = EBADF;
135 #endif
136 return;
137 }
138 c = io_getc(v->magic.ext);
139 #if EOF != -1
140 if (c == EOF) {
141 c = -1;
142 }
143 #endif
144 v_set_n(v, c);
145 }
146
147 void pp_getenv(struct val *v) {
148 const char *const tmp = getenv(v_sptr(v, NULL));
149 if (tmp) {
150 v_set_m(v, tmp, strlen(tmp));
151 } else {
152 V_xxx_OFF(v);
153 v->type = V_UNDEF;
154 }
155 }
156
157 void pp_gets(struct val *v) {
158
159 if (!V_EXT_P(v)) {
160 V_xxx_OFF(v);
161 v->type = V_UNDEF;
162 #ifdef EBADF
163 errno = EBADF;
164 #endif
165 return;
166 }
167
168 if (ko_getline(v->magic.ext, v->ko) + 1u) {
169 V_xxx_OFF(v);
170 v->type = V_STR_K;
171 } else {
172 V_xxx_OFF(v);
173 v->type = V_UNDEF;
174 }
175 }
176
177 void pp_int(struct val *v) {
178 V_NUM(v);
179 v_set_n(v, floor(v->num + .5));
180 }
181
182 void pp_io(struct val *v) {
183 if (V_EXT_P(v)) {
184 v_set_n(v, 1.0);
185 } else {
186 v_set_m(v, "", 0);
187 }
188 }
189
190 void pp_length(struct val *v) {
191 if (V_LIST_P(v)) {
192 v_set_n(v, li_length(v->magic.list));
193 return;
194 }
195 v_set_n(v, ko_length(v_kork(v)));
196 }
197
198 void pp_log(struct val *v) {
199 V_NUM(v);
200 v_set_n(v, log(v->num));
201 }
202
203 void pp_log10(struct val *v) {
204 V_NUM(v);
205 v_set_n(v, log10(v->num));
206 }
207
208 void pp_lower(struct val *v) {
209 V_STR(v);
210 V_xxx_OFF(v);
211 ko_lower(v->ko);
212 }
213
214 void pp_moend(struct val *v) {
215 size_t n;
216
217 V_NUM(v);
218 n = RINT(v->num);
219 if (n < Interp.m_end.size) {
220 v_set_n(v, Interp.m_end.index[n]);
221 } else {
222 v_set_undef(v);
223 }
224 }
225
226 void pp_mostart(struct val *v) {
227 size_t n;
228
229 V_NUM(v);
230 n = RINT(v->num);
231 if (n < Interp.m_start.size) {
232 v_set_n(v, Interp.m_start.index[n]);
233 } else {
234 v_set_undef(v);
235 }
236 }
237
238 void pp_neg(struct val *v) {
239 V_NUM(v);
240 V_xxx_OFF(v);
241 v->num = -v->num;
242 v->type = V_NUM_K;
243 }
244
245 void pp_not(struct val *v) {
246 if (v_true(v)) {
247 v_set_m(v, "", 0);
248 } else {
249 v_set_n(v, 1.0);
250 }
251 }
252
253 void pp_num(struct val *v) {
254 V_NUM(v);
255 V_xxx_OFF(v);
256 v->type = V_NUM_K;
257 }
258
259 void pp_open(struct val *v) {
260 IO *fh;
261 struct val *name, *mode;
262 enum io_flags flags;
263
264 if (!V_LIST_P(v) || li_length(v->magic.list) != 2) {
265 v_set_undef(v);
266 #ifdef ENOENT
267 errno = ENOENT;
268 #endif
269 return;
270 }
271
272 name = li_at(v->magic.list, 0);
273 V_STR(name);
274 if (ko_chr(name->ko, '\0') + 1u) {
275 v_set_undef(v);
276 #ifdef ENOENT
277 errno = ENOENT;
278 #endif
279 return;
280 }
281
282 mode = li_at(v->magic.list, 1);
283 flags = 0;
284 V_STR(mode);
285
286 if (ko_chr(mode->ko, 'A') + 1u) {
287 flags |= IO_APPEND;
288 if (ko_chr(mode->ko, '+') + 1u) {
289 flags |= IO_READ;
290 }
291 } else if (ko_chr(mode->ko, 'W') + 1u) {
292 flags |= IO_WRITE | IO_TRUNCATE;
293 if (ko_chr(mode->ko, '+') + 1u) {
294 flags |= IO_READ;
295 }
296 } else {
297 flags |= IO_READ;
298 if (ko_chr(mode->ko, '+') + 1u) {
299 flags |= IO_WRITE;
300 } else if (ko_chr(mode->ko, 'Z') + 1u) {
301 flags |= IO_BUFFERED;
302 }
303 }
304
305 if (ko_chr(mode->ko, 'B') + 1u) {
306 flags |= IO_BINARY;
307 }
308 if ((flags & IO_WRITE || flags & IO_APPEND) && ko_chr(mode->ko, 'F') + 1u) {
309 flags |= IO_AUTOFLUSH;
310 }
311
312 if (!(fh = io_open(ko_szp(name->ko), flags))) {
313 v_set_undef(v);
314 return;
315 }
316
317 v_set_io(v, fh);
318 }
319
320 void pp_openr(struct val *v) {
321 V_STR(v);
322 V_xxx_OFF(v);
323 if (ko_chr(v->ko, '\0') + 1u) {
324 v->type = V_UNDEF;
325 #ifdef ENOENT
326 errno = ENOENT;
327 #endif
328 } else if ((v->magic.ext = io_open(ko_szp(v->ko), IO_READ | IO_BINARY))) {
329 v->type = V_EXT_K;
330 } else {
331 v->type = V_UNDEF;
332 }
333 }
334
335 void pp_openw(struct val *v) {
336 V_STR(v);
337 V_xxx_OFF(v);
338 if (ko_chr(v->ko, '\0') + 1u) {
339 v->type = V_UNDEF;
340 #ifdef ENOENT
341 errno = ENOENT;
342 #endif
343 } else if ((v->magic.ext = io_open(ko_szp(v->ko), IO_WRITE | IO_TRUNCATE | IO_BINARY | IO_AUTOFLUSH))) {
344 v->type = V_EXT_K;
345 } else {
346 v->type = V_UNDEF;
347 }
348 }
349
350 void pp_ord(struct val *v) {
351 V_STR(v);
352 V_xxx_OFF(v);
353 if (ko_length(v->ko)) {
354 v->num = ko_at(v->ko, 0);
355 v->type = V_NUM_K;
356 } else {
357 v->type = V_UNDEF;
358 }
359 }
360
361 void pp_quote(struct val *v) {
362 String tmp;
363 size_t i;
364
365 V_STR(v);
366 V_xxx_OFF(v);
367 St_init(&tmp);
368 St_cpy_m(&tmp, ko_ptr(v->ko), ko_length(v->ko));
369 ko_zero(v->ko);
370 for (i = 0; i < St_len(&tmp); ++i) {
371 if (!(ST_INDEX(&tmp, i) == '_' || isalnum(ST_INDEX(&tmp, i)))) {
372 ko_cat_c(v->ko, '\\');
373 }
374 ko_cat_c(v->ko, ST_INDEX(&tmp, i));
375 }
376 St_clear(&tmp);
377 v->type = V_STR_K;
378 }
379
380 void pp_remove(struct val *v) {
381 V_STR(v);
382 V_xxx_OFF(v);
383 if (ko_chr(v->ko, '\0') + 1u) {
384 v->type = V_UNDEF;
385 #ifdef ENOENT
386 errno = ENOENT;
387 #endif
388 return;
389 }
390
391 if (remove(ko_szp(v->ko))) {
392 v_set_m(v, "", 0);
393 } else {
394 v_set_n(v, 1.0);
395 }
396 }
397
398 void pp_rename(struct val *v) {
399 struct val *from, *to;
400
401 if (!V_LIST_P(v) || li_length(v->magic.list) != 2) {
402 v_set_undef(v);
403 #ifdef ENOENT
404 errno = ENOENT;
405 #endif
406 return;
407 }
408
409 from = li_at(v->magic.list, 0);
410 V_STR(from);
411 if (ko_chr(from->ko, '\0') + 1u) {
412 v_set_undef(v);
413 #ifdef ENOENT
414 errno = ENOENT;
415 #endif
416 return;
417 }
418
419 to = li_at(v->magic.list, 1);
420 V_STR(to);
421 if (ko_chr(to->ko, '\0') + 1u) {
422 v_set_undef(v);
423 #ifdef EINVAL
424 errno = EINVAL;
425 #endif
426 return;
427 }
428
429 if (rename(ko_szp(from->ko), ko_szp(to->ko))) {
430 v_set_m(v, "", 0);
431 } else {
432 v_set_n(v, 1.0);
433 }
434 }
435
436 void pp_reverse(struct val *v) {
437 if (V_LIST_P(v)) {
438 li_reverse(v->magic.list);
439 v->type = V_LIST_K;
440 return;
441 }
442 V_STR(v);
443 V_xxx_OFF(v);
444 ko_reverse(v->ko);
445 v->type = V_STR_K;
446 }
447
448 void pp_seek(struct val *v) {
449 struct val *fh, *tmp;
450 long off;
451 enum io_whence whence = IOS_START;
452
453 if (!V_LIST_P(v) || li_length(v->magic.list) < 2 || li_length(v->magic.list) > 3) {
454 v_set_undef(v);
455 #ifdef EINVAL
456 errno = EINVAL;
457 #endif
458 return;
459 }
460
461 fh = li_at(v->magic.list, 0);
462 if (!V_EXT_P(fh)) {
463 v_set_undef(v);
464 #ifdef EBADF
465 errno = EBADF;
466 #endif
467 return;
468 }
469
470 tmp = li_at(v->magic.list, 1);
471 V_NUM(tmp);
472 off = RINT(tmp->num);
473
474 if ((tmp = li_at(v->magic.list, 2))) {
475 V_NUM(tmp);
476 switch ((long)RINT(tmp->num)) {
477 case 0: whence = IOS_START; break;
478 case 1: whence = IOS_CUR; break;
479 case 2: whence = IOS_END; break;
480 default:
481 v_set_undef(v);
482 #ifdef EINVAL
483 errno = EINVAL;
484 #endif
485 return;
486 }
487 }
488
489 v_set_n(v, io_seek(fh->magic.ext, off, whence));
490 }
491
492 void pp_sin(struct val *v) {
493 V_NUM(v);
494 v_set_n(v, sin(v->num));
495 }
496
497 void pp_sqrt(struct val *v) {
498 V_NUM(v);
499 V_xxx_OFF(v);
500 v->num = sqrt(v->num);
501 v->type = V_NUM_K;
502 }
503
504 void pp_str(struct val *v) {
505 V_STR(v);
506 V_xxx_OFF(v);
507 v->type |= V_STR_K;
508 }
509
510 void pp_tan(struct val *v) {
511 V_NUM(v);
512 v_set_n(v, tan(v->num));
513 }
514
515 void pp_tell(struct val *v) {
516 if (!V_EXT_P(v)) {
517 v_set_undef(v);
518 #ifdef EBADF
519 errno = EBADF;
520 #endif
521 return;
522 }
523 v_set_n(v, io_tell(v->magic.ext));
524 }
525
526 void pp_typeof(struct val *v) {
527 if (V_SUB_P(v)) {
528 v_set_m(v, "stuff", 5);
529 } else if (V_EXT_P(v)) {
530 v_set_m(v, "stream", 6);
531 } else if (V_LIST_P(v)) {
532 v_set_m(v, "list", 4);
533 } else if (V_NUM_P(v)) {
534 v_set_m(v, "number", 6);
535 } else if (V_STR_P(v)) {
536 v_set_m(v, "string", 6);
537 } else {
538 v_set_m(v, "nothing", 7);
539 }
540 }
541
542 void pp_upper(struct val *v) {
543 V_STR(v);
544 V_xxx_OFF(v);
545 ko_upper(v->ko);
546 }
547
548 #define NUMB(expr) \
549 do { \
550 V_NUM(b); \
551 V_NUM(v); \
552 v_set_n(v, expr); \
553 } while (0)
554
555 #define ARITH(op) NUMB(v->num op b->num)
556
557 void pp_add(struct val *v, struct val *b) {
558 ARITH(+);
559 }
560
561 #define LOGIC(init, cond) \
562 do { \
563 init; \
564 if (cond) { \
565 v_set_n(v, 1.0); \
566 } else { \
567 v_set_m(v, "", 0); \
568 } \
569 } while (0)
570
571 void pp_and(struct val *v, struct val *b) {
572 LOGIC((void)0, v_true(v) && v_true(b));
573 }
574
575 void pp_comma(struct val *v, struct val *b) {
576 v_set(v, b);
577 }
578
579 void pp_concat(struct val *v, struct val *b) {
580 v_cat(v, b);
581 }
582
583 void pp_div(struct val *v, struct val *b) {
584 ARITH(/);
585 }
586
587 #define CMP_LS(op) LOGIC((void)0, v_cmp_ls(v, b) op 0)
588
589 void pp_eq(struct val *v, struct val *b) {
590 CMP_LS(==);
591 }
592
593 #define CMP_N(op) LOGIC(V_NUM(v); V_NUM(b), v->num op b->num)
594
595 void pp_eq_n(struct val *v, struct val *b) {
596 if (V_EXT_P(v)) {
597 if (V_EXT_P(b)) {
598 LOGIC((void)0, v->magic.ext == b->magic.ext);
599 } else if (V_SUB_P(b)) {
600 goto false_cmp;
601 } else {
602 goto default_cmp;
603 }
604 } else if (V_SUB_P(v)) {
605 if (V_SUB_P(b)) {
606 LOGIC((void)0, v->magic.sub == b->magic.sub);
607 } else if (V_EXT_P(b)) false_cmp: {
608 LOGIC((void)0, 0);
609 } else {
610 goto default_cmp;
611 }
612 } else default_cmp: {
613 CMP_N(==);
614 }
615 }
616
617 static const char xdigits[] = "0123456789" "abcdefghijklmnopqrstuvwxyz";
618
619 void pp_frombase(struct val *v, struct val *b) {
620 double p;
621 size_t i;
622 int base, sign;
623 const char *tmp;
624
625 V_NUM(b);
626 V_STR(v);
627 V_xxx_OFF(v);
628 if (floor(b->num + .5) < 2. || floor(b->num + .5) > 36.) {
629 v->type = V_UNDEF;
630 return;
631 }
632 base = floor(b->num + .5);
633 ko_shiftws(v->ko);
634
635 sign = 0;
636 if (ko_at(v->ko, 0) == '-') {
637 sign = 1;
638 ko_shift(v->ko, 1);
639 } else if (ko_at(v->ko, 0) == '+') {
640 ko_shift(v->ko, 1);
641 }
642
643 p = 0.0;
644 for (i = 0; i < ko_length(v->ko); ++i) {
645 if ((tmp = strchr(xdigits, tolower(ko_at(v->ko, i)))) &&
646 tmp - xdigits < base) {
647 p *= base;
648 p += tmp - xdigits;
649 } else {
650 break;
651 }
652 }
653
654 if (i < ko_length(v->ko)) {
655 if (ko_at(v->ko, i) == '.') {
656 double shift = 1.0;
657
658 for (++i; i < ko_length(v->ko); ++i) {
659 if ((tmp = strchr(xdigits, tolower(ko_at(v->ko, i)))) &&
660 tmp - xdigits < base) {
661 shift *= base;
662 p *= base;
663 p += tmp - xdigits;
664 } else {
665 break;
666 }
667 }
668
669 p /= shift;
670 }
671 }
672
673 if (sign) {
674 p = -p;
675 }
676 v_set_n(v, p);
677 }
678
679 void pp_gt(struct val *v, struct val *b) {
680 CMP_LS(>);
681 }
682
683 void pp_gt_n(struct val *v, struct val *b) {
684 CMP_N(>);
685 }
686
687 void pp_lt(struct val *v, struct val *b) {
688 CMP_LS(<);
689 }
690
691 void pp_lt_n(struct val *v, struct val *b) {
692 CMP_N(<);
693 }
694
695 void pp_match(struct val *v, struct val *b) {
696 t_regex *re;
697
698 V_STR(b);
699 re = re_compile(ko_str(b->ko));
700 do_match(v, re);
701 re_free(re);
702 }
703
704 void pp_mod(struct val *v, struct val *b) {
705 NUMB(fmod(v->num, b->num));
706 }
707
708 void pp_mult(struct val *v, struct val *b) {
709 ARITH(*);
710 }
711
712 void pp_ne(struct val *v, struct val *b) {
713 CMP_LS(!=);
714 }
715
716 void pp_ne_n(struct val *v, struct val *b) {
717 if (V_EXT_P(v)) {
718 if (V_EXT_P(b)) {
719 LOGIC((void)0, v->magic.ext != b->magic.ext);
720 } else if (V_SUB_P(b)) {
721 goto true_cmp;
722 } else {
723 goto default_cmp;
724 }
725 } else if (V_SUB_P(v)) {
726 if (V_SUB_P(b)) {
727 LOGIC((void)0, v->magic.sub != b->magic.sub);
728 } else if (V_EXT_P(b)) true_cmp: {
729 LOGIC((void)0, 1);
730 } else {
731 goto default_cmp;
732 }
733 } else default_cmp: {
734 CMP_N(!=);
735 }
736 }
737
738 void pp_or(struct val *v, struct val *b) {
739 LOGIC((void)0, v_true(v) || v_true(b));
740 }
741
742 void pp_pop(struct val *v, struct val *b) {
743 long p;
744
745 V_NUM(b);
746 p = RINT(b->num);
747
748 if (V_LIST_P(v)) {
749 v->type = V_LIST_K;
750 if (p < 0) {
751 p += li_length(v->magic.list);
752 }
753 if (p < 0) {
754 p = 0;
755 }
756 if ((size_t)p >= li_length(v->magic.list)) {
757 return;
758 }
759 li_trunc(v->magic.list, p);
760 return;
761 }
762
763 V_STR(v);
764 V_xxx_OFF(v);
765 v->type = V_STR_K;
766 if (p < 0) {
767 p += ko_length(v->ko);
768 }
769 if (p < 0) {
770 p = 0;
771 }
772 if ((size_t)p >= ko_length(v->ko)) {
773 return;
774 }
775 ko_trunc(v->ko, p);
776 }
777
778 void pp_pow(struct val *v, struct val *b) {
779 NUMB(pow(v->num, b->num));
780 }
781
782 void pp_read(struct val *v, struct val *b) {
783 long n;
784
785 if (V_SUB_P(v)) {
786 const size_t curdepth = depth_get();
787 stack_store(&Interp.arg, b);
788 eval_into(sub_expr(v->magic.sub), v);
789 depth_restore(curdepth);
790 return;
791 }
792
793 if (V_EXT_P(v)) {
794 V_NUM(b);
795 ko_read(v->magic.ext, v->ko, b->num < 0.0 ? (size_t)-1 : b->num + .5);
796 V_xxx_OFF(v);
797 v->type = V_STR_K;
798 return;
799 }
800
801 if (V_LIST_P(v)) {
802 struct val *ptr;
803 V_NUM(b);
804 n = RINT(b->num);
805 if (n < 0) {
806 n += li_length(v->magic.list);
807 }
808
809 if (n >= 0 && (ptr = li_at(v->magic.list, n))) {
810 struct list *tmp = li_dup(v->magic.list);
811 v_set(v, ptr);
812 li_delete(tmp);
813 } else {
814 v_set_undef(v);
815 }
816 return;
817 }
818
819 V_STR(v);
820 V_xxx_OFF(v);
821 V_NUM(b);
822 n = RINT(b->num);
823 if (n < 0) {
824 n += ko_length(v->ko);
825 }
826 if (n >= 0 && (size_t)n < ko_length(v->ko)) {
827 ko_shift(v->ko, n);
828 ko_trunc(v->ko, 1);
829 v->type = V_STR_K;
830 } else {
831 v->type = V_UNDEF;
832 }
833 }
834
835 void pp_shift(struct val *v, struct val *b) {
836 long p;
837
838 V_NUM(b);
839 p = RINT(b->num);
840
841 if (V_LIST_P(v)) {
842 v->type = V_LIST_K;
843 if (p < 0) {
844 p += li_length(v->magic.list);
845 }
846 if (p <= 0) {
847 return;
848 }
849 if ((size_t)p >= li_length(v->magic.list)) {
850 li_zero(v->magic.list);
851 } else {
852 li_shift(v->magic.list, p);
853 }
854 return;
855 }
856
857 V_STR(v);
858 V_xxx_OFF(v);
859 v->type = V_STR_K;
860 if (p < 0) {
861 p += ko_length(v->ko);
862 }
863 if (p <= 0) {
864 return;
865 }
866 if ((size_t)p >= ko_length(v->ko)) {
867 ko_zero(v->ko);
868 } else {
869 ko_shift(v->ko, p);
870 }
871 }
872
873 void pp_sub(struct val *v, struct val *b) {
874 ARITH(-);
875 }
876
877 void pp_tobase(struct val *v, struct val *b) {
878 double p;
879 int base, sign;
880 size_t i;
881
882 V_NUM(b);
883 V_NUM(v);
884 V_xxx_OFF(v);
885
886 if (floor(b->num + .5) < 2. || floor(b->num + .5) > 36.) {
887 v->type = V_UNDEF;
888 return;
889 }
890 base = floor(b->num + .5);
891
892 sign = 0;
893 if (v->num < 0.) {
894 v->num = -v->num;
895 sign = 1;
896 }
897
898 p = v->num;
899 ko_zero(v->ko);
900
901 if (floor(p) < p) {
902 double foo, bar;
903 size_t rounds;
904
905 foo = 1 + floor(log(pow(10, DBL_DIG)) / log(base));
906 bar = p > 0. ? 1 + floor(log(p) / log(base)) : 0.;
907 if (bar >= foo) {
908 rounds = 0;
909 } else {
910 rounds = foo - bar;
911 }
912
913 for (i = 0; i < rounds; ++i) {
914 p *= base;
915 if (floor(p) >= p) {
916 ++i;
917 break;
918 }
919 }
920
921 p = floor(p);
922 while (i--) {
923 int c;
924 c = fmod(p, base);
925 p = floor(p / base);
926 if (c >= 0) {
927 ko_cat_c(v->ko, xdigits[c]);
928 }
929 }
930 }
931
932 while (ko_at(v->ko, 0) == '0') {
933 ko_shift(v->ko, 1);
934 }
935
936 if (ko_length(v->ko)) {
937 ko_cat_c(v->ko, '.');
938 }
939
940 while (p > 0.) {
941 int c;
942 c = fmod(p, base);
943 p = floor(p / base);
944 if (c >= 0) {
945 ko_cat_c(v->ko, xdigits[c]);
946 }
947 }
948
949 if (!ko_length(v->ko) || ko_lastchar(v->ko) == '.') {
950 ko_cat_c(v->ko, '0');
951 }
952 if (sign) {
953 ko_cat_c(v->ko, '-');
954 }
955
956 v->type = V_STR_K;
957 }