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