1 /******************************************************************************
2 * This file is part of TinTin++ *
3 * *
4 * Copyright 2004-2019 Igor van den Hoven *
5 * *
6 * TinTin++ is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with TinTin++. If not, see https://www.gnu.org/licenses. *
19 ******************************************************************************/
20
21 /******************************************************************************
22 * (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t *
23 * *
24 * coded by Bill Reiss 1993 *
25 * recoded by Igor van den Hoven 2004 *
26 ******************************************************************************/
27
28 #include "tintin.h"
29
DO_COMMAND(do_variable)30 DO_COMMAND(do_variable)
31 {
32 char *str;
33 struct listroot *root = ses->list[LIST_VARIABLE];
34 struct listnode *node;
35
36 arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
37
38 if (*arg1 == 0)
39 {
40 show_list(root, 0);
41 }
42 else if (*arg == 0)
43 {
44 node = search_nest_node(root, arg1);
45
46 if (node)
47 {
48 if (node->root)
49 {
50 char *str_result;
51
52 str_result = str_alloc_stack(0);
53
54 view_nest_node(node, &str_result, 0, TRUE, TRUE);
55
56 print_lines(ses, SUB_NONE, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s" COLOR_BRACE "}" COLOR_RESET "\n", gtd->tintin_char, list_table[LIST_VARIABLE].name, node->arg1, str_result);
57 }
58 else
59 {
60 tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}" COLOR_RESET "\n", gtd->tintin_char, list_table[LIST_VARIABLE].name, node->arg1, node->arg2);
61 }
62 }
63 else if (show_node_with_wild(ses, arg1, ses->list[LIST_VARIABLE]) == FALSE)
64 {
65 show_message(ses, LIST_VARIABLE, "#VARIABLE: NO MATCH(ES) FOUND FOR {%s}.", arg1);
66 }
67 }
68 else
69 {
70 if (!valid_variable(ses, arg1))
71 {
72 show_error(ses, LIST_VARIABLE, "#VARIABLE: INVALID VARIALBE NAME {%s}.", arg1);
73
74 return ses;
75 }
76 str = str_alloc_stack(strlen(arg));
77
78 arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
79
80 node = set_nest_node(root, arg1, "%s", str);
81
82 while (*arg)
83 {
84 arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
85
86 if (*str)
87 {
88 add_nest_node(root, arg1, "%s", str);
89 }
90 }
91
92 show_nest_node(node, &str, 1);
93
94 show_message(ses, LIST_VARIABLE, "#OK. VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
95 }
96 return ses;
97 }
98
DO_COMMAND(do_unvariable)99 DO_COMMAND(do_unvariable)
100 {
101 arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
102
103 do
104 {
105 if (delete_nest_node(ses->list[LIST_VARIABLE], arg1))
106 {
107 show_message(ses, LIST_VARIABLE, "#OK. {%s} IS NO LONGER A VARIABLE.", arg1);
108 }
109 else
110 {
111 delete_node_with_wild(ses, LIST_VARIABLE, arg1);
112 }
113 arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
114 }
115 while (*arg1);
116
117 return ses;
118 }
119
DO_COMMAND(do_local)120 DO_COMMAND(do_local)
121 {
122 char *str;
123 struct listroot *root;
124 struct listnode *node;
125
126 root = local_list(ses);
127
128 arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
129
130 if (*arg1 == 0)
131 {
132 show_list(root, 0);
133 }
134 else if (*arg1 && *arg == 0)
135 {
136 root = search_nest_base_ses(ses, arg1);
137
138 if (root)
139 {
140 node = search_nest_node_ses(ses, arg1);
141 }
142 else
143 {
144 root = local_list(ses);
145 node = NULL;
146 }
147
148 if (node)
149 {
150 show_node(root, node, 0);
151 }
152 else if (show_node_with_wild(ses, arg1, root) == FALSE)
153 {
154 show_message(ses, LIST_VARIABLE, "#LOCAL: NO MATCH(ES) FOUND FOR {%s}.", arg1);
155 }
156 }
157 else
158 {
159 str = str_alloc_stack(strlen(arg));
160
161 arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
162
163 DEL_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
164
165 node = set_nest_node(root, arg1, "%s", str);
166
167 SET_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
168
169 while (*arg)
170 {
171 arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
172
173 if (*str)
174 {
175 add_nest_node(root, arg1, "%s", str);
176 }
177 }
178
179 show_nest_node(node, &str, 1);
180
181 show_message(ses, LIST_VARIABLE, "#OK. LOCAL VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
182 }
183 return ses;
184 }
185
DO_COMMAND(do_unlocal)186 DO_COMMAND(do_unlocal)
187 {
188 struct listroot *root;
189 int index, found;
190
191 arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
192
193 root = local_list(ses);
194
195 do
196 {
197 if (delete_nest_node(root, arg1))
198 {
199 show_message(ses, LIST_VARIABLE, "#OK. {%s} IS NO LONGER A LOCAL VARIABLE.", arg1);
200 }
201 else
202 {
203 found = FALSE;
204
205 for (index = root->used - 1 ; index >= 0 ; index--)
206 {
207 if (match(ses, root->list[index]->arg1, arg1, SUB_VAR|SUB_FUN))
208 {
209 show_message(ses, LIST_VARIABLE, "#OK. {%s} IS NO LONGER A LOCAL VARIABLE.", root->list[index]->arg1);
210
211 delete_index_list(root, index);
212
213 found = TRUE;
214 }
215 }
216
217 if (found == 0)
218 {
219 show_message(ses, LIST_VARIABLE, "#UNLOCAL: NO MATCHES FOUND FOR {%s}.", arg1);
220 }
221 }
222 arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
223 }
224 while (*arg1);
225
226 return ses;
227 }
228
DO_COMMAND(do_cat)229 DO_COMMAND(do_cat)
230 {
231 char *str, name[BUFFER_SIZE];
232 struct listroot *root;
233 struct listnode *node;
234
235 arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
236
237 if (*arg1 == 0 || *arg == 0)
238 {
239 show_error(ses, LIST_COMMAND, "#SYNTAX: CAT {<VARIABLE>} {<ARGUMENT>}");
240 }
241 else
242 {
243 str = str_alloc_stack(strlen(arg));
244
245 if ((node = search_nest_node_ses(ses, arg1)) == NULL)
246 {
247 arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
248
249 node = set_nest_node(ses->list[LIST_VARIABLE], arg1, "");
250 }
251
252 root = search_nest_base_ses(ses, arg1);
253
254 get_arg_to_brackets(ses, arg1, name);
255
256 check_all_events(ses, EVENT_FLAG_VARIABLE, 1, 3, "VARIABLE UPDATE %s", name, name, node->arg2, arg1);
257
258 while (*arg)
259 {
260 arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
261
262 if (*str)
263 {
264 if (node->root)
265 {
266 add_nest_node(root, arg1, "%s", str);
267 }
268 else
269 {
270 str_cat(&node->arg2, str);
271 }
272 }
273 }
274
275 check_all_events(ses, EVENT_FLAG_VARIABLE, 1, 3, "VARIABLE UPDATED %s", name, name, node->arg2, arg1);
276
277 show_nest_node(node, &str, 1);
278
279 show_message(ses, LIST_VARIABLE, "#CAT: VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
280 }
281 return ses;
282 }
283
DO_COMMAND(do_replace)284 DO_COMMAND(do_replace)
285 {
286 char *tmp, *pti, *ptm, *str;
287 struct listnode *node;
288
289 arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
290 arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
291 arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR);
292
293 if (*arg1 == 0 || *arg2 == 0)
294 {
295 show_error(ses, LIST_VARIABLE, "#SYNTAX: #REPLACE {VARIABLE} {OLD TEXT} {NEW TEXT}");
296
297 return ses;
298 }
299
300 if ((node = search_nest_node_ses(ses, arg1)) == NULL)
301 {
302 show_error(ses, LIST_VARIABLE, "#REPLACE: VARIABLE {%s} NOT FOUND.", arg1);
303
304 return ses;
305 }
306
307 if (tintin_regexp(ses, NULL, node->arg2, arg2, 0, REGEX_FLAG_CMD) == FALSE)
308 {
309 show_message(ses, LIST_VARIABLE, "#REPLACE: {%s} NOT FOUND IN {%s}.", arg2, node->arg2);
310 }
311 else
312 {
313 show_debug(ses, LIST_VARIABLE, "#REPLACE {%s} {%s} {%s}", node->arg2, arg2, arg3);
314
315 pti = node->arg2;
316 str = str_alloc_stack(0);
317 tmp = str_alloc_stack(0);
318
319 do
320 {
321 if (*gtd->cmds[0] == 0) // Set by tintin_regexp
322 {
323 break;
324 }
325
326 ptm = strstr(pti, gtd->cmds[0]);
327
328 if (ptm == NULL)
329 {
330 break;
331 }
332
333 *ptm = 0;
334
335 substitute(ses, arg3, tmp, SUB_CMD|SUB_FUN);
336
337 str_cat_printf(&str, "%s%s", pti, tmp);
338
339 pti = ptm + strlen(gtd->cmds[0]);
340 }
341 while (tintin_regexp(ses, NULL, pti, arg2, 0, REGEX_FLAG_CMD));
342
343 str_cat(&str, pti);
344
345 str_cpy(&node->arg2, str);
346
347 }
348 return ses;
349 }
350
valid_variable(struct session * ses,char * arg)351 int valid_variable(struct session *ses, char *arg)
352 {
353 if (*arg == 0)
354 {
355 return FALSE;
356 }
357
358 if (is_math(ses, arg))
359 {
360 return FALSE;
361 }
362
363 if (strlen(arg) > 4096)
364 {
365 return FALSE;
366 }
367
368 if (is_digit(*arg))
369 {
370 show_error(ses, LIST_COMMAND, "\e[1;31m#WARNING: VALIDATE {%s}: VARIABLES SHOULD NOT START WITH A NUMBER.", arg);
371 }
372
373 return TRUE;
374 }
375
376 /*
377 support routines for #format
378 */
379
stringtobase(char * str,char * base)380 void stringtobase(char *str, char *base)
381 {
382 char *buf;
383
384 push_call("stringtobase(%p,%p)",str,base);
385
386 buf = strdup(str);
387
388 switch (atoi(base))
389 {
390 case 64:
391 str_to_base64(buf, str, strlen(str));
392 break;
393
394 case 252:
395 str_to_base252(buf, str, strlen(str));
396 break;
397
398 default:
399 tintin_printf2(gtd->ses, "#FORMAT: Unknown base conversion {%s}.", base);
400 break;
401 }
402 free(buf);
403
404 pop_call();
405 return;
406 }
407
basetostring(char * str,char * base)408 void basetostring(char *str, char *base)
409 {
410 char *buf;
411
412 push_call("basetostring(%p,%p)",str,base);
413
414 buf = strdup(str);
415
416 switch (atoi(base))
417 {
418 case 64:
419 base64_to_str(buf, str, strlen(str));
420 break;
421
422 case 252:
423 base252_to_str(buf, str, strlen(str));
424 break;
425
426 default:
427 tintin_printf2(gtd->ses, "#FORMAT: Unknown base conversion {%s}.", base);
428 break;
429 }
430 pop_call();
431 return;
432 }
433
stringtobasez(char * str,char * base)434 void stringtobasez(char *str, char *base)
435 {
436 char *buf;
437
438 push_call("stringtobase(%p,%p)",str,base);
439
440 buf = strdup(str);
441
442 switch (atoi(base))
443 {
444 case 64:
445 str_to_base64z(buf, str, strlen(str));
446 break;
447
448 case 252:
449 str_to_base252z(buf, str, strlen(str));
450 break;
451
452 default:
453 tintin_printf2(gtd->ses, "#FORMAT: Unknown base conversion {%s}.", base);
454 break;
455 }
456 free(buf);
457
458 pop_call();
459 return;
460 }
461
basetostringz(char * str,char * base)462 void basetostringz(char *str, char *base)
463 {
464 char *buf;
465
466 push_call("basetostring(%p,%p)",str,base);
467
468 buf = strdup(str);
469
470 switch (atoi(base))
471 {
472 case 64:
473 base64z_to_str(buf, str, strlen(str));
474 break;
475
476 case 252:
477 base252z_to_str(buf, str, strlen(str));
478 break;
479
480 default:
481 tintin_printf2(gtd->ses, "#FORMAT: Unknown base conversion {%s}.", base);
482 break;
483 }
484 pop_call();
485 return;
486 }
487
generate_hash_key(char * str)488 unsigned long long generate_hash_key(char *str)
489 {
490 unsigned long long len, h = 4321;
491
492 for (len = 0 ; *str != 0 ; str++, len++)
493 {
494 h = ((h << 5) + h) + *str;
495 }
496
497 h += len;
498
499 return h;
500 }
501
numbertocharacter(struct session * ses,char * str)502 void numbertocharacter(struct session *ses, char *str)
503 {
504 if (get_number(ses, str) < 256)
505 {
506 sprintf(str, "%c", (int) get_number(ses, str));
507 }
508 else if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC))
509 {
510 sprintf(str, "%c%c", (unsigned int) get_number(ses, str) % 256, (unsigned int) get_number(ses, str) / 256);
511 }
512 else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
513 {
514 unicode_to_utf8((int) get_number(ses, str), str);
515 }
516 else
517 {
518 sprintf(str, "%c", (int) get_number(ses, str));
519 }
520 }
521
charactertonumber(struct session * ses,char * str)522 void charactertonumber(struct session *ses, char *str)
523 {
524 int result;
525
526 if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, str))
527 {
528 if (get_euc_size(ses, str) == 4)
529 {
530 result = (unsigned char) str[0] + (unsigned char) str[1] * 256 + (unsigned char) str[2] * 256 * 256 + (unsigned char) str[3] * 256 * 256 * 256;
531 }
532 else
533 {
534 result = (unsigned char) str[0] + (unsigned char) str[1] * 256;
535 }
536 }
537 else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(str))
538 {
539 get_utf8_index(str, &result);
540 }
541 else
542 {
543 result = (unsigned char) str[0];
544 }
545 sprintf(str, "%d", result);
546 }
547
charactertohex(struct session * ses,char * str)548 void charactertohex(struct session *ses, char *str)
549 {
550 if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, str))
551 {
552 if (get_euc_size(ses, str) == 4)
553 {
554 sprintf(str, "%u", (unsigned char) str[0] + (unsigned char) str[1] * 256 + (unsigned char) str[2] * 256 * 256 + (unsigned char) str[3] * 256 * 256 * 256);
555 }
556 else
557 {
558 sprintf(str, "%u", (unsigned char) str[0] + (unsigned char) str[1] * 256);
559 }
560 }
561 else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(str))
562 {
563 int result;
564
565 get_utf8_index(str, &result);
566
567 sprintf(str, "%u", result);
568 }
569 else if (!is_math(ses, str))
570 {
571 sprintf(str, "%u", (unsigned int) str[0]);
572 }
573 }
574
575
colorstring(struct session * ses,char * str)576 void colorstring(struct session *ses, char *str)
577 {
578 char *result;
579
580 push_call("colorstring(%p,%p)",ses,str);
581
582 result = str_alloc_stack(0);
583
584 get_color_names(ses, str, result);
585
586 strcpy(str, result);
587
588 pop_call();
589 return;
590 }
591
headerstring(struct session * ses,char * str,char * columns)592 void headerstring(struct session *ses, char *str, char *columns)
593 {
594 char *buf, *fill;
595 int len, max;
596
597 push_call("headerstring(%p,%p,%p)",ses,str,columns);
598
599 buf = str_alloc_stack(0);
600 fill = str_alloc_stack(0);
601
602 max = *columns ? atoi(columns) : get_scroll_cols(ses);
603
604 len = string_raw_str_len(ses, str, 0, max);
605
606 if (len > max - 2)
607 {
608 pop_call();
609 return;
610 }
611
612 if (HAS_BIT(ses->config_flags, CONFIG_FLAG_SCREENREADER))
613 {
614 memset(fill, ' ', max);
615 }
616 else
617 {
618 memset(fill, '#', max);
619 }
620
621 sprintf(buf, "%.*s%s%.*s%s", (max - len) / 2, fill, str, (max - len) / 2, fill, (max - len) % 2 ? "#" : "");
622
623 strcpy(str, buf);
624
625 pop_call();
626 return;
627 }
628
lowerstring(char * str)629 void lowerstring(char *str)
630 {
631 char *pts;
632
633 for (pts = str ; *pts ; pts++)
634 {
635 *pts = tolower((int) *pts);
636 }
637 }
638
upperstring(char * str)639 void upperstring(char *str)
640 {
641 char *pts;
642
643 for (pts = str ; *pts ; pts++)
644 {
645 *pts = toupper((int) *pts);
646 }
647 }
648
hexstring(char * str)649 void hexstring(char *str)
650 {
651 unsigned long long result = hex_number_64bit(str);
652
653 unicode_to_utf8(result, str);
654 }
655
reversestring(char * str)656 void reversestring(char *str)
657 {
658 char *pts, *ptz, *dup = str_mim(str);
659 int skip;
660
661 pts = str;
662 ptz = dup + strlen(str);
663
664 *ptz-- = 0;
665
666 while (*pts)
667 {
668 switch (*pts)
669 {
670 case '\\':
671 skip = pts[1] ? 2 : 0;
672 break;
673
674 case '\e':
675 skip = skip_vt102_codes(pts);
676 break;
677
678 case '<':
679 skip = is_color_code(pts);
680 break;
681
682 default:
683 skip = 0;
684 break;
685 }
686
687 if (skip)
688 {
689 ptz -= skip;
690 memcpy(ptz + 1, pts, skip);
691 pts += skip;
692 }
693 else
694 {
695 *ptz-- = *pts++;
696 }
697 }
698 strcpy(str, dup);
699
700 str_free(dup);
701 }
702
mathstring(struct session * ses,char * str)703 void mathstring(struct session *ses, char *str)
704 {
705 get_number_string(ses, str, str);
706 }
707
thousandgroupingstring(struct session * ses,char * str)708 void thousandgroupingstring(struct session *ses, char *str)
709 {
710 char *result, *strold;
711 int cnt1, cnt2, cnt3, cnt4;
712
713 push_call("thousandsgroupingstring(%p,%p)",ses,str);
714
715 result = str_alloc_stack(0);
716 strold = str_alloc_stack(0);
717
718 get_number_string(ses, str, strold);
719
720 cnt1 = strlen(strold) - 1;
721 cnt2 = BUFFER_SIZE / 2;
722 cnt4 = strchr(strold, '.') ? 1 : 0;
723
724 result[cnt2+1] = 0;
725
726 for (cnt3 = 0 ; cnt1 >= 0 ; cnt1--, cnt2--)
727 {
728 if (cnt3++ % 3 == 0 && cnt3 != 1 && cnt4 == 0 && is_digit(strold[cnt1]))
729 {
730 result[cnt2--] = ',';
731 }
732
733 result[cnt2] = strold[cnt1];
734
735 if (!is_digit(result[cnt2]))
736 {
737 cnt4 = 0;
738 cnt3 = 0;
739 continue;
740 }
741 }
742
743 strcpy(str, result + cnt2 + 1);
744
745 pop_call();
746 return;
747 }
748
749 /*
750 void chronosgroupingstring(struct session *ses, char *str)
751 {
752 char *sign = "-";
753 long long val = (long long) get_number(ses, str);
754 int days, hours, minutes, seconds;
755
756 if (val < 0)
757 {
758 val *= -1;
759 }
760 else
761 {
762 sign = "";
763 }
764
765 seconds = val % 60;
766 val /= 60;
767
768 minutes = val % 60;
769 val /= 60;
770
771 hours = val % 24;
772 val /= 24;
773
774 days = val;
775
776 if (days)
777 {
778 sprintf(str, "%s%d:%02d:%02d:%02d", sign, days, hours, minutes, seconds);
779 }
780 else if (hours)
781 {
782 sprintf(str, "%s%d:%02d:%02d", sign, hours, minutes, seconds);
783 }
784 else
785 {
786 sprintf(str, "%s%d:%02d", sign, minutes, seconds);
787 }
788 }
789 */
790
metricgroupingstring(struct session * ses,char * str)791 void metricgroupingstring(struct session *ses, char *str)
792 {
793 char big[] = {' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', '?', '?', '?', '?', '?', '?', '?', '?'};
794 char small[] = {' ', 'm', 'u', 'n', 'p', 'f', 'a', 'z', 'y', '?', '?', '?', '?', '?', '?', '?', '?'};
795 char tmp[NUMBER_SIZE];
796 long double val = get_number(ses, str);
797 int index = 0;
798
799 if (val >= 1000)
800 {
801 while (val >= 1000)
802 {
803 val = val / 1000;
804 index++;
805 }
806 if (val >= 100)
807 {
808 sprintf(tmp, " %Lf", val);
809 }
810 else
811 {
812 sprintf(tmp, "%Lf", val);
813 }
814 sprintf(str, "%.4s%c", tmp, big[index]);
815 }
816 else if (val > 0 && val < 0.01)
817 {
818 while (val < 0.01)
819 {
820 val = val * 1000;
821 index++;
822 }
823 sprintf(tmp, "%Lf", val);
824 sprintf(str, "%.4s%c", tmp, small[index]);
825 }
826 else if (val >= 0)
827 {
828 if (val >= 100)
829 {
830 sprintf(tmp, " %Lf", val);
831 }
832 else
833 {
834 sprintf(tmp, "%Lf", val);
835 }
836 sprintf(str, "%.4s%c", tmp, big[index]);
837 }
838 else if (val <= -0.01 && val > -1000)
839 {
840 if (val <= -100)
841 {
842 sprintf(tmp, " %Lf", val);
843 }
844 else
845 {
846 sprintf(tmp, "%Lf", val);
847 }
848 sprintf(str, "%.5s%c", tmp, small[index]);
849 }
850 else if (val <= -1000)
851 {
852 while (val <= -100)
853 {
854 if (val <= -10000)
855 {
856 val = (long double) ((long long) val / 100LL * 100LL);
857 }
858 val = val / 1000;
859 index++;
860 }
861 sprintf(tmp, "%Lf", val);
862 sprintf(str, "%.5s%c", tmp, big[index]);
863 }
864
865 else if (val < 0 /*&& val > -0.01*/)
866 {
867 while (val > -0.01)
868 {
869 val = val * 1000;
870 index++;
871 }
872 sprintf(tmp, "%Lf", val);
873 sprintf(str, "%.5s%c", tmp, small[index]);
874 }
875 }
876
stripspaces(char * str)877 void stripspaces(char *str)
878 {
879 int cnt;
880
881 for (cnt = strlen(str) - 1 ; cnt >= 0 ; cnt--)
882 {
883 if (!is_space(str[cnt]))
884 {
885 break;
886 }
887 str[cnt] = 0;
888 }
889
890 for (cnt = 0 ; str[cnt] != 0 ; cnt++)
891 {
892 if (!is_space(str[cnt]))
893 {
894 break;
895 }
896 }
897 memmove(str, &str[cnt], strlen(&str[cnt]) + 1);
898 // strcpy(str, &str[cnt]);
899 }
900
wrapstring(struct session * ses,char * str,char * wrap)901 void wrapstring(struct session *ses, char *str, char *wrap)
902 {
903 char *arg1, *arg2;
904 char *pts, *pte, *arg;
905 int cnt, width, height;
906
907 push_call("wrapstring(%p,%p,%p)",ses,str,wrap);
908
909 arg1 = str_alloc_stack(0);
910 arg2 = str_alloc_stack(0);
911
912 // arg = sub_arg_in_braces(ses, str, arg1, GET_ALL, SUB_COL|SUB_LIT|SUB_ESC);
913 arg = sub_arg_in_braces(ses, str, arg1, GET_ALL, SUB_COL|SUB_ESC);
914
915 if (*arg == COMMAND_SEPARATOR)
916 {
917 arg++;
918 }
919
920 arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
921
922 if (*arg2)
923 {
924 cnt = get_number(ses, arg2);
925 }
926 else if (*wrap)
927 {
928 cnt = atoi(wrap);
929 }
930 else
931 {
932 cnt = get_scroll_cols(ses);
933 }
934
935 if (cnt <= 0)
936 {
937 cnt = get_scroll_cols(ses) + cnt;
938
939 if (cnt <= 0)
940 {
941 show_error(ses, LIST_VARIABLE, "#FORMAT %w: INVALID LENTGH {%s}", arg2);
942
943 pop_call();
944 return;
945 }
946 }
947
948 word_wrap_split(ses, arg1, arg2, cnt, 0, 0, 0, &height, &width);
949
950 pts = pte = arg2;
951
952 str[0] = cnt = 0;
953
954 while (*pte != 0)
955 {
956 if (*pte == '\n')
957 {
958 *pte++ = 0;
959
960 substitute(ses, pts, arg1, SUB_BRA);
961
962 cat_sprintf(str, "{%d}{%s}", ++cnt, arg1);
963
964 pts = pte;
965 }
966 else
967 {
968 pte++;
969 }
970 }
971 substitute(ses, pts, arg1, SUB_BRA);
972
973 cat_sprintf(str, "{%d}{%s}", ++cnt, arg1);
974
975 pop_call();
976 return;
977 }
978
stringlength(struct session * ses,char * str)979 int stringlength(struct session *ses, char *str)
980 {
981 int len;
982 char *temp;
983
984 push_call("stringlength(%p,%p)",ses,str);
985
986 temp = str_alloc_stack(0);
987
988 substitute(ses, str, temp, SUB_COL|SUB_ESC);
989
990 len = strip_vt102_strlen(ses, temp);
991
992 pop_call();
993 return len;
994 }
995
996
997 // stripped range raw return
998
string_str_raw_len(struct session * ses,char * str,int start,int end)999 int string_str_raw_len(struct session *ses, char *str, int start, int end)
1000 {
1001 int raw_cnt, str_cnt, ret_cnt, tmp_cnt, tot_len, width, col_len, skip;
1002
1003 raw_cnt = str_cnt = ret_cnt = 0;
1004
1005 tot_len = strlen(str);
1006
1007 while (raw_cnt < tot_len)
1008 {
1009 skip = skip_vt102_codes(&str[raw_cnt]);
1010
1011 if (skip)
1012 {
1013 if (str_cnt >= start)
1014 {
1015 ret_cnt += skip;
1016 }
1017 raw_cnt += skip;
1018
1019 continue;
1020 }
1021
1022 col_len = is_color_code(&str[raw_cnt]);
1023
1024 if (col_len)
1025 {
1026 ret_cnt += (str_cnt >= start) ? col_len : 0;
1027 raw_cnt += col_len;
1028
1029 continue;
1030 }
1031
1032 if (str_cnt >= end)
1033 {
1034 break;
1035 }
1036
1037 if (str[raw_cnt] == '\\')
1038 {
1039 ret_cnt += (str_cnt >= start) ? 1 : 0;
1040 raw_cnt++;
1041
1042 if (str[raw_cnt] == '\\')
1043 {
1044 ret_cnt += (str_cnt >= start) ? 1 : 0;
1045 raw_cnt++;
1046 str_cnt++;
1047 }
1048 continue;
1049 }
1050
1051 if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, &str[raw_cnt]))
1052 {
1053 tmp_cnt = get_euc_width(ses, &str[raw_cnt], &width);
1054
1055 if (str_cnt >= start)
1056 {
1057 ret_cnt += tmp_cnt;
1058 }
1059 raw_cnt += tmp_cnt;
1060 str_cnt += width;
1061 }
1062 else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
1063 {
1064 tmp_cnt = get_utf8_width(&str[raw_cnt], &width, NULL);
1065
1066 if (str_cnt >= start)
1067 {
1068 ret_cnt += tmp_cnt;
1069 }
1070 raw_cnt += tmp_cnt;
1071 str_cnt += width;
1072 }
1073 else
1074 {
1075 ret_cnt += (str_cnt >= start) ? 1 : 0;
1076 raw_cnt++;
1077 str_cnt++;
1078 }
1079 }
1080 return ret_cnt;
1081 }
1082
1083 // raw range stripped return
1084
string_raw_str_len(struct session * ses,char * str,int raw_start,int raw_end)1085 int string_raw_str_len(struct session *ses, char *str, int raw_start, int raw_end)
1086 {
1087 int raw_cnt, ret_cnt, tot_len, width, col_len;
1088
1089 raw_cnt = raw_start;
1090 ret_cnt = 0;
1091 tot_len = strlen(str);
1092
1093 while (raw_cnt < tot_len)
1094 {
1095 if (raw_end >= 0 && raw_cnt >= raw_end)
1096 {
1097 break;
1098 }
1099
1100 if (skip_vt102_codes(&str[raw_cnt]))
1101 {
1102 raw_cnt += skip_vt102_codes(&str[raw_cnt]);
1103
1104 continue;
1105 }
1106
1107 col_len = is_color_code(&str[raw_cnt]);
1108
1109 if (col_len)
1110 {
1111 raw_cnt += col_len;
1112
1113 continue;
1114 }
1115
1116 if (str[raw_cnt] == '\\')
1117 {
1118 raw_cnt++;
1119
1120 if (valid_escape(ses, &str[raw_cnt]))
1121 {
1122 raw_cnt++;
1123 ret_cnt++;
1124 }
1125 else
1126 {
1127 ret_cnt++;
1128 }
1129 continue;
1130 }
1131
1132 if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, &str[raw_cnt]))
1133 {
1134 raw_cnt += get_euc_width(ses, &str[raw_cnt], &width);
1135
1136 ret_cnt += width;
1137 }
1138 else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
1139 {
1140 raw_cnt += get_utf8_width(&str[raw_cnt], &width, NULL);
1141
1142 ret_cnt += width;
1143 }
1144 else
1145 {
1146 raw_cnt++;
1147 ret_cnt++;
1148 }
1149 }
1150 return ret_cnt;
1151 }
1152
timestring(struct session * ses,char * str)1153 void timestring(struct session *ses, char *str)
1154 {
1155 char *arg, *arg1, *arg2;
1156 struct tm timeval_tm;
1157 time_t timeval_t;
1158
1159 push_call("timestring(%p,%p)",ses,str);
1160
1161 arg1 = str_alloc_stack(0);
1162 arg2 = str_alloc_stack(0);
1163
1164 arg = get_arg_in_braces(ses, str, arg1, GET_ALL);
1165
1166 if (*arg == COMMAND_SEPARATOR)
1167 {
1168 arg++;
1169 }
1170 arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
1171
1172 if (*arg2)
1173 {
1174 timeval_t = (time_t) get_number(ses, arg2);
1175 }
1176 else
1177 {
1178 timeval_t = gtd->time;
1179 }
1180
1181 timeval_tm = *localtime(&timeval_t);
1182
1183 strftime(str, BUFFER_SIZE, arg1, &timeval_tm);
1184
1185 pop_call();
1186 return;
1187 }
1188
justify_string(struct session * ses,char * in,char * out,int align,int cut)1189 void justify_string(struct session *ses, char *in, char *out, int align, int cut)
1190 {
1191 char *temp;
1192
1193 push_call("justify_string(%p,%p,%p,%d,%d)",ses,in,out,align,cut);
1194
1195 temp = str_alloc_stack(0);
1196
1197 if (align < 0)
1198 {
1199 sprintf(temp, "%%%d.%ds", align - ((int) strlen(in) - string_raw_str_len(ses, in, 0, -1)), string_str_raw_len(ses, in, 0, cut));
1200 }
1201 else
1202 {
1203 sprintf(temp, "%%%d.%ds", align + ((int) strlen(in) - string_raw_str_len(ses, in, 0, -1)), string_str_raw_len(ses, in, 0, cut));
1204 }
1205
1206 sprintf(out, temp, in);
1207
1208 pop_call();
1209 return;
1210 }
1211
format_string(struct session * ses,char * format,char * arg,char * out)1212 void format_string(struct session *ses, char *format, char *arg, char *out)
1213 {
1214 char *arglist[30];
1215 char *argformat, *newformat, *arg1, *arg2, *ptf, *ptt, *pts, *ptn;
1216 struct tm timeval_tm;
1217 time_t timeval_t;
1218 int i, max;
1219
1220 argformat = str_alloc_stack(0);
1221 newformat = str_alloc_stack(0);
1222
1223 arg1 = str_alloc_stack(0);
1224 arg2 = str_alloc_stack(0);
1225
1226 for (max = 0 ; max < 4 ; max++)
1227 {
1228 arglist[max] = str_alloc_stack(0);
1229
1230 arg = sub_arg_in_braces(ses, arg, arglist[max], GET_ONE, SUB_VAR|SUB_FUN);
1231 }
1232
1233 for (max = 4 ; *arg && max < 30 ; max++)
1234 {
1235 arglist[max] = str_alloc_stack(0);
1236
1237 arg = sub_arg_in_braces(ses, arg, arglist[max], GET_ONE, SUB_VAR|SUB_FUN);
1238 }
1239
1240 for (i = max ; i < 30 ; i++)
1241 {
1242 arglist[i] = "";
1243 }
1244
1245 i = 0;
1246
1247 ptf = format;
1248 ptn = newformat;
1249
1250 while (*ptf)
1251 {
1252 if (*ptf == '%')
1253 {
1254 if (i >= max)
1255 {
1256 *ptn++ = *ptf++;
1257 *ptn++ = '%';
1258 i++;
1259 continue;
1260 }
1261 pts = ptn;
1262
1263 *ptn++ = *ptf++;
1264
1265 if (*ptf == 0)
1266 {
1267 *ptn++ = '%';
1268 break;
1269 }
1270 else if (*ptf == '%')
1271 {
1272 *ptn++ = *ptf++;
1273 }
1274 else if (*ptf == ' ')
1275 {
1276 *ptn++ = '%';
1277 }
1278 else
1279 {
1280 while (!is_alpha(*ptf))
1281 {
1282 if (*ptf == 0)
1283 {
1284 break;
1285 }
1286 *ptn++ = *ptf++;
1287 }
1288
1289 *ptn = 0;
1290
1291 switch (*ptf)
1292 {
1293 case 0:
1294 show_error(ses, LIST_VARIABLE, "#FORMAT STRING: UNKNOWN ARGUMENT {%s}.", pts);
1295 continue;
1296
1297 case 'd':
1298 case 'f':
1299 case 'X':
1300 strcpy(argformat, pts);
1301
1302 ptn = pts + 1;
1303 *ptn = 0;
1304 break;
1305
1306 case 'b':
1307 case 'B':
1308 case 'h':
1309 case 'w':
1310 case 'z':
1311 case 'Z':
1312 strcpy(argformat, pts+1);
1313 ptn = pts + 1;
1314 *ptn = 0;
1315 break;
1316
1317 default:
1318 if (pts[1])
1319 {
1320 ptt = arg1;
1321 ptn = pts + 1;
1322
1323 while (*ptn && *ptn != '.')
1324 {
1325 *ptt++ = *ptn++;
1326 }
1327
1328 *ptt = 0;
1329
1330 if (*ptn == 0)
1331 {
1332 if (atoi(arg1) < 0)
1333 {
1334 sprintf(argformat, "%%%d", atoi(arg1) - ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, -1)));
1335 }
1336 else
1337 {
1338 sprintf(argformat, "%%%d", atoi(arg1) + ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, -1)));
1339 }
1340 }
1341 else
1342 {
1343 ptt = arg2;
1344 ptn = ptn + 1;
1345
1346 while (*ptn)
1347 {
1348 *ptt++ = *ptn++;
1349 }
1350
1351 *ptt = 0;
1352
1353 if (atoi(arg1) < 0)
1354 {
1355 sprintf(argformat, "%%%d.%d",
1356 atoi(arg1) - ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, -1)),
1357 string_str_raw_len(ses, arglist[i], 0, atoi(arg2)));
1358 }
1359 else
1360 {
1361 sprintf(argformat, "%%%d.%d",
1362 atoi(arg1) + ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, -1)),
1363 string_str_raw_len(ses, arglist[i], 0, atoi(arg2)));
1364 }
1365 }
1366
1367 ptt = argformat;
1368 ptn = pts;
1369
1370 while (*ptt)
1371 {
1372 *ptn++ = *ptt++;
1373 }
1374
1375 *ptn = 0;
1376 }
1377 }
1378
1379 switch (*ptf)
1380 {
1381 case 'a':
1382 numbertocharacter(ses, arglist[i]);
1383 break;
1384
1385 case 'b':
1386 substitute(ses, arglist[i], arglist[i], SUB_VAR|SUB_FUN);
1387 stringtobase(arglist[i], argformat);
1388 break;
1389
1390 case 'c':
1391 colorstring(ses, arglist[i]);
1392 break;
1393
1394 case 'd':
1395 strcat(argformat, "lld");
1396 sprintf(arglist[i], argformat, (long long) get_number(ses, arglist[i]));
1397 break;
1398
1399 case 'f':
1400 strcat(argformat, "Lf");
1401 sprintf(arglist[i], argformat, get_double(ses, arglist[i]));
1402 break;
1403
1404 case 'g':
1405 thousandgroupingstring(ses, arglist[i]);
1406 break;
1407
1408 case 'h':
1409 substitute(ses, arglist[i], arglist[i], SUB_VAR|SUB_FUN);
1410 headerstring(ses, arglist[i], argformat);
1411 break;
1412
1413 case 'l':
1414 lowerstring(arglist[i]);
1415 break;
1416
1417 case 'm':
1418 mathstring(ses, arglist[i]);
1419 break;
1420
1421 case 'n':
1422 arglist[i][0] = toupper((int) arglist[i][0]);
1423 break;
1424
1425 case 'p':
1426 stripspaces(arglist[i]);
1427 break;
1428
1429 case 'r':
1430 reversestring(arglist[i]);
1431 break;
1432
1433 case 's':
1434 break;
1435
1436 case 't':
1437 timestring(ses, arglist[i]);
1438 break;
1439
1440 case 'u':
1441 upperstring(arglist[i]);
1442 break;
1443
1444 case 'w':
1445 substitute(ses, arglist[i], arglist[i], SUB_VAR|SUB_FUN);
1446 wrapstring(ses, arglist[i], argformat);
1447 break;
1448
1449 case 'x':
1450 hexstring(arglist[i]);
1451 break;
1452
1453 case 'z':
1454 substitute(ses, arglist[i], arglist[i], SUB_VAR|SUB_FUN);
1455 stringtobasez(arglist[i], argformat);
1456 break;
1457
1458 case 'A':
1459 charactertonumber(ses, arglist[i]);
1460 break;
1461
1462 case 'B':
1463 substitute(ses, arglist[i], arglist[i], SUB_VAR|SUB_FUN);
1464 basetostring(arglist[i], argformat);
1465 break;
1466
1467 case 'C':
1468 tintin_printf2(ses, "\e[1;31m#echo/#format %%C please use #screen {get} {cols} to get screen width.");
1469 // chronosgroupingstring(ses, arglist[i]);
1470 break;
1471
1472 case 'D':
1473 sprintf(arglist[i], "%llu", hex_number_64bit(arglist[i]));
1474
1475 break;
1476
1477 case 'G':
1478 thousandgroupingstring(ses, arglist[i]);
1479 break;
1480
1481 case 'H':
1482 sprintf(arglist[i], "%llu", generate_hash_key(arglist[i]));
1483 break;
1484
1485 case 'L':
1486 sprintf(arglist[i], "%d", stringlength(ses, arglist[i]));
1487 break;
1488
1489 case 'M':
1490 metricgroupingstring(ses, arglist[i]);
1491 break;
1492
1493 case 'R':
1494 if (*arglist[i] == 0)
1495 {
1496 sprintf(arglist[i], "%d", gtd->screen->rows);
1497 }
1498 else
1499 {
1500 sprintf(arglist[i], "%d", get_row_index_arg(ses, arglist[i]));
1501 }
1502 break;
1503
1504 case 'S':
1505 sprintf(arglist[i], "%d", spellcheck_count(ses, arglist[i]));
1506 break;
1507
1508 case 'T':
1509 sprintf(arglist[i], "%ld", gtd->time);
1510 break;
1511
1512 case 'U':
1513 sprintf(arglist[i], "%lld", ++gtd->utime);
1514 break;
1515
1516 case 'X':
1517 strcat(argformat, "llX");
1518 charactertohex(ses, arglist[i]);
1519 sprintf(arglist[i], argformat, (unsigned long long) get_number(ses, arglist[i]));
1520 break;
1521
1522 // undocumented
1523 case 'Y': // print the year, experimental
1524 timeval_t = (time_t) *arglist[i] ? atoll(arglist[i]) : gtd->time;
1525 timeval_tm = *localtime(&timeval_t);
1526 strftime(arglist[i], BUFFER_SIZE, "%Y", &timeval_tm);
1527 break;
1528
1529 case 'Z':
1530 substitute(ses, arglist[i], arglist[i], SUB_VAR|SUB_FUN);
1531 basetostringz(arglist[i], argformat);
1532 break;
1533
1534 default:
1535 show_error(ses, LIST_VARIABLE, "#FORMAT STRING: UNKNOWN ARGUMENT {%s%c}.", pts, *ptf);
1536 break;
1537 }
1538 *ptn++ = 's';
1539 i++;
1540 ptf++;
1541 }
1542 }
1543 else
1544 {
1545 *ptn++ = *ptf++;
1546 }
1547 }
1548 *ptn = 0;
1549
1550 snprintf(out, BUFFER_SIZE - 1, newformat, arglist[0], arglist[1], arglist[2], arglist[3], arglist[4], arglist[5], arglist[6], arglist[7], arglist[8], arglist[9], arglist[10], arglist[11], arglist[12], arglist[13], arglist[14], arglist[15], arglist[16], arglist[17], arglist[18], arglist[19], arglist[20], arglist[21], arglist[22], arglist[23], arglist[24], arglist[25], arglist[26], arglist[27], arglist[28], arglist[29]);
1551
1552 return;
1553 }
1554
DO_COMMAND(do_format)1555 DO_COMMAND(do_format)
1556 {
1557 char *argvar, *format, *result;
1558
1559 argvar = arg1;
1560 format = arg2;
1561 result = arg3;
1562
1563 arg = sub_arg_in_braces(ses, arg, argvar, GET_NST, SUB_VAR|SUB_FUN);
1564 arg = sub_arg_in_braces(ses, arg, format, GET_ONE, SUB_VAR|SUB_FUN);
1565
1566 if (*argvar == 0)
1567 {
1568 show_error(ses, LIST_VARIABLE, "#SYNTAX: #format {variable} {format} {arg1} {arg2}");
1569
1570 return ses;
1571 }
1572
1573 format_string(ses, format, arg, result);
1574
1575 set_nest_node_ses(ses, argvar, "%s", result);
1576
1577 show_message(ses, LIST_VARIABLE, "#OK. VARIABLE {%s} HAS BEEN SET TO {%s}.", argvar, result);
1578
1579 return ses;
1580 }
1581