forked from sumatrapdfreader/sumatrapdf
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStrFormat.h
More file actions
119 lines (100 loc) · 3.15 KB
/
Copy pathStrFormat.h
File metadata and controls
119 lines (100 loc) · 3.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/* Copyright 2015 the SumatraPDF project authors (see AUTHORS file).
License: Simplified BSD (see COPYING.BSD) */
/*
fmt::Fmt is type-safe printf()-like system with support for both %-style formatting
directives and C#-like positional directives ({0}, {1} etc.).
Type safety is achieved by using strongly typed methods for adding arguments
(i(), c(), s() etc.). We also verify that the type of the argument matches
the type of formatting directive.
Positional directives are useful in translations with more than 1 argument
because in some languages translation is akward if you can't re-arrange
the order of arguments.
TODO: we should change at least those translations that involve 2 or more arguments.
TODO: ultimately we shouldn't use sprintf() in the implementation, so that we are
sure what the semantics are and they are always the same (independent of platform).
We should serialize all values ourselves.
TODO: similar approach could be used for type-safe scanf() replacement.
Idiomatic usage:
fmt::Fmt fmt("%d = %s");
char *s = fmt.i(5).s("5").Get(); // returns "5 = 5"
// s is valid until fmt is valid
// use .GetDup() to get a copy that must be free()d
// you can re-use fmt as:
s = fmt.ParseFormat("{1} = {2} + {0}").i(3).s("3").s(L"
You can mix % and {} directives but beware, as the rule for assigning argument
number to % directive is simple (n-th argument position for n-th % directive)
but it's easy to mis-count when adding {} to the mix.
*/
namespace fmt {
// arbitrary limits, but should be large enough for us
// the bigger the limit, the bigger the sizeof(Fmt)
enum { MaxInstructions = 32 };
enum {
// more than MaxInstructions for positional args
MaxArgs = 32 + 8
};
enum Type {
FormatStr, // from format string
Char,
Int,
Float,
Double,
Str,
WStr,
Any,
Invalid,
};
// formatting instruction
struct Inst {
Type t;
int argNo; // <0 for strings that come from formatting string
};
// argument to a formatting instruction
// at the front are arguments given with i(), s() etc.
// at the end are FormatStr arguments from format string
struct Arg {
Type t;
size_t len; // for s when FormatStr
union {
char c;
int i;
float f;
double d;
const char *s;
const WCHAR *ws;
};
};
class Fmt {
public:
Fmt(const char *fmt);
Fmt &i(int);
Fmt &s(const char *);
Fmt &s(const WCHAR *);
Fmt &c(char);
Fmt &f(float);
Fmt &f(double);
Fmt &ParseFormat(const char *fmt);
Fmt &Reset();
char *Get();
char *GetDup();
bool isOk; // true if mismatch between formatting instruction and args
private:
const char *parseArgDef(const char *fmt);
void addFormatStr(const char *s, size_t len);
const char *parseArgDefPerc(const char *);
const char *parseArgDefPositional(const char *);
Fmt &addArgType(Type t);
void serializeInst(int n);
DWORD threadId;
const char *format;
Inst instructions[MaxInstructions];
int nInst;
Arg args[MaxArgs];
int nArgs;
int nArgsUsed;
int maxArgNo;
int currPercArgNo;
int currArgFromFormatNo; // counts from the end of args
str::Str<char> res;
};
}