Freeciv-3.3: /fast/freeciv/nightly/main/common/featured_text.c Source File

Freeciv-3.3

Loading...
Searching...
No Matches
featured_text.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13#ifdef HAVE_CONFIG_H
14#include <fc_config.h>
15#endif
16
17#include <stdarg.h>
18#include <string.h>
19
20/* utility */
21#include "fcintl.h"
22#include "log.h"
23#include "mem.h"
24#include "shared.h"
25#include "support.h"
26
27/* common */
28#include "city.h"
29#include "combat.h"
30#include "game.h"
31#include "map.h"
32#include "tile.h"
33#include "unit.h"
34
35#include "featured_text.h"
36
37#define SEQ_START '['
38#define SEQ_STOP ']'
39#define SEQ_END '/'
40
41#define MAX_LEN_STR 32
42#define log_featured_text log_verbose
43
44#define text_tag_list_rev_iterate(tags, ptag) \
45 TYPED_LIST_ITERATE_REV(struct text_tag, tags, ptag)
46#define text_tag_list_rev_iterate_end LIST_ITERATE_REV_END
47
48/* The text_tag structure. See documentation in featured_text.h. */
49 struct text_tag {
50 enum text_tag_type type; /* The type of the tag. */
51 ft_offset_t start_offset; /* The start offset (in bytes). */
52 ft_offset_t stop_offset; /* The stop offset (in bytes). */
53 union {
54 struct { /* TTT_COLOR only. */
55 char foreground[MAX_LEN_STR]; /* foreground color name. */
56 char background[MAX_LEN_STR]; /* background color name. */
57 } color;
58 struct { /* TTT_LINK only. */
59 enum text_link_type type; /* The target type of the link. */
60 int id; /* The id of linked object. */
61 char name[MAX_LEN_STR]; /* A string to indentify the link. */
62 } link;
63 };
64};
65
66 enum sequence_type {
67 ST_START, /* e.g. [sequence]. */
68 ST_STOP, /* e.g. [/sequence]. */
69 ST_SINGLE /* e.g. [sequence/]. */
70};
71
72/* Predefined colors. */
73 const struct ft_color ftc_any = FT_COLOR(nullptr, nullptr);
74
75 const struct ft_color ftc_warning = FT_COLOR("#FF0000", nullptr);
76 const struct ft_color ftc_log = FT_COLOR("#7F7F7F", nullptr);
77 const struct ft_color ftc_server = FT_COLOR("#8B0000", nullptr);
78 const struct ft_color ftc_client = FT_COLOR("#EF7F00", nullptr);
79 const struct ft_color ftc_editor = FT_COLOR("#0000FF", nullptr);
80 const struct ft_color ftc_command = FT_COLOR("#006400", nullptr);
81 struct ft_color ftc_changed = FT_COLOR("#FF0000", nullptr);
82 const struct ft_color ftc_server_prompt = FT_COLOR("#FF0000", "#BEBEBE");
83 const struct ft_color ftc_player_lost = FT_COLOR("#FFFFFF", "#000000");
84 const struct ft_color ftc_game_start = FT_COLOR("#00FF00", "#115511");
85
86 const struct ft_color ftc_chat_public = FT_COLOR("#00008B", nullptr);
87 const struct ft_color ftc_chat_ally = FT_COLOR("#551166", nullptr);
88 const struct ft_color ftc_chat_private = FT_COLOR("#A020F0", nullptr);
89 const struct ft_color ftc_chat_luaconsole = FT_COLOR("#006400", nullptr);
90
91 const struct ft_color ftc_vote_public = FT_COLOR("#FFFFFF", "#AA0000");
92 const struct ft_color ftc_vote_team = FT_COLOR("#FFFFFF", "#5555CC");
93 const struct ft_color ftc_vote_passed = FT_COLOR("#006400", "#AAFFAA");
94 const struct ft_color ftc_vote_failed = FT_COLOR("#8B0000", "#FFAAAA");
95 const struct ft_color ftc_vote_yes = FT_COLOR("#000000", "#C8FFD5");
96 const struct ft_color ftc_vote_no = FT_COLOR("#000000", "#FFD2D2");
97 const struct ft_color ftc_vote_abstain = FT_COLOR("#000000", "#E8E8E8");
98
99 const struct ft_color ftc_luaconsole_input = FT_COLOR("#2B008B", nullptr);
100 const struct ft_color ftc_luaconsole_error = FT_COLOR("#FF0000", nullptr);
101 const struct ft_color ftc_luaconsole_warn = FT_COLOR("#CF2020", nullptr);
102 const struct ft_color ftc_luaconsole_normal = FT_COLOR("#006400", nullptr);
103 const struct ft_color ftc_luaconsole_verbose = FT_COLOR("#B8B8B8", nullptr);
104 const struct ft_color ftc_luaconsole_debug = FT_COLOR("#B87676", nullptr);
105
106/**********************************************************************/
110 static const char *text_tag_type_name(enum text_tag_type type)
111{
112 switch (type) {
113 case TTT_BOLD:
114 return "bold";
115 case TTT_ITALIC:
116 return "italic";
117 case TTT_STRIKE:
118 return "strike";
119 case TTT_UNDERLINE:
120 return "underline";
121 case TTT_COLOR:
122 return "color";
123 case TTT_LINK:
124 return "link";
125 };
126
127 /* Don't handle the default case to be warned if a new value was added. */
128 return nullptr;
129}
130
131/**********************************************************************/
135 static const char *text_tag_type_short_name(enum text_tag_type type)
136{
137 switch (type) {
138 case TTT_BOLD:
139 return "b";
140 case TTT_ITALIC:
141 return "i";
142 case TTT_STRIKE:
143 return "s";
144 case TTT_UNDERLINE:
145 return "u";
146 case TTT_COLOR:
147 return "c";
148 case TTT_LINK:
149 return "l";
150 };
151
152 /* Don't handle the default case to be warned if a new value was added. */
153 return nullptr;
154}
155
156/**********************************************************************/
159 static const char *text_link_type_name(enum text_link_type type)
160{
161 switch (type) {
162 case TLT_CITY:
163 return "city";
164 case TLT_TILE:
165 return "tile";
166 case TLT_UNIT:
167 return "unit";
168 };
169
170 /* Don't handle the default case to be warned if a new value was added. */
171 return nullptr;
172}
173
174/**********************************************************************/
178 static bool find_option(const char *buf_in, const char *option,
179 char *buf_out, size_t write_len)
180{
181 size_t option_len = strlen(option);
182
183 while (*buf_in != '\0') {
184 while (fc_isspace(*buf_in) && *buf_in != '\0') {
185 buf_in++;
186 }
187
188 if (0 == strncasecmp(buf_in, option, option_len)) {
189 /* This is this one. */
190 buf_in += option_len;
191
192 while ((fc_isspace(*buf_in) || *buf_in == '=') && *buf_in != '\0') {
193 buf_in++;
194 }
195 if (*buf_in == '"') {
196 /* Quote case. */
197 const char *end = strchr(++buf_in, '"');
198
199 if (!end) {
200 return FALSE;
201 }
202 if (end - buf_in + 1 > 0) {
203 fc_strlcpy(buf_out, buf_in, MIN(end - buf_in + 1, write_len));
204 } else {
205 *buf_out = '\0';
206 }
207 return TRUE;
208 } else {
209 while (fc_isalnum(*buf_in) && write_len > 1) {
210 *buf_out++ = *buf_in++;
211 write_len--;
212 }
213 *buf_out = '\0';
214 return TRUE;
215 }
216 }
217 buf_in++;
218 }
219
220 return FALSE;
221}
222
223/**********************************************************************/
227 static bool text_tag_init_from_sequence(struct text_tag *ptag,
228 enum text_tag_type type,
229 ft_offset_t start_offset,
230 const char *sequence)
231{
232 ptag->type = type;
233 ptag->start_offset = start_offset;
234 ptag->stop_offset = FT_OFFSET_UNSET;
235
236 switch (type) {
237 case TTT_BOLD:
238 case TTT_ITALIC:
239 case TTT_STRIKE:
240 case TTT_UNDERLINE:
241 return TRUE;
242 case TTT_COLOR:
243 {
244 if (!find_option(sequence, "foreground", ptag->color.foreground,
245 sizeof(ptag->color.foreground))
246 && !find_option(sequence, "fg", ptag->color.foreground,
247 sizeof(ptag->color.foreground))) {
248 ptag->color.foreground[0] = '\0';
249 }
250 if (!find_option(sequence, "background", ptag->color.background,
251 sizeof(ptag->color.background))
252 && !find_option(sequence, "bg", ptag->color.background,
253 sizeof(ptag->color.background))) {
254 ptag->color.background[0] = '\0';
255 }
256 }
257 return TRUE;
258 case TTT_LINK:
259 {
260 char buf[64];
261 const char *name;
262 int i;
263
264 if (!find_option(sequence, "target", buf, sizeof(buf))
265 && !find_option(sequence, "tgt", buf, sizeof(buf))) {
266 log_featured_text("text_tag_init_from_sequence(): "
267 "target link type not set.");
268 return FALSE;
269 }
270
271 ptag->link.type = -1;
272 for (i = 0; (name = text_link_type_name(i)); i++) {
273 if (0 == fc_strncasecmp(buf, name, strlen(name))) {
274 ptag->link.type = i;
275 break;
276 }
277 }
278 if (ptag->link.type == -1) {
279 log_featured_text("text_tag_init_from_sequence(): "
280 "target link type not supported (\"%s\").", buf);
281 return FALSE;
282 }
283
284 switch (ptag->link.type) {
285 case TLT_CITY:
286 {
287 if (!find_option(sequence, "id", buf, sizeof(buf))) {
288 log_featured_text("text_tag_init_from_sequence(): "
289 "city link without id.");
290 return FALSE;
291 }
292 if (!str_to_int(buf, &ptag->link.id)) {
293 log_featured_text("text_tag_init_from_sequence(): "
294 "city link without valid id (\"%s\").", buf);
295 return FALSE;
296 }
297
298 if (!find_option(sequence, "name", ptag->link.name,
299 sizeof(ptag->link.name))) {
300 /* Set something as name. */
301 fc_snprintf(ptag->link.name, sizeof(ptag->link.name),
302 "CITY_ID%d", ptag->link.id);
303 }
304 }
305 return TRUE;
306 case TLT_TILE:
307 {
308 struct tile *ptile;
309 int x, y;
310
311 if (!find_option(sequence, "x", buf, sizeof(buf))) {
312 log_featured_text("text_tag_init_from_sequence(): "
313 "tile link without x coordinate.");
314 return FALSE;
315 }
316 if (!str_to_int(buf, &x)) {
317 log_featured_text("text_tag_init_from_sequence(): "
318 "tile link without valid x coordinate "
319 "(\"%s\").", buf);
320 return FALSE;
321 }
322
323 if (!find_option(sequence, "y", buf, sizeof(buf))) {
324 log_featured_text("text_tag_init_from_sequence(): "
325 "tile link without y coordinate.");
326 return FALSE;
327 }
328 if (!str_to_int(buf, &y)) {
329 log_featured_text("text_tag_init_from_sequence(): "
330 "tile link without valid y coordinate "
331 "(\"%s\").", buf);
332 return FALSE;
333 }
334
335 ptile = map_pos_to_tile(&(wld.map), x, y);
336 if (!ptile) {
337 log_featured_text("text_tag_init_from_sequence(): "
338 "(%d, %d) are not valid coordinates "
339 "in this game.", x, y);
340 return FALSE;
341 }
342 ptag->link.id = tile_index(ptile);
343 fc_snprintf(ptag->link.name, sizeof(ptag->link.name),
344 "(%d, %d)", TILE_XY(ptile));
345 }
346 return TRUE;
347 case TLT_UNIT:
348 {
349 if (!find_option(sequence, "id", buf, sizeof(buf))) {
350 log_featured_text("text_tag_init_from_sequence(): "
351 "unit link without id.");
352 return FALSE;
353 }
354 if (!str_to_int(buf, &ptag->link.id)) {
355 log_featured_text("text_tag_init_from_sequence(): "
356 "unit link without valid id (\"%s\").", buf);
357 return FALSE;
358 }
359
360 if (!find_option(sequence, "name", ptag->link.name,
361 sizeof(ptag->link.name))) {
362 /* Set something as name. */
363 fc_snprintf(ptag->link.name, sizeof(ptag->link.name),
364 "UNIT_ID%d", ptag->link.id);
365 }
366 }
367 return TRUE;
368 };
369 }
370 };
371 return FALSE;
372}
373
374/**********************************************************************/
391 static bool text_tag_initv(struct text_tag *ptag, enum text_tag_type type,
392 ft_offset_t start_offset, ft_offset_t stop_offset,
393 va_list args)
394{
395 ptag->type = type;
396 ptag->start_offset = start_offset;
397 ptag->stop_offset = stop_offset;
398
399 switch (type) {
400 case TTT_BOLD:
401 case TTT_ITALIC:
402 case TTT_STRIKE:
403 case TTT_UNDERLINE:
404 return TRUE;
405 case TTT_COLOR:
406 {
407 const struct ft_color color = va_arg(args, struct ft_color);
408
409 if ((color.foreground == nullptr || color.foreground[0] == '\0')
410 && (color.background == nullptr || color.background[0] == '\0')) {
411 return FALSE; /* No color at all. */
412 }
413
414 if (color.foreground != nullptr && color.foreground[0] != '\0') {
415 sz_strlcpy(ptag->color.foreground, color.foreground);
416 } else {
417 ptag->color.foreground[0] = '\0';
418 }
419
420 if (color.background != nullptr && color.background[0] != '\0') {
421 sz_strlcpy(ptag->color.background, color.background);
422 } else {
423 ptag->color.background[0] = '\0';
424 }
425 }
426 return TRUE;
427 case TTT_LINK:
428 {
429 ptag->link.type = va_arg(args, enum text_link_type);
430 switch (ptag->link.type) {
431 case TLT_CITY:
432 {
433 struct city *pcity = va_arg(args, struct city *);
434
435 if (!pcity) {
436 return FALSE;
437 }
438 ptag->link.id = pcity->id;
439 sz_strlcpy(ptag->link.name, city_name_get(pcity));
440 }
441 return TRUE;
442 case TLT_TILE:
443 {
444 struct tile *ptile = va_arg(args, struct tile *);
445
446 if (!ptile) {
447 return FALSE;
448 }
449 ptag->link.id = tile_index(ptile);
450 fc_snprintf(ptag->link.name, sizeof(ptag->link.name),
451 "(%d, %d)", TILE_XY(ptile));
452 }
453 return TRUE;
454 case TLT_UNIT:
455 {
456 struct unit *punit = va_arg(args, struct unit *);
457
458 if (!punit) {
459 return FALSE;
460 }
461 ptag->link.id = punit->id;
462 sz_strlcpy(ptag->link.name, unit_name_translation(punit));
463 }
464 return TRUE;
465 };
466 }
467 };
468 return FALSE;
469}
470
471/**********************************************************************/
474 static size_t text_tag_start_sequence(const struct text_tag *ptag,
475 char *buf, size_t len)
476{
477 switch (ptag->type) {
478 case TTT_BOLD:
479 case TTT_ITALIC:
480 case TTT_STRIKE:
481 case TTT_UNDERLINE:
482 return fc_snprintf(buf, len, "%c%s%c", SEQ_START,
483 text_tag_type_short_name(ptag->type), SEQ_STOP);
484 case TTT_COLOR:
485 {
486 size_t ret = fc_snprintf(buf, len, "%c%s", SEQ_START,
487 text_tag_type_short_name(ptag->type));
488
489 if (ptag->color.foreground[0] != '\0') {
490 ret += fc_snprintf(buf + ret, len - ret, " fg=\"%s\"",
491 ptag->color.foreground);
492 }
493 if (ptag->color.background[0] != '\0') {
494 ret += fc_snprintf(buf + ret, len - ret, " bg=\"%s\"",
495 ptag->color.background);
496 }
497 return ret + fc_snprintf(buf + ret, len - ret, "%c", SEQ_STOP);
498 }
499 case TTT_LINK:
500 {
501 size_t ret = fc_snprintf(buf, len, "%c%s tgt=\"%s\"", SEQ_START,
502 text_tag_type_short_name(ptag->type),
503 text_link_type_name(ptag->link.type));
504
505 switch (ptag->link.type) {
506 case TLT_CITY:
507 {
508 struct city *pcity = game_city_by_number(ptag->link.id);
509
510 if (pcity) {
511 ret += fc_snprintf(buf + ret, len - ret,
512 " id=%d name=\"%s\"",
513 pcity->id, city_name_get(pcity));
514 } else {
515 ret += fc_snprintf(buf + ret, len - ret,
516 " id=%d", ptag->link.id);
517 }
518 }
519 break;
520 case TLT_TILE:
521 {
522 struct tile *ptile = index_to_tile(&(wld.map), ptag->link.id);
523
524 if (ptile) {
525 ret += fc_snprintf(buf + ret, len - ret,
526 " x=%d y=%d", TILE_XY(ptile));
527 } else {
528 ret += fc_snprintf(buf + ret, len - ret,
529 " id=%d", ptag->link.id);
530 }
531 }
532 break;
533 case TLT_UNIT:
534 {
535 struct unit *punit = game_unit_by_number(ptag->link.id);
536
537 if (punit) {
538 ret += fc_snprintf(buf + ret, len - ret,
539 " id=%d name=\"%s\"",
540 punit->id, unit_name_translation(punit));
541 } else {
542 ret += fc_snprintf(buf + ret, len - ret,
543 " id=%d", ptag->link.id);
544 }
545 }
546 break;
547 };
548
549 if (ptag->stop_offset == ptag->start_offset) {
550 /* This is a single sequence like [link ... /]. */
551 ret += fc_snprintf(buf + ret, len - ret, "%c", SEQ_END);
552 }
553
554 return ret + fc_snprintf(buf + ret, len - ret, "%c", SEQ_STOP);
555 }
556 };
557 return 0;
558}
559
560/**********************************************************************/
563 static size_t text_tag_stop_sequence(const struct text_tag *ptag,
564 char *buf, size_t len)
565{
566 if (ptag->type == TTT_LINK && ptag->stop_offset == ptag->start_offset) {
567 /* Should be already finished. */
568 return 0;
569 }
570
571 return fc_snprintf(buf, len, "%c%c%s%c", SEQ_START, SEQ_END,
572 text_tag_type_short_name(ptag->type), SEQ_STOP);
573}
574
575/**********************************************************************/
578 static size_t text_tag_replace_text(const struct text_tag *ptag,
579 char *buf, size_t len,
580 bool replace_link_text)
581{
582 if (ptag->type != TTT_LINK) {
583 return 0;
584 }
585
586 if (replace_link_text) {
587 /* The client might check if this should be updated or translated. */
588 switch (ptag->link.type) {
589 case TLT_CITY:
590 {
591 struct city *pcity = game_city_by_number(ptag->link.id);
592
593 /* Note that if city_tile(pcity) is nullptr, then it is probably an
594 * invisible city (see client/packhand.c). Then, we don't
595 * use the current city name which is usually not complete,
596 * a dumb string using the city id. */
597 if (pcity != nullptr && city_tile(pcity) != nullptr) {
598 return fc_snprintf(buf, len, "%s", city_name_get(pcity));
599 }
600 }
601 break;
602 case TLT_TILE:
603 break;
604 case TLT_UNIT:
605 {
606 struct unit *punit = game_unit_by_number(ptag->link.id);
607
608 if (punit) {
609 return fc_snprintf(buf, len, "%s", unit_name_translation(punit));
610 }
611 }
612 break;
613 };
614 }
615
616 if (ptag->link.type == TLT_UNIT) {
617 /* Attempt to translate the link name (it should be a unit type name). */
618 return fc_snprintf(buf, len, "%s", _(ptag->link.name));
619 } else {
620 return fc_snprintf(buf, len, "%s", ptag->link.name);
621 }
622}
623
624/**********************************************************************/
641 struct text_tag *text_tag_new(enum text_tag_type tag_type,
642 ft_offset_t start_offset,
643 ft_offset_t stop_offset,
644 ...)
645{
646 struct text_tag *ptag = fc_malloc(sizeof(struct text_tag));
647 va_list args;
648 bool ok;
649
650 va_start(args, stop_offset);
651 ok = text_tag_initv(ptag, tag_type, start_offset, stop_offset, args);
652 va_end(args);
653
654 if (ok) {
655 return ptag;
656 } else {
657 free(ptag);
658
659 return nullptr;
660 }
661}
662
663/**********************************************************************/
667 struct text_tag *text_tag_copy(const struct text_tag *ptag)
668{
669 struct text_tag *pnew_tag;
670
671 if (ptag == nullptr) {
672 return nullptr;
673 }
674
675 pnew_tag = fc_malloc(sizeof(struct text_tag));
676 *pnew_tag = *ptag;
677
678 return pnew_tag;
679}
680
681/**********************************************************************/
684 void text_tag_destroy(struct text_tag *ptag)
685{
686 free(ptag);
687}
688
689/**********************************************************************/
692 enum text_tag_type text_tag_type(const struct text_tag *ptag)
693{
694 return ptag->type;
695}
696
697/**********************************************************************/
700 ft_offset_t text_tag_start_offset(const struct text_tag *ptag)
701{
702 return ptag->start_offset;
703}
704
705/**********************************************************************/
708 ft_offset_t text_tag_stop_offset(const struct text_tag *ptag)
709{
710 return ptag->stop_offset;
711}
712
713/**********************************************************************/
717 const char *text_tag_color_foreground(const struct text_tag *ptag)
718{
719 if (ptag->type != TTT_COLOR) {
720 log_error("text_tag_color_foreground(): incompatible tag type.");
721 return nullptr;
722 }
723
724 return ptag->color.foreground;
725}
726
727/**********************************************************************/
731 const char *text_tag_color_background(const struct text_tag *ptag)
732{
733 if (ptag->type != TTT_COLOR) {
734 log_error("text_tag_color_background(): incompatible tag type.");
735 return nullptr;
736 }
737
738 return ptag->color.background;
739}
740
741/**********************************************************************/
745 enum text_link_type text_tag_link_type(const struct text_tag *ptag)
746{
747 if (ptag->type != TTT_LINK) {
748 log_error("text_tag_link_type(): incompatible tag type.");
749 return -1;
750 }
751
752 return ptag->link.type;
753}
754
755/**********************************************************************/
760 int text_tag_link_id(const struct text_tag *ptag)
761{
762 if (ptag->type != TTT_LINK) {
763 log_error("text_tag_link_id(): incompatible tag type.");
764 return -1;
765 }
766
767 return ptag->link.id;
768}
769
770/**********************************************************************/
774 static size_t extract_sequence_text(const char *featured_text,
775 char *buf, size_t len,
776 enum sequence_type *seq_type,
777 enum text_tag_type *type)
778{
779 const char *buf_in = featured_text;
780 const char *stop = strchr(buf_in, SEQ_STOP);
781 const char *end = stop;
782 const char *name;
783 size_t type_len;
784 size_t name_len;
785 int i;
786
787 if (stop == nullptr) {
788 return 0; /* Not valid. */
789 }
790
791 /* Check sequence type. */
792 for (buf_in++; fc_isspace(*buf_in); buf_in++);
793
794 if (*buf_in == SEQ_END) {
795 *seq_type = ST_STOP;
796 buf_in++;
797 } else {
798 for (end--; fc_isspace(*end); end--);
799
800 if (*end == SEQ_END) {
801 *seq_type = ST_SINGLE;
802
803 for (end--; fc_isspace(*end); end--);
804 } else {
805 *seq_type = ST_START;
806 }
807 }
808
809 while (fc_isspace(*buf_in)) {
810 buf_in++;
811 }
812
813 /* Check the length of the type name. */
814 for (name = buf_in; name < stop; name++) {
815 if (!fc_isalpha(*name)) {
816 break;
817 }
818 }
819 type_len = name - buf_in;
820
821 *type = -1;
822 for (i = 0; (name = text_tag_type_name(i)); i++) {
823 name_len = strlen(name);
824 if (name_len == type_len && 0 == fc_strncasecmp(name, buf_in, name_len)) {
825 buf_in += name_len;
826 *type = i;
827 break;
828 }
829 }
830 if (*type == -1) {
831 /* Try with short names. */
832 for (i = 0; (name = text_tag_type_short_name(i)); i++) {
833 name_len = strlen(name);
834 if (name_len == type_len
835 && 0 == fc_strncasecmp(name, buf_in, name_len)) {
836 buf_in += name_len;
837 *type = i;
838 break;
839 }
840 }
841 if (*type == -1) {
842 return 0; /* Not valid. */
843 }
844 }
845
846 while (fc_isspace(*buf_in)) {
847 buf_in++;
848 }
849
850 if (end - buf_in + 2 > 0) {
851 fc_strlcpy(buf, buf_in, MIN(end - buf_in + 2, len));
852 } else {
853 buf[0] = '\0';
854 }
855 return stop - featured_text + 1;
856}
857
858
859/**********************************************************************/
868 size_t featured_text_to_plain_text(const char *featured_text,
869 char *plain_text, size_t plain_text_len,
870 struct text_tag_list **tags,
871 bool replace_link_text)
872{
873 const char *text_in = featured_text;
874 char *text_out = plain_text;
875 size_t text_out_len = plain_text_len;
876
877 if (tags) {
878 *tags = text_tag_list_new();
879 }
880
881 while (*text_in != '\0' && text_out_len > 1) {
882 if (SEQ_START == *text_in) {
883 /* Escape sequence... */
884 char buf[text_out_len];
885 enum sequence_type seq_type;
886 enum text_tag_type type;
887 size_t len = extract_sequence_text(text_in, buf, text_out_len,
888 &seq_type, &type);
889
890 if (len > 0) {
891 /* Looks a valid sequence. */
892 text_in += len;
893 switch (seq_type) {
894 case ST_START:
895 if (tags) {
896 /* Create a new tag. */
897 struct text_tag *ptag = fc_malloc(sizeof(struct text_tag));
898
899 if (text_tag_init_from_sequence(ptag, type,
900 text_out - plain_text, buf)) {
901 text_tag_list_append(*tags, ptag);
902 } else {
903 text_tag_destroy(ptag);
904 log_featured_text("Couldn't create a text tag with \"%s\".",
905 buf);
906 }
907 }
908 break;
909 case ST_STOP:
910 if (tags) {
911 /* Set the stop offset. */
912 struct text_tag *ptag = nullptr;
913
914 /* Look up on reversed order. */
915 text_tag_list_rev_iterate(*tags, piter) {
916 if (piter->type == type
917 && piter->stop_offset == FT_OFFSET_UNSET) {
918 ptag = piter;
919 break;
920 }
921 } text_tag_list_rev_iterate_end;
922
923 if (ptag) {
924 ptag->stop_offset = text_out - plain_text;
925 } else {
926 log_featured_text("Extra text tag end for \"%s\".",
927 text_tag_type_name(type));
928 }
929 }
930 break;
931 case ST_SINGLE:
932 {
933 /* In this case, we replace the sequence by some text. */
934 struct text_tag tag;
935
936 if (!text_tag_init_from_sequence(&tag, type,
937 text_out - plain_text, buf)) {
938 log_featured_text("Couldn't create a text tag with \"%s\".",
939 buf);
940 } else {
941 len = text_tag_replace_text(&tag, text_out, text_out_len,
942 replace_link_text);
943 text_out += len;
944 text_out_len -= len;
945 if (tags) {
946 /* Set it in the list. */
947 struct text_tag *ptag = fc_malloc(sizeof(struct text_tag));
948
949 *ptag = tag;
950 ptag->stop_offset = text_out - plain_text;
951 text_tag_list_append(*tags, ptag);
952 }
953 }
954 }
955 break;
956 };
957 } else {
958 *text_out++ = *text_in++;
959 text_out_len--;
960 }
961 } else {
962 *text_out++ = *text_in++;
963 text_out_len--;
964 }
965 }
966 if (tags) {
967 /* Auto-stop all tags opened and not closed */
968 text_tag_list_iterate(*tags, ptag) {
969 if (ptag->stop_offset == FT_OFFSET_UNSET) {
970 ptag->stop_offset = text_out - plain_text;
971 }
972 } text_tag_list_iterate_end;
973 }
974 *text_out = '\0';
975
976 return plain_text_len - text_out_len;
977}
978
979/**********************************************************************/
997 size_t featured_text_apply_tag(const char *text_source,
998 char *featured_text, size_t featured_text_len,
999 enum text_tag_type tag_type,
1000 ft_offset_t start_offset,
1001 ft_offset_t stop_offset,
1002 ...)
1003{
1004 struct text_tag tag;
1005 size_t len, total_len = 0;
1006 va_list args;
1007
1008 if (start_offset == FT_OFFSET_UNSET
1009 || start_offset > strlen(text_source)
1010 || (stop_offset != FT_OFFSET_UNSET
1011 && stop_offset < start_offset)) {
1012 log_featured_text("featured_text_apply_tag(): invalid offsets.");
1013 return 0;
1014 }
1015
1016 va_start(args, stop_offset);
1017 if (!text_tag_initv(&tag, tag_type, start_offset, stop_offset, args)) {
1018 va_end(args);
1019 return 0;
1020 }
1021 va_end(args);
1022
1023 if (start_offset > 0) {
1024 /* First part: before the sequence. */
1025 len = 0;
1026 while (len < start_offset
1027 && *text_source != '\0'
1028 && featured_text_len > 1) {
1029 *featured_text++ = *text_source++;
1030 featured_text_len--;
1031 len++;
1032 }
1033 total_len += len;
1034 }
1035
1036 /* Start sequence. */
1037 len = text_tag_start_sequence(&tag, featured_text, featured_text_len);
1038 total_len += len;
1039 featured_text += len;
1040 featured_text_len -= len;
1041
1042 /* Second part: between the sequences. */
1043 len = start_offset;
1044 while (len < stop_offset
1045 && *text_source != '\0'
1046 && featured_text_len > 1) {
1047 *featured_text++ = *text_source++;
1048 featured_text_len--;
1049 len++;
1050 }
1051 total_len += len;
1052
1053 /* Stop sequence. */
1054 len = text_tag_stop_sequence(&tag, featured_text, featured_text_len);
1055 total_len += len;
1056 featured_text += len;
1057 featured_text_len -= len;
1058
1059 /* Third part: after the sequence. */
1060 while (*text_source != '\0'
1061 && featured_text_len > 1) {
1062 *featured_text++ = *text_source++;
1063 featured_text_len--;
1064 total_len++;
1065 }
1066 *featured_text = '\0';
1067
1068 return total_len;
1069}
1070
1071/**********************************************************************/
1076 const char *city_link(const struct city *pcity)
1077{
1078 static char buf[MAX_LEN_LINK];
1079
1080 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" id=%d name=\"%s\" %c%c",
1081 SEQ_START, text_tag_type_short_name(TTT_LINK),
1082 text_link_type_name(TLT_CITY), pcity->id,
1083 city_name_get(pcity), SEQ_END, SEQ_STOP);
1084 return buf;
1085}
1086
1087/**********************************************************************/
1093 const char *city_tile_link(const struct city *pcity)
1094{
1095 static char buf[MAX_LEN_LINK];
1096 const char *tag_name = text_tag_type_short_name(TTT_LINK);
1097
1098 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" x=%d y=%d%c%s%c%c%s%c",
1099 SEQ_START, tag_name, text_link_type_name(TLT_TILE),
1100 TILE_XY(city_tile(pcity)), SEQ_STOP, city_name_get(pcity),
1101 SEQ_START, SEQ_END, tag_name, SEQ_STOP);
1102 return buf;
1103}
1104
1105/**********************************************************************/
1110 const char *tile_link(const struct tile *ptile)
1111{
1112 static char buf[MAX_LEN_LINK];
1113
1114 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" x=%d y=%d %c%c",
1115 SEQ_START, text_tag_type_short_name(TTT_LINK),
1116 text_link_type_name(TLT_TILE), TILE_XY(ptile),
1117 SEQ_END, SEQ_STOP);
1118 return buf;
1119}
1120
1121/**********************************************************************/
1126 const char *unit_link(const struct unit *punit)
1127{
1128 static char buf[MAX_LEN_LINK];
1129
1130 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" id=%d name=\"%s\" %c%c",
1131 SEQ_START, text_tag_type_short_name(TTT_LINK),
1132 text_link_type_name(TLT_UNIT), punit->id,
1133 unit_name_translation(punit), SEQ_END, SEQ_STOP);
1134 return buf;
1135}
1136
1137/**********************************************************************/
1143 const char *unit_tile_link(const struct unit *punit)
1144{
1145 static char buf[MAX_LEN_LINK];
1146 const char *tag_name = text_tag_type_short_name(TTT_LINK);
1147
1148 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" x=%d y=%d%c%s%c%c%s%c",
1149 SEQ_START, tag_name, text_link_type_name(TLT_TILE),
1150 TILE_XY(unit_tile(punit)), SEQ_STOP,
1151 unit_name_translation(punit),
1152 SEQ_START, SEQ_END, tag_name, SEQ_STOP);
1153 return buf;
1154}
city_name_get
const char * city_name_get(const struct city *pcity)
Definition city.c:1128
city.h
city_tile
#define city_tile(_pcity_)
Definition city.h:564
combat.h
incite_cost
char * incite_cost
Definition comments.c:74
punit
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:74
tag_name
char * tag_name
Definition events.c:77
fcintl.h
_
#define _(String)
Definition fcintl.h:67
text_tag_init_from_sequence
static bool text_tag_init_from_sequence(struct text_tag *ptag, enum text_tag_type type, ft_offset_t start_offset, const char *sequence)
Definition featured_text.c:227
ftc_chat_private
const struct ft_color ftc_chat_private
Definition featured_text.c:88
featured_text_apply_tag
size_t featured_text_apply_tag(const char *text_source, char *featured_text, size_t featured_text_len, enum text_tag_type tag_type, ft_offset_t start_offset, ft_offset_t stop_offset,...)
Definition featured_text.c:997
ftc_luaconsole_debug
const struct ft_color ftc_luaconsole_debug
Definition featured_text.c:104
find_option
static bool find_option(const char *buf_in, const char *option, char *buf_out, size_t write_len)
Definition featured_text.c:178
ftc_vote_abstain
const struct ft_color ftc_vote_abstain
Definition featured_text.c:97
text_tag_link_type
enum text_link_type text_tag_link_type(const struct text_tag *ptag)
Definition featured_text.c:745
ftc_log
const struct ft_color ftc_log
Definition featured_text.c:76
ftc_player_lost
const struct ft_color ftc_player_lost
Definition featured_text.c:83
city_tile_link
const char * city_tile_link(const struct city *pcity)
Definition featured_text.c:1093
featured_text_to_plain_text
size_t featured_text_to_plain_text(const char *featured_text, char *plain_text, size_t plain_text_len, struct text_tag_list **tags, bool replace_link_text)
Definition featured_text.c:868
ftc_luaconsole_verbose
const struct ft_color ftc_luaconsole_verbose
Definition featured_text.c:103
text_tag_copy
struct text_tag * text_tag_copy(const struct text_tag *ptag)
Definition featured_text.c:667
text_tag_list_rev_iterate
#define text_tag_list_rev_iterate(tags, ptag)
Definition featured_text.c:44
SEQ_STOP
#define SEQ_STOP
Definition featured_text.c:38
tile_link
const char * tile_link(const struct tile *ptile)
Definition featured_text.c:1110
SEQ_START
#define SEQ_START
Definition featured_text.c:37
ftc_command
const struct ft_color ftc_command
Definition featured_text.c:80
text_tag_stop_offset
ft_offset_t text_tag_stop_offset(const struct text_tag *ptag)
Definition featured_text.c:708
text_tag_initv
static bool text_tag_initv(struct text_tag *ptag, enum text_tag_type type, ft_offset_t start_offset, ft_offset_t stop_offset, va_list args)
Definition featured_text.c:391
ftc_server
const struct ft_color ftc_server
Definition featured_text.c:77
ftc_vote_failed
const struct ft_color ftc_vote_failed
Definition featured_text.c:94
text_tag_destroy
void text_tag_destroy(struct text_tag *ptag)
Definition featured_text.c:684
ftc_vote_yes
const struct ft_color ftc_vote_yes
Definition featured_text.c:95
text_tag_start_sequence
static size_t text_tag_start_sequence(const struct text_tag *ptag, char *buf, size_t len)
Definition featured_text.c:474
ftc_luaconsole_error
const struct ft_color ftc_luaconsole_error
Definition featured_text.c:100
ftc_warning
const struct ft_color ftc_warning
Definition featured_text.c:75
text_tag_color_foreground
const char * text_tag_color_foreground(const struct text_tag *ptag)
Definition featured_text.c:717
text_tag_list_rev_iterate_end
#define text_tag_list_rev_iterate_end
Definition featured_text.c:46
text_link_type_name
static const char * text_link_type_name(enum text_link_type type)
Definition featured_text.c:159
ftc_client
const struct ft_color ftc_client
Definition featured_text.c:78
ftc_luaconsole_normal
const struct ft_color ftc_luaconsole_normal
Definition featured_text.c:102
ftc_editor
const struct ft_color ftc_editor
Definition featured_text.c:79
text_tag_type_name
static const char * text_tag_type_name(enum text_tag_type type)
Definition featured_text.c:110
text_tag_replace_text
static size_t text_tag_replace_text(const struct text_tag *ptag, char *buf, size_t len, bool replace_link_text)
Definition featured_text.c:578
city_link
const char * city_link(const struct city *pcity)
Definition featured_text.c:1076
ftc_any
const struct ft_color ftc_any
Definition featured_text.c:73
ftc_vote_no
const struct ft_color ftc_vote_no
Definition featured_text.c:96
ftc_vote_passed
const struct ft_color ftc_vote_passed
Definition featured_text.c:93
MAX_LEN_STR
#define MAX_LEN_STR
Definition featured_text.c:41
log_featured_text
#define log_featured_text
Definition featured_text.c:42
text_tag_stop_sequence
static size_t text_tag_stop_sequence(const struct text_tag *ptag, char *buf, size_t len)
Definition featured_text.c:563
ftc_luaconsole_warn
const struct ft_color ftc_luaconsole_warn
Definition featured_text.c:101
extract_sequence_text
static size_t extract_sequence_text(const char *featured_text, char *buf, size_t len, enum sequence_type *seq_type, enum text_tag_type *type)
Definition featured_text.c:774
text_tag_link_id
int text_tag_link_id(const struct text_tag *ptag)
Definition featured_text.c:760
ftc_chat_luaconsole
const struct ft_color ftc_chat_luaconsole
Definition featured_text.c:89
text_tag_type_short_name
static const char * text_tag_type_short_name(enum text_tag_type type)
Definition featured_text.c:135
text_tag_start_offset
ft_offset_t text_tag_start_offset(const struct text_tag *ptag)
Definition featured_text.c:700
text_tag_new
struct text_tag * text_tag_new(enum text_tag_type tag_type, ft_offset_t start_offset, ft_offset_t stop_offset,...)
Definition featured_text.c:641
ftc_vote_team
const struct ft_color ftc_vote_team
Definition featured_text.c:92
ftc_game_start
const struct ft_color ftc_game_start
Definition featured_text.c:84
unit_link
const char * unit_link(const struct unit *punit)
Definition featured_text.c:1126
ftc_server_prompt
const struct ft_color ftc_server_prompt
Definition featured_text.c:82
ftc_changed
struct ft_color ftc_changed
Definition featured_text.c:81
ftc_vote_public
const struct ft_color ftc_vote_public
Definition featured_text.c:91
sequence_type
sequence_type
Definition featured_text.c:66
ST_STOP
@ ST_STOP
Definition featured_text.c:68
ST_SINGLE
@ ST_SINGLE
Definition featured_text.c:69
ST_START
@ ST_START
Definition featured_text.c:67
unit_tile_link
const char * unit_tile_link(const struct unit *punit)
Definition featured_text.c:1143
text_tag_color_background
const char * text_tag_color_background(const struct text_tag *ptag)
Definition featured_text.c:731
ftc_luaconsole_input
const struct ft_color ftc_luaconsole_input
Definition featured_text.c:99
SEQ_END
#define SEQ_END
Definition featured_text.c:39
ftc_chat_public
const struct ft_color ftc_chat_public
Definition featured_text.c:86
ftc_chat_ally
const struct ft_color ftc_chat_ally
Definition featured_text.c:87
featured_text.h
text_tag_list_iterate_end
#define text_tag_list_iterate_end
Definition featured_text.h:116
text_tag_list_iterate
#define text_tag_list_iterate(tags, ptag)
Definition featured_text.h:114
FT_OFFSET_UNSET
#define FT_OFFSET_UNSET
Definition featured_text.h:104
MAX_LEN_LINK
#define MAX_LEN_LINK
Definition featured_text.h:138
text_tag_list_new
#define text_tag_list_new()
Definition featured_text.h:213
ft_offset_t
int ft_offset_t
Definition featured_text.h:102
text_link_type
text_link_type
Definition featured_text.h:131
TLT_TILE
@ TLT_TILE
Definition featured_text.h:133
TLT_UNIT
@ TLT_UNIT
Definition featured_text.h:134
TLT_CITY
@ TLT_CITY
Definition featured_text.h:132
text_tag_type
text_tag_type
Definition featured_text.h:120
TTT_LINK
@ TTT_LINK
Definition featured_text.h:126
TTT_BOLD
@ TTT_BOLD
Definition featured_text.h:121
TTT_ITALIC
@ TTT_ITALIC
Definition featured_text.h:122
TTT_STRIKE
@ TTT_STRIKE
Definition featured_text.h:123
TTT_COLOR
@ TTT_COLOR
Definition featured_text.h:125
TTT_UNDERLINE
@ TTT_UNDERLINE
Definition featured_text.h:124
FT_COLOR
#define FT_COLOR(fg, bg)
Definition featured_text.h:145
wld
struct world wld
Definition game.c:63
game_unit_by_number
struct unit * game_unit_by_number(int id)
Definition game.c:116
game_city_by_number
struct city * game_city_by_number(int id)
Definition game.c:107
game.h
type
GType type
Definition repodlgs.c:1313
name
const char * name
Definition inputfile.c:127
log.h
log_error
#define log_error(message,...)
Definition log.h:103
index_to_tile
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Definition map.c:462
map_pos_to_tile
struct tile * map_pos_to_tile(const struct civ_map *nmap, int map_x, int map_y)
Definition map.c:425
map.h
mem.h
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
len
int len
Definition packhand.c:127
str_to_int
bool str_to_int(const char *str, int *pint)
Definition shared.c:517
shared.h
MIN
#define MIN(x, y)
Definition shared.h:55
y
struct sprite int int y
Definition sprite_g.h:31
x
struct sprite int x
Definition sprite_g.h:31
city
Definition city.h:320
city::id
int id
Definition city.h:326
color
Definition colors.h:21
ft_color
Definition featured_text.h:141
option
Definition options.c:514
text_tag
Definition featured_text.c:49
text_tag::id
int id
Definition featured_text.c:60
text_tag::background
char background[MAX_LEN_STR]
Definition featured_text.c:56
text_tag::name
char name[MAX_LEN_STR]
Definition featured_text.c:61
text_tag::stop_offset
ft_offset_t stop_offset
Definition featured_text.c:52
text_tag::start_offset
ft_offset_t start_offset
Definition featured_text.c:51
text_tag::type
enum text_tag_type type
Definition featured_text.c:50
text_tag::color
struct text_tag::@26::@28 color
text_tag::foreground
char foreground[MAX_LEN_STR]
Definition featured_text.c:55
text_tag::link
struct text_tag::@26::@29 link
text_tag::type
enum text_link_type type
Definition featured_text.c:59
tile
Definition tile.h:50
unit
Definition unit.h:140
unit::id
int id
Definition unit.h:147
world::map
struct civ_map map
Definition world_object.h:38
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
fc_isalpha
bool fc_isalpha(char c)
Definition support.c:1207
fc_strlcpy
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:777
fc_isspace
bool fc_isspace(char c)
Definition support.c:1240
fc_isalnum
bool fc_isalnum(char c)
Definition support.c:1196
fc_strncasecmp
int fc_strncasecmp(const char *str0, const char *str1, size_t n)
Definition support.c:235
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
tile.h
tile_index
#define tile_index(_pt_)
Definition tile.h:89
TILE_XY
#define TILE_XY(ptile)
Definition tile.h:43
unit.h
unit_tile
#define unit_tile(_pu)
Definition unit.h:397
unit_name_translation
const char * unit_name_translation(const struct unit *punit)
Definition unittype.c:1569