variable.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404
  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. * (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t *
  22. * *
  23. * coded by Bill Reiss 1993 *
  24. * recoded by Igor van den Hoven 2004 *
  25. ******************************************************************************/
  26. #include "tintin.h"
  27. DO_COMMAND(do_variable)
  28. {
  29. char arg1[BUFFER_SIZE], *str;
  30. struct listroot *root = ses->list[LIST_VARIABLE];
  31. struct listnode *node;
  32. arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
  33. if (*arg1 == 0)
  34. {
  35. show_list(root, 0);
  36. }
  37. else if (*arg == 0)
  38. {
  39. node = search_nest_node(root, arg1);
  40. if (node)
  41. {
  42. if (node->root)
  43. {
  44. char *str_result;
  45. str_result = str_dup("");
  46. view_nest_node(node, &str_result, 0, 1);
  47. 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);
  48. str_free(str_result);
  49. }
  50. else
  51. {
  52. 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);
  53. }
  54. }
  55. else if (show_node_with_wild(ses, arg1, ses->list[LIST_VARIABLE]) == FALSE)
  56. {
  57. show_message(ses, LIST_VARIABLE, "#VARIABLE: NO MATCH(ES) FOUND FOR {%s}.", arg1);
  58. }
  59. }
  60. else
  61. {
  62. if (!valid_variable(ses, arg1))
  63. {
  64. show_message(ses, LIST_VARIABLE, "#VARIABLE: INVALID VARIALBE NAME {%s}.", arg1);
  65. return ses;
  66. }
  67. str = str_alloc(UMAX(strlen(arg), BUFFER_SIZE));
  68. arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
  69. node = set_nest_node(root, arg1, "%s", str);
  70. while (*arg)
  71. {
  72. arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
  73. if (*str)
  74. {
  75. add_nest_node(root, arg1, "%s", str);
  76. }
  77. }
  78. show_nest_node(node, &str, 1);
  79. show_message(ses, LIST_VARIABLE, "#OK. VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
  80. str_free(str);
  81. }
  82. return ses;
  83. }
  84. DO_COMMAND(do_local)
  85. {
  86. char arg1[BUFFER_SIZE], *str;
  87. struct listroot *root;
  88. struct listnode *node;
  89. root = local_list(ses);
  90. arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
  91. if (*arg1 == 0)
  92. {
  93. show_list(root, 0);
  94. }
  95. else if (*arg1 && *arg == 0)
  96. {
  97. root = search_nest_base_ses(ses, arg1);
  98. if (root)
  99. {
  100. node = search_nest_node_ses(ses, arg1);
  101. }
  102. else
  103. {
  104. root = local_list(ses);
  105. node = NULL;
  106. }
  107. if (node)
  108. {
  109. show_node(root, node, 0);
  110. }
  111. else if (show_node_with_wild(ses, arg1, root) == FALSE)
  112. {
  113. show_message(ses, LIST_VARIABLE, "#LOCAL: NO MATCH(ES) FOUND FOR {%s}.", arg1);
  114. }
  115. }
  116. else
  117. {
  118. str = str_alloc(UMAX(strlen(arg), BUFFER_SIZE));
  119. arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
  120. node = set_nest_node(root, arg1, "%s", str);
  121. while (*arg)
  122. {
  123. arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
  124. if (*str)
  125. {
  126. add_nest_node(root, arg1, "%s", str);
  127. }
  128. }
  129. show_nest_node(node, &str, 1);
  130. show_message(ses, LIST_VARIABLE, "#OK. LOCAL VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
  131. str_free(str);
  132. SET_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
  133. }
  134. return ses;
  135. }
  136. DO_COMMAND(do_unvariable)
  137. {
  138. char arg1[BUFFER_SIZE];
  139. arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
  140. do
  141. {
  142. if (delete_nest_node(ses->list[LIST_VARIABLE], arg1))
  143. {
  144. show_message(ses, LIST_VARIABLE, "#OK. {%s} IS NO LONGER A VARIABLE.", arg1);
  145. }
  146. else
  147. {
  148. delete_node_with_wild(ses, LIST_VARIABLE, arg1);
  149. }
  150. arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
  151. }
  152. while (*arg1);
  153. return ses;
  154. }
  155. DO_COMMAND(do_cat)
  156. {
  157. char arg1[BUFFER_SIZE], *str;
  158. struct listnode *node;
  159. arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
  160. if (*arg1 == 0 || *arg == 0)
  161. {
  162. show_error(ses, LIST_COMMAND, "#SYNTAX: CAT {<VARIABLE>} {<ARGUMENT>}");
  163. }
  164. else
  165. {
  166. str = str_alloc(UMAX(strlen(arg), BUFFER_SIZE));
  167. if ((node = search_nest_node_ses(ses, arg1)) == NULL)
  168. {
  169. arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
  170. node = set_nest_node(ses->list[LIST_VARIABLE], arg1, "%s", str);
  171. }
  172. while (*arg)
  173. {
  174. arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
  175. check_all_events(ses, SUB_ARG, 1, 2, "VARIABLE UPDATE %s", arg1, arg1, str);
  176. if (*str)
  177. {
  178. str_cat(&node->arg2, str);
  179. }
  180. }
  181. check_all_events(ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", arg1, arg1, str);
  182. show_message(ses, LIST_VARIABLE, "#CAT: VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, node->arg2);
  183. str_free(str);
  184. }
  185. return ses;
  186. }
  187. DO_COMMAND(do_replace)
  188. {
  189. char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], tmp[BUFFER_SIZE], *pti, *ptm, *str;
  190. struct listnode *node;
  191. arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
  192. arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
  193. arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN);
  194. if (*arg1 == 0 || *arg2 == 0)
  195. {
  196. show_error(ses, LIST_VARIABLE, "#SYNTAX: #REPLACE {VARIABLE} {OLD TEXT} {NEW TEXT}");
  197. return ses;
  198. }
  199. if ((node = search_nest_node_ses(ses, arg1)) == NULL)
  200. {
  201. show_error(ses, LIST_VARIABLE, "#REPLACE: VARIABLE {%s} NOT FOUND.", arg1);
  202. return ses;
  203. }
  204. if (tintin_regexp(ses, NULL, node->arg2, arg2, 0, REGEX_FLAG_CMD) == FALSE)
  205. {
  206. show_message(ses, LIST_VARIABLE, "#REPLACE: {%s} NOT FOUND IN {%s}.", arg2, node->arg2);
  207. }
  208. else
  209. {
  210. pti = node->arg2;
  211. str = str_dup("");
  212. do
  213. {
  214. if (*gtd->cmds[0] == 0) // Set by tintin_regexp
  215. {
  216. break;
  217. }
  218. ptm = strstr(pti, gtd->cmds[0]);
  219. if (ptm == NULL)
  220. {
  221. break;
  222. }
  223. *ptm = 0;
  224. substitute(ses, arg3, tmp, SUB_CMD);
  225. str_cat_printf(&str, "%s%s", pti, tmp);
  226. pti = ptm + strlen(gtd->cmds[0]);
  227. }
  228. while (tintin_regexp(ses, NULL, pti, arg2, 0, REGEX_FLAG_CMD));
  229. str_cat(&str, pti);
  230. str_cpy(&node->arg2, str);
  231. str_free(str);
  232. }
  233. return ses;
  234. }
  235. int valid_variable(struct session *ses, char *arg)
  236. {
  237. if (*arg == 0)
  238. {
  239. return FALSE;
  240. }
  241. if (is_math(ses, arg))
  242. {
  243. return FALSE;
  244. }
  245. return TRUE;
  246. }
  247. /*
  248. support routines for #format
  249. */
  250. unsigned long long generate_hash_key(char *str)
  251. {
  252. unsigned long long len, h = 4321;
  253. for (len = 0 ; *str != 0 ; str++, len++)
  254. {
  255. h = ((h << 5) + h) + *str;
  256. }
  257. h += len;
  258. return h;
  259. }
  260. void numbertocharacter(struct session *ses, char *str)
  261. {
  262. if (get_number(ses, str) < 256)
  263. {
  264. sprintf(str, "%c", (int) get_number(ses, str));
  265. }
  266. else if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC))
  267. {
  268. sprintf(str, "%c%c", (unsigned int) get_number(ses, str) % 256, (unsigned int) get_number(ses, str) / 256);
  269. }
  270. else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
  271. {
  272. unicode_to_utf8((int) get_number(ses, str), str);
  273. }
  274. else
  275. {
  276. sprintf(str, "%c", (int) get_number(ses, str));
  277. }
  278. }
  279. void charactertonumber(struct session *ses, char *str)
  280. {
  281. int result;
  282. if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, str))
  283. {
  284. if (get_euc_size(ses, str) == 4)
  285. {
  286. result = (unsigned char) str[0] + (unsigned char) str[1] * 256 + (unsigned char) str[2] * 256 * 256 + (unsigned char) str[3] * 256 * 256 * 256;
  287. }
  288. else
  289. {
  290. result = (unsigned char) str[0] + (unsigned char) str[1] * 256;
  291. }
  292. }
  293. else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(str))
  294. {
  295. get_utf8_index(str, &result);
  296. }
  297. else
  298. {
  299. result = (unsigned char) str[0];
  300. }
  301. sprintf(str, "%d", result);
  302. }
  303. void charactertohex(struct session *ses, char *str)
  304. {
  305. if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, str))
  306. {
  307. if (get_euc_size(ses, str) == 4)
  308. {
  309. 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);
  310. }
  311. else
  312. {
  313. sprintf(str, "%u", (unsigned char) str[0] + (unsigned char) str[1] * 256);
  314. }
  315. }
  316. else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(str))
  317. {
  318. int result;
  319. get_utf8_index(str, &result);
  320. sprintf(str, "%u", result);
  321. }
  322. else if (!is_math(ses, str))
  323. {
  324. sprintf(str, "%u", (unsigned int) str[0]);
  325. }
  326. }
  327. void colorstring(struct session *ses, char *str)
  328. {
  329. char result[BUFFER_SIZE];
  330. get_color_names(ses, str, result);
  331. strcpy(str, result);
  332. }
  333. int translate_color_names(struct session *ses, char *string, char *result)
  334. {
  335. int cnt;
  336. *result = 0;
  337. if (*string == '<')
  338. {
  339. strcpy(result, string);
  340. return TRUE;
  341. }
  342. if (*string == '\\')
  343. {
  344. strcpy(result, string);
  345. return TRUE;
  346. }
  347. while (*string)
  348. {
  349. if (isalpha(*string))
  350. {
  351. for (cnt = 0 ; *color_table[cnt].name ; cnt++)
  352. {
  353. if (!strncmp(color_table[cnt].name, string, color_table[cnt].len))
  354. {
  355. result += sprintf(result, "%s", color_table[cnt].code);
  356. break;
  357. }
  358. }
  359. if (*color_table[cnt].name == 0)
  360. {
  361. for (cnt = 0 ; *color_table[cnt].name ; cnt++)
  362. {
  363. if (!strncasecmp(color_table[cnt].name, string, color_table[cnt].len))
  364. {
  365. result += sprintf(result, "%s", color_table[cnt].code);
  366. break;
  367. }
  368. }
  369. if (*color_table[cnt].name == 0)
  370. {
  371. return FALSE;
  372. }
  373. }
  374. string += strlen(color_table[cnt].name);
  375. }
  376. switch (*string)
  377. {
  378. case ' ':
  379. case ';':
  380. case ',':
  381. case '{':
  382. case '}':
  383. string++;
  384. break;
  385. case 0:
  386. return TRUE;
  387. default:
  388. return FALSE;
  389. }
  390. }
  391. return TRUE;
  392. }
  393. int get_color_names(struct session *ses, char *string, char *result)
  394. {
  395. int cnt;
  396. *result = 0;
  397. if (*string == '<')
  398. {
  399. substitute(ses, string, result, SUB_COL);
  400. return TRUE;
  401. }
  402. if (*string == '\\')
  403. {
  404. substitute(ses, string, result, SUB_ESC);
  405. return TRUE;
  406. }
  407. while (*string)
  408. {
  409. if (isalpha(*string))
  410. {
  411. for (cnt = 0 ; *color_table[cnt].name ; cnt++)
  412. {
  413. if (!strncmp(color_table[cnt].name, string, color_table[cnt].len))
  414. {
  415. substitute(ses, color_table[cnt].code, result, SUB_COL);
  416. result += strlen(result);
  417. break;
  418. }
  419. }
  420. if (*color_table[cnt].name == 0)
  421. {
  422. for (cnt = 0 ; *color_table[cnt].name ; cnt++)
  423. {
  424. if (!strncasecmp(color_table[cnt].name, string, color_table[cnt].len))
  425. {
  426. substitute(ses, color_table[cnt].code, result, SUB_COL);
  427. result += strlen(result);
  428. break;
  429. }
  430. }
  431. if (*color_table[cnt].name == 0)
  432. {
  433. return FALSE;
  434. }
  435. }
  436. string += strlen(color_table[cnt].name);
  437. }
  438. switch (*string)
  439. {
  440. case ' ':
  441. case ';':
  442. case ',':
  443. case '{':
  444. case '}':
  445. string++;
  446. break;
  447. case 0:
  448. return TRUE;
  449. default:
  450. return FALSE;
  451. }
  452. }
  453. return TRUE;
  454. }
  455. void headerstring(struct session *ses, char *str)
  456. {
  457. char buf[BUFFER_SIZE], fill[BUFFER_SIZE];
  458. int len, max;
  459. len = string_raw_str_len(ses, str, 0, BUFFER_SIZE);
  460. max = get_scroll_cols(ses);
  461. if (len > max - 2)
  462. {
  463. str[max] = 0;
  464. return;
  465. }
  466. memset(fill, '#', max);
  467. sprintf(buf, "%.*s%s%.*s%s", (max - len) / 2, fill, str, (max - len) / 2, fill, (max - len) % 2 ? "#" : "");
  468. strcpy(str, buf);
  469. }
  470. void lowerstring(char *str)
  471. {
  472. char *pts;
  473. for (pts = str ; *pts ; pts++)
  474. {
  475. *pts = tolower((int) *pts);
  476. }
  477. }
  478. void upperstring(char *str)
  479. {
  480. char *pts;
  481. for (pts = str ; *pts ; pts++)
  482. {
  483. *pts = toupper((int) *pts);
  484. }
  485. }
  486. void hexstring(char *str)
  487. {
  488. unsigned long long result = hex_number_64bit(str);
  489. unicode_to_utf8(result, str);
  490. }
  491. void reversestring(char *str)
  492. {
  493. char t;
  494. int a = 0, z = strlen(str) - 1;
  495. while (z > a)
  496. {
  497. t = str[z];
  498. str[z--] = str[a];
  499. str[a++] = t;
  500. }
  501. z = strlen(str) - 1;
  502. for (a = 1 ; a < z ; a++)
  503. {
  504. if (str[a] == '\\' && str[a + 1] != '\\')
  505. {
  506. str[a] = str[a - 1];
  507. str[a - 1] = '\\';
  508. }
  509. }
  510. }
  511. void mathstring(struct session *ses, char *str)
  512. {
  513. get_number_string(ses, str, str);
  514. }
  515. void thousandgroupingstring(struct session *ses, char *str)
  516. {
  517. char result[BUFFER_SIZE], strold[BUFFER_SIZE];
  518. int cnt1, cnt2, cnt3, cnt4;
  519. get_number_string(ses, str, strold);
  520. cnt1 = strlen(strold);
  521. cnt2 = BUFFER_SIZE / 2;
  522. cnt4 = strchr(strold, '.') ? 1 : 0;
  523. result[cnt2+1] = 0;
  524. for (cnt3 = 0 ; cnt1 >= 0 ; cnt1--, cnt2--)
  525. {
  526. if (cnt3++ % 3 == 0 && cnt3 != 1 && cnt4 == 0 && isdigit((int) strold[cnt1]))
  527. {
  528. result[cnt2--] = ',';
  529. }
  530. result[cnt2] = strold[cnt1];
  531. if (!isdigit((int) result[cnt2]))
  532. {
  533. cnt4 = 0;
  534. cnt3 = 0;
  535. continue;
  536. }
  537. }
  538. strcpy(str, result + cnt2 + 1);
  539. }
  540. void chronosgroupingstring(struct session *ses, char *str)
  541. {
  542. char *sign = "-";
  543. long long val = (long long) get_number(ses, str);
  544. int days, hours, minutes, seconds;
  545. if (val < 0)
  546. {
  547. val *= -1;
  548. }
  549. else
  550. {
  551. sign = "";
  552. }
  553. seconds = val % 60;
  554. val /= 60;
  555. minutes = val % 60;
  556. val /= 60;
  557. hours = val % 24;
  558. val /= 24;
  559. days = val;
  560. if (days)
  561. {
  562. sprintf(str, "%s%d:%02d:%02d:%02d", sign, days, hours, minutes, seconds);
  563. }
  564. else if (hours)
  565. {
  566. sprintf(str, "%s%d:%02d:%02d", sign, hours, minutes, seconds);
  567. }
  568. else
  569. {
  570. sprintf(str, "%s%d:%02d", sign, minutes, seconds);
  571. }
  572. }
  573. void metricgroupingstring(struct session *ses, char *str)
  574. {
  575. char big[] = {' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', '?', '?', '?', '?', '?', '?', '?', '?'};
  576. char small[] = {' ', 'm', 'u', 'n', 'p', 'f', 'a', 'z', 'y', '?', '?', '?', '?', '?', '?', '?', '?'};
  577. char tmp[NUMBER_SIZE];
  578. long double val = get_number(ses, str);
  579. int index = 0;
  580. if (val >= 1000)
  581. {
  582. while (val >= 1000)
  583. {
  584. val = val / 1000;
  585. index++;
  586. }
  587. if (val >= 100)
  588. {
  589. sprintf(tmp, " %Lf", val);
  590. }
  591. else
  592. {
  593. sprintf(tmp, "%Lf", val);
  594. }
  595. sprintf(str, "%.4s%c", tmp, big[index]);
  596. }
  597. else if (val > 0 && val < 0.01)
  598. {
  599. while (val < 0.01)
  600. {
  601. val = val * 1000;
  602. index++;
  603. }
  604. sprintf(tmp, "%Lf", val);
  605. sprintf(str, "%.4s%c", tmp, small[index]);
  606. }
  607. else if (val >= 0)
  608. {
  609. if (val >= 100)
  610. {
  611. sprintf(tmp, " %Lf", val);
  612. }
  613. else
  614. {
  615. sprintf(tmp, "%Lf", val);
  616. }
  617. sprintf(str, "%.4s%c", tmp, big[index]);
  618. }
  619. else if (val <= -0.01 && val > -1000)
  620. {
  621. if (val <= -100)
  622. {
  623. sprintf(tmp, " %Lf", val);
  624. }
  625. else
  626. {
  627. sprintf(tmp, "%Lf", val);
  628. }
  629. sprintf(str, "%.5s%c", tmp, small[index]);
  630. }
  631. else if (val <= -1000)
  632. {
  633. while (val <= -100)
  634. {
  635. if (val <= -10000)
  636. {
  637. val = (long double) ((long long) val / 100LL * 100LL);
  638. }
  639. val = val / 1000;
  640. index++;
  641. }
  642. sprintf(tmp, "%Lf", val);
  643. sprintf(str, "%.5s%c", tmp, big[index]);
  644. }
  645. else if (val < 0 /*&& val > -0.01*/)
  646. {
  647. while (val > -0.01)
  648. {
  649. val = val * 1000;
  650. index++;
  651. }
  652. sprintf(tmp, "%Lf", val);
  653. sprintf(str, "%.5s%c", tmp, small[index]);
  654. }
  655. }
  656. void stripspaces(char *str)
  657. {
  658. int cnt;
  659. for (cnt = strlen(str) - 1 ; cnt >= 0 ; cnt--)
  660. {
  661. if (!isspace((int) str[cnt]))
  662. {
  663. break;
  664. }
  665. str[cnt] = 0;
  666. }
  667. for (cnt = 0 ; str[cnt] != 0 ; cnt++)
  668. {
  669. if (!isspace((int) str[cnt]))
  670. {
  671. break;
  672. }
  673. }
  674. memmove(str, &str[cnt], strlen(&str[cnt]) + 1);
  675. // strcpy(str, &str[cnt]);
  676. }
  677. void wrapstring(struct session *ses, char *str, char *wrap)
  678. {
  679. char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
  680. char *pts, *pte, *arg;
  681. int cnt, width, height;
  682. push_call("wrapstring(%p,%p,%p)",ses,str,wrap);
  683. arg = sub_arg_in_braces(ses, str, arg1, GET_ALL, SUB_COL);
  684. if (*arg == COMMAND_SEPARATOR)
  685. {
  686. arg++;
  687. }
  688. arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
  689. if (*arg2)
  690. {
  691. cnt = get_number(ses, arg2);
  692. }
  693. else if (*wrap)
  694. {
  695. cnt = atoi(wrap);
  696. }
  697. else
  698. {
  699. cnt = get_scroll_cols(ses);
  700. }
  701. if (cnt <= 0)
  702. {
  703. cnt = get_scroll_cols(ses) + cnt;
  704. if (cnt <= 0)
  705. {
  706. show_error(ses, LIST_VARIABLE, "#FORMAT %w: INVALID LENTGH {%s}", arg2);
  707. pop_call();
  708. return;
  709. }
  710. }
  711. word_wrap_split(ses, arg1, arg2, cnt, 0, 0, 0, &height, &width);
  712. pts = pte = arg2;
  713. str[0] = cnt = 0;
  714. while (*pte != 0)
  715. {
  716. if (*pte == '\n')
  717. {
  718. *pte++ = 0;
  719. cat_sprintf(str, "{%d}{%s}", ++cnt, pts);
  720. pts = pte;
  721. }
  722. else
  723. {
  724. pte++;
  725. }
  726. }
  727. cat_sprintf(str, "{%d}{%s}", ++cnt, pts);
  728. pop_call();
  729. return;
  730. }
  731. int stringlength(struct session *ses, char *str)
  732. {
  733. char temp[BUFFER_SIZE];
  734. substitute(ses, str, temp, SUB_COL|SUB_ESC);
  735. return strip_vt102_strlen(ses, temp);
  736. }
  737. // stripped range raw return
  738. int string_str_raw_len(struct session *ses, char *str, int start, int end)
  739. {
  740. int raw_cnt, str_cnt, ret_cnt, tmp_cnt, tot_len, width, col_len;
  741. raw_cnt = str_cnt = ret_cnt = 0;
  742. tot_len = strlen(str);
  743. while (raw_cnt < tot_len)
  744. {
  745. if (skip_vt102_codes(&str[raw_cnt]))
  746. {
  747. ret_cnt += (str_cnt >= start) ? skip_vt102_codes(&str[raw_cnt]) : 0;
  748. raw_cnt += skip_vt102_codes(&str[raw_cnt]);
  749. continue;
  750. }
  751. col_len = is_color_code(&str[raw_cnt]);
  752. if (col_len)
  753. {
  754. ret_cnt += (str_cnt >= start) ? col_len : 0;
  755. raw_cnt += col_len;
  756. continue;
  757. }
  758. if (str_cnt >= end)
  759. {
  760. break;
  761. }
  762. if (str[raw_cnt] == '\\')
  763. {
  764. ret_cnt += (str_cnt >= start) ? 1 : 0;
  765. raw_cnt++;
  766. if (str[raw_cnt] == '\\')
  767. {
  768. ret_cnt += (str_cnt >= start) ? 1 : 0;
  769. raw_cnt++;
  770. str_cnt++;
  771. }
  772. continue;
  773. }
  774. if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
  775. {
  776. tmp_cnt = get_utf8_width(&str[raw_cnt], &width);
  777. if (str_cnt >= start)
  778. {
  779. ret_cnt += tmp_cnt;
  780. }
  781. raw_cnt += tmp_cnt;
  782. str_cnt += width;
  783. }
  784. else
  785. {
  786. ret_cnt += (str_cnt >= start) ? 1 : 0;
  787. raw_cnt++;
  788. str_cnt++;
  789. }
  790. }
  791. return ret_cnt;
  792. }
  793. // raw range stripped return
  794. int string_raw_str_len(struct session *ses, char *str, int raw_start, int raw_end)
  795. {
  796. int raw_cnt, ret_cnt, tot_len, width, col_len;
  797. raw_cnt = raw_start;
  798. ret_cnt = 0;
  799. tot_len = strlen(str);
  800. while (raw_cnt < tot_len)
  801. {
  802. if (raw_cnt >= raw_end)
  803. {
  804. break;
  805. }
  806. if (skip_vt102_codes(&str[raw_cnt]))
  807. {
  808. raw_cnt += skip_vt102_codes(&str[raw_cnt]);
  809. continue;
  810. }
  811. col_len = is_color_code(&str[raw_cnt]);
  812. if (col_len)
  813. {
  814. raw_cnt += col_len;
  815. continue;
  816. }
  817. if (str[raw_cnt] == '\\')
  818. {
  819. raw_cnt++;
  820. if (str[raw_cnt] == '\\')
  821. {
  822. raw_cnt++;
  823. ret_cnt++;
  824. }
  825. continue;
  826. }
  827. if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, &str[raw_cnt]))
  828. {
  829. raw_cnt += get_euc_width(ses, &str[raw_cnt], &width);
  830. ret_cnt += width;
  831. }
  832. else if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
  833. {
  834. raw_cnt += get_utf8_width(&str[raw_cnt], &width);
  835. ret_cnt += width;
  836. }
  837. else
  838. {
  839. raw_cnt++;
  840. ret_cnt++;
  841. }
  842. }
  843. return ret_cnt;
  844. }
  845. void timestring(struct session *ses, char *str)
  846. {
  847. char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], *arg;
  848. struct tm timeval_tm;
  849. time_t timeval_t;
  850. arg = get_arg_in_braces(ses, str, arg1, GET_ALL);
  851. if (*arg == COMMAND_SEPARATOR)
  852. {
  853. arg++;
  854. }
  855. arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
  856. if (*arg2)
  857. {
  858. timeval_t = (time_t) get_number(ses, arg2);
  859. }
  860. else
  861. {
  862. timeval_t = gtd->time;
  863. }
  864. timeval_tm = *localtime(&timeval_t);
  865. strftime(str, BUFFER_SIZE, arg1, &timeval_tm);
  866. }
  867. void justify_string(struct session *ses, char *in, char *out, int align, int cut)
  868. {
  869. char temp[BUFFER_SIZE];
  870. if (align < 0)
  871. {
  872. sprintf(temp, "%%%d.%ds", align - ((int) strlen(in) - string_raw_str_len(ses, in, 0, BUFFER_SIZE)), string_str_raw_len(ses, in, 0, cut));
  873. }
  874. else
  875. {
  876. sprintf(temp, "%%%d.%ds", align + ((int) strlen(in) - string_raw_str_len(ses, in, 0, BUFFER_SIZE)), string_str_raw_len(ses, in, 0, cut));
  877. }
  878. sprintf(out, temp, in);
  879. }
  880. void format_string(struct session *ses, char *format, char *arg, char *out)
  881. {
  882. char argformat[BUFFER_SIZE], newformat[BUFFER_SIZE], arglist[30][20000], *ptf, *ptt, *pts, *ptn;
  883. struct tm timeval_tm;
  884. time_t timeval_t;
  885. int i;
  886. for (i = 0 ; i < 30 ; i++)
  887. {
  888. arg = sub_arg_in_braces(ses, arg, arglist[i], GET_ONE, SUB_VAR|SUB_FUN);
  889. }
  890. i = 0;
  891. ptf = format;
  892. ptn = newformat;
  893. while (*ptf)
  894. {
  895. if (i == 30)
  896. {
  897. break;
  898. }
  899. if (*ptf == '%')
  900. {
  901. pts = ptn;
  902. *ptn++ = *ptf++;
  903. if (*ptf == 0)
  904. {
  905. *ptn++ = '%';
  906. break;
  907. }
  908. else if (*ptf == '%')
  909. {
  910. *ptn++ = *ptf++;
  911. }
  912. else if (*ptf == ' ')
  913. {
  914. *ptn++ = '%';
  915. }
  916. else
  917. {
  918. while (!isalpha((int) *ptf))
  919. {
  920. if (*ptf == 0)
  921. {
  922. break;
  923. }
  924. *ptn++ = *ptf++;
  925. }
  926. *ptn = 0;
  927. if (*ptf == 0)
  928. {
  929. show_error(ses, LIST_VARIABLE, "#FORMAT STRING: UNKNOWN ARGUMENT {%s}.", pts);
  930. continue;
  931. }
  932. if (*ptf == 'd' || *ptf == 'f' || *ptf == 'X')
  933. {
  934. strcpy(argformat, pts);
  935. ptn = pts + 1;
  936. *ptn = 0;
  937. }
  938. else if (*ptf == 'w')
  939. {
  940. strcpy(argformat, pts+1);
  941. ptn = pts + 1;
  942. *ptn = 0;
  943. }
  944. else if (pts[1])
  945. {
  946. char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
  947. ptt = arg1;
  948. ptn = pts + 1;
  949. while (*ptn && *ptn != '.')
  950. {
  951. *ptt++ = *ptn++;
  952. }
  953. *ptt = 0;
  954. if (*ptn == 0)
  955. {
  956. if (atoi(arg1) < 0)
  957. {
  958. sprintf(argformat, "%%%d", atoi(arg1) - ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)));
  959. }
  960. else
  961. {
  962. sprintf(argformat, "%%%d", atoi(arg1) + ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)));
  963. }
  964. }
  965. else
  966. {
  967. ptt = arg2;
  968. ptn = ptn + 1;
  969. while (*ptn)
  970. {
  971. *ptt++ = *ptn++;
  972. }
  973. *ptt = 0;
  974. if (atoi(arg1) < 0)
  975. {
  976. sprintf(argformat, "%%%d.%d",
  977. atoi(arg1) - ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)),
  978. string_str_raw_len(ses, arglist[i], 0, atoi(arg2)));
  979. }
  980. else
  981. {
  982. sprintf(argformat, "%%%d.%d",
  983. atoi(arg1) + ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)),
  984. string_str_raw_len(ses, arglist[i], 0, atoi(arg2)));
  985. }
  986. }
  987. ptt = argformat;
  988. ptn = pts;
  989. while (*ptt)
  990. {
  991. *ptn++ = *ptt++;
  992. }
  993. *ptn = 0;
  994. }
  995. switch (*ptf)
  996. {
  997. case 'a':
  998. numbertocharacter(ses, arglist[i]);
  999. // sprintf(arglist[i], "%c", (char) get_number(ses, arglist[i]));
  1000. break;
  1001. case 'c':
  1002. colorstring(ses, arglist[i]);
  1003. break;
  1004. case 'd':
  1005. strcat(argformat, "lld");
  1006. sprintf(arglist[i], argformat, (long long) get_number(ses, arglist[i]));
  1007. break;
  1008. case 'f':
  1009. strcat(argformat, "Lf");
  1010. sprintf(arglist[i], argformat, get_double(ses, arglist[i]));
  1011. break;
  1012. case 'g':
  1013. thousandgroupingstring(ses, arglist[i]);
  1014. break;
  1015. case 'h':
  1016. headerstring(ses, arglist[i]);
  1017. break;
  1018. case 'l':
  1019. lowerstring(arglist[i]);
  1020. break;
  1021. case 'm':
  1022. mathstring(ses, arglist[i]);
  1023. break;
  1024. case 'n':
  1025. arglist[i][0] = toupper((int) arglist[i][0]);
  1026. break;
  1027. case 'p':
  1028. stripspaces(arglist[i]);
  1029. break;
  1030. case 'r':
  1031. reversestring(arglist[i]);
  1032. break;
  1033. case 's':
  1034. break;
  1035. case 't':
  1036. timestring(ses, arglist[i]);
  1037. break;
  1038. case 'u':
  1039. upperstring(arglist[i]);
  1040. break;
  1041. case 'w':
  1042. substitute(ses, arglist[i], arglist[i], SUB_VAR|SUB_FUN);
  1043. wrapstring(ses, arglist[i], argformat);
  1044. break;
  1045. case 'x':
  1046. hexstring(arglist[i]);
  1047. break;
  1048. case 'A':
  1049. charactertonumber(ses, arglist[i]);
  1050. break;
  1051. case 'C':
  1052. chronosgroupingstring(ses, arglist[i]);
  1053. break;
  1054. case 'D':
  1055. sprintf(arglist[i], "%llu", hex_number_64bit(arglist[i]));
  1056. break;
  1057. /* case 'D':
  1058. timeval_t = (time_t) *arglist[i] ? atoll(arglist[i]) : gtd->time;
  1059. timeval_tm = *localtime(&timeval_t);
  1060. strftime(arglist[i], BUFFER_SIZE, "%d", &timeval_tm);
  1061. break;
  1062. */
  1063. case 'G':
  1064. thousandgroupingstring(ses, arglist[i]);
  1065. break;
  1066. case 'H':
  1067. sprintf(arglist[i], "%llu", generate_hash_key(arglist[i]));
  1068. break;
  1069. case 'L':
  1070. sprintf(arglist[i], "%d", stringlength(ses, arglist[i]));
  1071. break;
  1072. case 'M':
  1073. metricgroupingstring(ses, arglist[i]);
  1074. break;
  1075. case 'R':
  1076. tintin_printf2(ses, "\e[1;31m#echo/#format %%R please use #screen {get} {rows} to get screen height.");
  1077. sprintf(arglist[i], "%d", gtd->screen->rows);
  1078. break;
  1079. case 'S':
  1080. sprintf(arglist[i], "%d", spellcheck_count(ses, arglist[i]));
  1081. break;
  1082. case 'T':
  1083. sprintf(arglist[i], "%ld", gtd->time);
  1084. break;
  1085. case 'U':
  1086. sprintf(arglist[i], "%lld", utime());
  1087. break;
  1088. case 'X':
  1089. strcat(argformat, "llX");
  1090. charactertohex(ses, arglist[i]);
  1091. sprintf(arglist[i], argformat, (unsigned long long) get_number(ses, arglist[i]));
  1092. break;
  1093. // undocumented
  1094. case 'Y': // print the year, experimental
  1095. timeval_t = (time_t) *arglist[i] ? atoll(arglist[i]) : gtd->time;
  1096. timeval_tm = *localtime(&timeval_t);
  1097. strftime(arglist[i], BUFFER_SIZE, "%Y", &timeval_tm);
  1098. break;
  1099. default:
  1100. show_error(ses, LIST_VARIABLE, "#FORMAT STRING: UNKNOWN ARGUMENT {%s%c}.", pts, *ptf);
  1101. break;
  1102. }
  1103. *ptn++ = 's';
  1104. i++;
  1105. ptf++;
  1106. }
  1107. }
  1108. else
  1109. {
  1110. *ptn++ = *ptf++;
  1111. }
  1112. }
  1113. *ptn = 0;
  1114. 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]);
  1115. return;
  1116. }
  1117. DO_COMMAND(do_format)
  1118. {
  1119. char destvar[BUFFER_SIZE], format[BUFFER_SIZE], result[BUFFER_SIZE];
  1120. arg = sub_arg_in_braces(ses, arg, destvar, GET_NST, SUB_VAR|SUB_FUN);
  1121. arg = sub_arg_in_braces(ses, arg, format, GET_ONE, SUB_VAR|SUB_FUN);
  1122. if (*destvar == 0)
  1123. {
  1124. show_error(ses, LIST_VARIABLE, "#SYNTAX: #format {variable} {format} {arg1} {arg2}");
  1125. return ses;
  1126. }
  1127. format_string(ses, format, arg, result);
  1128. set_nest_node_ses(ses, destvar, "%s", result);
  1129. show_message(ses, LIST_VARIABLE, "#OK. VARIABLE {%s} HAS BEEN SET TO {%s}.", destvar, result);
  1130. return ses;
  1131. }