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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
/*** format.c - Parameter Formatter
*
* Microsoft Confidential
* Copyright (C) Microsoft Corporation 1994
* All Rights Reserved.
*
* Author:
* Benjamin W. Slivka
*
* History:
* 28-Apr-1994 bens Initial version
* 10-May-1994 bens Add braces support
*/
#include <memory.h>
#include <string.h>
#include "types.h"
#include "asrt.h"
#include "error.h"
#include "message.h"
#include "misc.h"
#include "inf.h"
#include "format.h"
#include "format.msg"
/*** SubstituteFormatString - Do parameter substitution
*
* NOTE: See format.h for entry/exit conditions.
*/
BOOL SubstituteFormatString(char *pszDst,
int cbDst,
char *pszSrc,
PFNFORMATPARM pfnfp,
void *pv,
PERROR perr)
{
char achParmName[cbPARM_NAME_MAX];
int cb;
int cch;
BOOL fParmSeen; // TRUE => parm seen in {braces}
BOOL fParmEmpty; // TRUE => all parms were empty in {opt}
char *pch;
char *pszAfterParm; // Points to first char after var subst.
char *pszOptStart; // Start of optional text
char *pszParmStart; // Points to first * in var substitution
//** Not in conditional test
pszOptStart = NULL;
//** Process string for parameters and conditional text
while (*pszSrc != '\0') {
switch (*pszSrc) {
case chFP_LBRACE:
pszSrc++; // Eat the left brace
if (*pszSrc == chFP_LBRACE) { // Have "{{"
//** Collapse two {{ into one {
if (!copyBounded(&pszDst,&cbDst,&pszSrc,1)) {
goto error_copying;
}
}
else {
//** Make sure we're not already in a brace section
if (pszOptStart) {
ErrSet(perr,pszFMTERR_NESTED_BRACES,"%c%s",
chFP_LBRACE,pszSrc);
return FALSE;
}
pszOptStart = pszDst; // Save start of conditional text
fParmSeen = FALSE; // No parm seen, yet
fParmEmpty = TRUE; // Assume parm was empty
}
break;
case chFP_RBRACE:
pszSrc++; // Eat the right brace
if (*pszSrc == chFP_RBRACE) { // Have "}}"
//** Collapse two }} into one }
if (!copyBounded(&pszDst,&cbDst,&pszSrc,1)) {
goto error_copying;
}
}
else {
//** Make sure we are in a brace section
if (!pszOptStart) {
ErrSet(perr,pszFMTERR_RIGHT_WITH_NO_LEFT,"%c%c%s",
chFP_RBRACE,chFP_LBRACE,pszSrc);
return FALSE;
}
//** Omit text if we need to
if (fParmSeen && fParmEmpty) { // All parms were empty
//** Remove optional text
Assert(pszDst >= pszOptStart);
cbDst += pszDst - pszOptStart;
pszDst = pszOptStart;
}
//** Reset state variables
pszOptStart = NULL;
}
break;
case chFP_MARKER:
pszParmStart = pszSrc; // Save start for error messgages
pszSrc++; // Skip first *
if (*pszSrc == chFP_MARKER) { // Have "**"
//** Collapse two ** into one *
if (!copyBounded(&pszDst,&cbDst,&pszSrc,1)) {
goto error_copying;
}
}
else {
//** Attempt parameter substitution
pch = strchr(pszSrc,chFP_MARKER); // Finding ending *
if (!pch) { // No terminating *
ErrSet(perr,pszFMTERR_MISSING_SUBST,"%c%s",
chFP_MARKER,pszParmStart);
return FALSE;
}
pszAfterParm = pch+1; // Point after ending *
//** Extract parameter name
cch = pch - pszSrc; // Length of parameter name
if (cch >= sizeof(achParmName)) {
ErrSet(perr,pszFMTERR_PARM_NAME_TOO_LONG,"%d%s",
sizeof(achParmName)-1,pszParmStart);
return FALSE;
}
memcpy(achParmName,pszSrc,cch); // Copy it
achParmName[cch] = '\0'; // Terminate it
//** Get parameter value
if (-1 == (cb = (*pfnfp)(pszDst, // Destination
cbDst, // Space remaining
achParmName, // Parm name
pv, // Context
perr))) {
return FALSE; // Error already filled in
}
//** Adjust output buffer and space remaining
// NOTE: Don't count NUL byte, as we do that at the very end
Assert(cbDst >= cb);
pszDst += cb;
cbDst -= cb;
//** Remember we saw a parm, and if it was not empty
fParmSeen = TRUE;
if (cb > 0) {
fParmEmpty = FALSE; // At least one parm not empty
}
//** Skip over parameter name
pszSrc = pszAfterParm;
}
break;
default:
//** Just copy the character
if (!copyBounded(&pszDst,&cbDst,&pszSrc,1)) {
goto error_copying;
}
}
} /* while */
//** Make sure we didn't leave an open optional text section
if (pszOptStart) {
ErrSet(perr,pszFMTERR_MISSING_RIGHT_BRACE,"%c",chFP_RBRACE);
return FALSE;
}
//** Terminate processed string
if (cbDst == 0) { // No room for terminator
goto error_copying;
}
*pszDst++ = '\0'; // Terminate string
//** Success
return TRUE;
error_copying:
ErrSet(perr,pszFMTERR_COPYING_OVERFLOW,"%s",pszSrc);
return FALSE;
} /* SubstituteFormatString() */
|