6
6
#pragma newdecls required
7
7
#pragma semicolon 1
8
8
9
+ // --------------------------------------------------------------------------------------------------------------------------------
10
+ // Import sources
11
+ // --------------------------------------------------------------------------------------------------------------------------------
12
+
9
13
enum ImportSource
10
14
{
11
15
IMPORT_STRIPPER
12
16
}
13
17
18
+ // --------------------------------------------------------------------------------------------------------------------------------
19
+ // Import utils
20
+ // --------------------------------------------------------------------------------------------------------------------------------
21
+
22
+ methodmap ImportUtil
23
+ {
24
+ public static bool FileFilter (ImportSource src, const char [] szFileName, char szMapName[MAX_MAPNAME])
25
+ {
26
+ int len = strlen (szFileName);
27
+ int extLen;
28
+
29
+ if (src == IMPORT_STRIPPER)
30
+ {
31
+ if (!StrEndsWithEx (szFileName, len, " .cfg" , false ))
32
+ return false ;
33
+ extLen = 4 ;
34
+ }
35
+ else ThrowError (" ImportUtil.FileFilter not implemented for this import source." );
36
+
37
+ len = len - extLen + 1 ;
38
+ if (len > MAX_MAPNAME)
39
+ {
40
+ MsgSrv (" Map name in \" %s\" exceeds limit of %d characters and won't be imported." , szFileName, MAX_MAPNAME - 1 );
41
+ return false ;
42
+ }
43
+
44
+ strcopy (szMapName, len, szFileName);
45
+ return true ;
46
+ }
47
+
48
+ public static bool ImportAsNode (const char [] szNode, const char [] szNodeContent, StringBuilder pConfigBuilder, char [] szError, int maxErrorLen)
49
+ {
50
+ // This regex enters first child key from given position.
51
+ // Matching stops after the opening { brace.
52
+ //
53
+ // Raw form:
54
+ // /^(?:\/\/.*|"(?:\\.|[^"])*"|\s|[^}{"])*?{/
55
+
56
+ Regex pEnterChildNode = new Regex (" ^(?:\\ /\\ /.*|\" (?:\\\\ .|[^\" ])*\" |\\ s|[^}{\" ])*?{" );
57
+
58
+ // This regex consists of OR'd groups each representing a part of KV syntax. The <braces> group is recursive.
59
+ // The target node is searched at current depth, as in kv.JumpToKey().
60
+ // Matching stops after the name of the specified node.
61
+ //
62
+ // Raw form:
63
+ // /^(?:(?<comments>\/\/.*)|(?<braces>{(?:(?&comments)|(?&braces)|(?"es)|(?&misc))*})|(?<quotes>"(?:\\.|[^"])*")|(?<misc>\s|[^"{}]))*?(?:(?<=\s)(?<target>entity)(?=[{\s])|"(?&target)")/
64
+
65
+ char szGoToNode[256 ] = " ^(?:(?<comments>\\ /\\ /.*)|(?<braces>{(?:(?&comments)|(?&braces)|(?"es)|(?&misc))*})|(?<quotes>\" (?:\\\\ .|[^\" ])*\" )|(?<misc>\\ s|[^\" {}]))*?(?:(?<=\\ s)(?<target>%s)(?=[{\\ s])|\" (?&target)\" )" ;
66
+ Format (szGoToNode, sizeof (szGoToNode), szGoToNode, szNode);
67
+ Regex pGoToNode = new Regex (szGoToNode);
68
+
69
+ // Moves to end of current node.
70
+ // Same as above, but without the target node mathing part at the end.
71
+ // Matching stops before closing } brace.
72
+ //
73
+ // Raw form:
74
+ // /^(?:(?<comments>\/\/.*)|(?<braces>{(?:(?&comments)|(?&braces)|(?"es)|(?&misc))*})|(?<quotes>"(?:\\.|[^"])*")|(?<misc>\s|[^"{}]))*/
75
+
76
+ Regex pGoToEnd = new Regex (" ^(?:(?<comments>\\ /\\ /.*)|(?<braces>{(?:(?&comments)|(?&braces)|(?"es)|(?&misc))*})|(?<quotes>\" (?:\\\\ .|[^\" ])*\" )|(?<misc>\\ s|[^\" {}]))*" );
77
+
78
+ char [] szConfig = new char [pConfigBuilder.BufferSize ];
79
+ pConfigBuilder.ToString (szConfig).Reset ();
80
+
81
+ int offset;
82
+ if (!ImportUtil.RegexAdvance (pEnterChildNode, szConfig, offset))
83
+ {
84
+ Format (szError, maxErrorLen, " SourceCoop config root element not found" );
85
+ }
86
+ else
87
+ {
88
+ if (ImportUtil.RegexAdvance (pGoToNode, szConfig, offset))
89
+ {
90
+ // found requested node
91
+
92
+ if (ImportUtil.RegexAdvance (pEnterChildNode, szConfig, offset))
93
+ {
94
+ pConfigBuilder.AppendEx (szConfig, offset);
95
+ pConfigBuilder.Append (" \n " );
96
+ pConfigBuilder.Append (szNodeContent);
97
+ pConfigBuilder.Append (" \t " );
98
+ if (ImportUtil.RegexAdvance (pGoToEnd, szConfig, offset))
99
+ {
100
+ pConfigBuilder.Append (szConfig[offset]);
101
+ }
102
+ else
103
+ {
104
+ Format (szError, maxErrorLen, " Unable to traverse SourceCoop config (#3)" );
105
+ }
106
+ }
107
+ else
108
+ {
109
+ Format (szError, maxErrorLen, " Unable to traverse SourceCoop config (#1)" );
110
+ }
111
+ }
112
+ else
113
+ {
114
+ // requested node missing
115
+
116
+ if (ImportUtil.RegexAdvance (pGoToEnd, szConfig, offset))
117
+ {
118
+ pConfigBuilder.AppendEx (szConfig, offset);
119
+ pConfigBuilder.Append (" \t\" " );
120
+ pConfigBuilder.Append (szNode);
121
+ pConfigBuilder.Append (" \"\n\t {\n " );
122
+ pConfigBuilder.Append (szNodeContent);
123
+ pConfigBuilder.Append (" \t }\n " );
124
+ pConfigBuilder.Append (szConfig[offset]);
125
+ }
126
+ else
127
+ {
128
+ Format (szError, maxErrorLen, " Unable to traverse SourceCoop config (#2)" );
129
+ }
130
+ }
131
+ }
132
+
133
+ pEnterChildNode.Close ();
134
+ pGoToNode.Close ();
135
+ pGoToEnd.Close ();
136
+ return (szError[0 ] == EOS);
137
+ }
138
+
139
+ public static bool RegexAdvance (Regex regex, const char [] szStr, int &offset = 0 )
140
+ {
141
+ int ret = regex.Match (szStr[offset]);
142
+ if (ret != -1 && regex.MatchCount ())
143
+ {
144
+ offset += regex.MatchOffset ();
145
+ return true ;
146
+ }
147
+ return false ;
148
+ }
149
+
150
+ public static void AppendLine (StringBuilder sb, const char [] szText, int indent)
151
+ {
152
+ ImportUtil.Indent (sb, indent);
153
+ sb.Append (szText);
154
+ sb.Append (" \n " );
155
+ }
156
+
157
+ public static void Indent (StringBuilder sb, int indent)
158
+ {
159
+ for (int i = 0 ; i < indent; i++)
160
+ sb.Append (" \t " );
161
+ }
162
+ }
163
+
164
+ // --------------------------------------------------------------------------------------------------------------------------------
165
+ // Import boilerplate
166
+ // --------------------------------------------------------------------------------------------------------------------------------
167
+
14
168
bool ImportConfigs (ImportSource src, const char [] szMapFilter, bool bCreate, bool bDryRun, int &count, int &createCount, int &errors)
15
169
{
16
170
if (src == IMPORT_STRIPPER)
@@ -20,11 +174,11 @@ bool ImportConfigs(ImportSource src, const char[] szMapFilter, bool bCreate, boo
20
174
ThrowError (" ImportConfigs not implemented for this import source." ); return false ;
21
175
}
22
176
23
- bool ImportConfig (ImportSource src, const char [] szPath, File pSrcCoopConfig , char [] szError, int maxErrorLen)
177
+ bool ImportConfig (ImportSource src, const char [] szPath, StringBuilder pConfigBuilder , char [] szError, int maxErrorLen)
24
178
{
25
179
if (src == IMPORT_STRIPPER)
26
180
{
27
- return ImportStripperConfig (szPath, pSrcCoopConfig , szError, maxErrorLen);
181
+ return ImportStripperConfig (szPath, pConfigBuilder , szError, maxErrorLen);
28
182
}
29
183
ThrowError (" ImportConfig not implemented for this import source." ); return false ;
30
184
}
@@ -61,11 +215,13 @@ bool ImportConfigsDir(ImportSource src, const char[] szDir, const char[] szMapFi
61
215
{
62
216
if (!bCreate)
63
217
{
64
- MsgSrv (" Found config for \" %s\" , but no SourceCoop config. Run with <CREATE> set to 1 to remedy this ." , szMapName);
218
+ MsgSrv (" Found config for \" %s\" , but no SourceCoop config. Run with <CREATE> set to 1 to auto-create missing configs ." , szMapName);
65
219
continue ;
66
220
}
67
221
if (bDryRun)
68
222
{
223
+ MsgSrv (" - Create: %s" , szSrcCoopConfig);
224
+ count++; createCount++;
69
225
continue ;
70
226
}
71
227
if (!CoopManager.FindMapConfig (szMapName, szSrcCoopConfig, ccl, true ))
@@ -77,17 +233,38 @@ bool ImportConfigsDir(ImportSource src, const char[] szDir, const char[] szMapFi
77
233
bCreated = true ;
78
234
}
79
235
80
- File pSrcCoopConfig = OpenFile (szSrcCoopConfig, " r+" , CoopManager.ConfigUsesValveFS (ccl));
236
+ File pSrcCoopConfig = OpenFileEx (szSrcCoopConfig, " r+" , CoopManager.ConfigUsesValveFS (ccl));
81
237
if (!pSrcCoopConfig)
82
238
{
83
239
errors++;
84
240
MsgSrv (" Unable to read SourceCoop config \" %s\" (ValveFS=%d)" , szSrcCoopConfig, CoopManager.ConfigUsesValveFS (ccl));
85
241
continue ;
86
242
}
87
-
243
+
244
+ szError = " " ;
88
245
Format (szFileName, sizeof (szFileName), " %s/%s" , szDir, szFileName);
89
- if (bDryRun || ImportConfig (src, szFileName, pSrcCoopConfig, szError, sizeof (szError)))
246
+ StringBuilder pConfigBuilder = new StringBuilder ();
247
+
248
+ if (!pConfigBuilder.AppendFile (pSrcCoopConfig))
90
249
{
250
+ Format (szError, sizeof (szError), " Unable to read from SourceCoop config" );
251
+ }
252
+ else
253
+ {
254
+ if (ImportConfig (src, szFileName, pConfigBuilder, szError, sizeof (szError)))
255
+ {
256
+ if (!bDryRun)
257
+ {
258
+ if (!pSrcCoopConfig.Seek (0 , SEEK_SET) || !pConfigBuilder.ToFile (pSrcCoopConfig))
259
+ {
260
+ Format (szError, sizeof (szError), " Unable to write to SourceCoop config" );
261
+ }
262
+ }
263
+ }
264
+ }
265
+
266
+ if (szError[0 ] == EOS)
267
+ {
91
268
count++;
92
269
if (bCreated)
93
270
{
@@ -111,6 +288,7 @@ bool ImportConfigsDir(ImportSource src, const char[] szDir, const char[] szMapFi
111
288
DeleteFile (szSrcCoopConfig, CoopManager.ConfigUsesValveFS (ccl));
112
289
}
113
290
}
291
+ pConfigBuilder.Close ();
114
292
}
115
293
dir.Close ();
116
294
return true ;
@@ -134,7 +312,7 @@ bool ImportConfigsDir(ImportSource src, const char[] szDir, const char[] szMapFi
134
312
#define STRIPPER_ELEMENTS_ROOT (STRIPPER_TOK_FILTER|STRIPPER_TOK_ADD|STRIPPER_TOK_MODIFY)
135
313
#define STRIPPER_ELEMENTS_MODIFY (STRIPPER_TOK_MATCH|STRIPPER_TOK_REPLACE|STRIPPER_TOK_DELETE|STRIPPER_TOK_INSERT)
136
314
137
- bool ImportStripperConfig (const char [] szStripperConfig, File pSrcCoopConfig , char [] szError, int maxErrorLen)
315
+ bool ImportStripperConfig (const char [] szStripperConfig, StringBuilder pConfigBuilder , char [] szError, int maxErrorLen)
138
316
{
139
317
File pStripperCfg = OpenFile (szStripperConfig, " rt" );
140
318
if (!pStripperCfg)
@@ -281,7 +459,7 @@ bool ImportStripperConfig(const char[] szStripperConfig, File pSrcCoopConfig, ch
281
459
{
282
460
char [] szOut = new char [pOutBuilder.BufferSize ];
283
461
pOutBuilder.ToString (szOut);
284
- bError = !ImportUtil.ImportAsNode (" entity_import_stripper" , true , szOut, pSrcCoopConfig , szError, maxErrorLen);
462
+ bError = !ImportUtil.ImportAsNode (" entity_import_stripper" , szOut, pConfigBuilder , szError, maxErrorLen);
285
463
}
286
464
287
465
pStripperCfg.Close ();
@@ -290,79 +468,4 @@ bool ImportStripperConfig(const char[] szStripperConfig, File pSrcCoopConfig, ch
290
468
pKvDataRegex.Close ();
291
469
292
470
return !bError;
293
- }
294
-
295
- // --------------------------------------------------------------------------------------------------------------------------------
296
- // Import utils
297
- // --------------------------------------------------------------------------------------------------------------------------------
298
-
299
- methodmap ImportUtil
300
- {
301
- public static bool FileFilter (ImportSource src, const char [] szFileName, char szMapName[MAX_MAPNAME])
302
- {
303
- int len = strlen (szFileName);
304
- int extLen;
305
-
306
- if (src == IMPORT_STRIPPER)
307
- {
308
- if (!StrEndsWithEx (szFileName, len, " .cfg" , false ))
309
- return false ;
310
- extLen = 4 ;
311
- }
312
- else ThrowError (" ImportUtil.FileFilter not implemented for this import source." );
313
-
314
- len = len - extLen + 1 ;
315
- if (len > MAX_MAPNAME)
316
- {
317
- MsgSrv (" Map name in \" %s\" exceeds limit of %d characters and won't be imported." , szFileName, MAX_MAPNAME - 1 );
318
- return false ;
319
- }
320
-
321
- strcopy (szMapName, len, szFileName);
322
- return true ;
323
- }
324
-
325
- public static bool ImportAsNode (const char [] szNode, bool bReplaceNode, const char [] szNodeContent, File pSrcCoopConfig, char [] szError, int maxErrorLen)
326
- {
327
- StringBuilder sb = new StringBuilder ();
328
- if (!sb.AppendFile (pSrcCoopConfig))
329
- {
330
- sb.Close ();
331
- Format (szError, maxErrorLen, " Unable to read from SourceCoop config" );
332
- return false ;
333
- }
334
-
335
- int iConfigLen = sb.BufferSize ;
336
- char [] szConfig = new char [iConfigLen];
337
- sb.ToString (szConfig);
338
-
339
- PrintToServer (szConfig);
340
-
341
- // This regex enters the next (or first) child from given position. Matching stops at opening { brace.
342
- // /^(?:\/\/.*|"(?:\\.|[^"])*"|\s|[^}{"])*?{/
343
- Regex pEnterChildNode = new Regex (" ^(?:\\ /\\ /.*|\" (?:\\\\ .|[^\" ])*\" |\\ s|[^}{\" ])*?{" );
344
-
345
- // This regex consists of OR'd groups each representing a part of KV syntax. The <braces> group is able to recurse itself.
346
- // The target node is searched only at current depth, as in kv.JumpToKey(). Matching stops at the start of the specified node (positive lookeahead).
347
- // /^(?:(?<comments>\/\/.*)|(?="?nodename"?)|(?<braces>{(?:(?&comments)|(?&braces)|(?"es)|(?&misc))*})|(?<quotes>"(?:\\.|[^"])*")|(?<misc>\s|[^"{}]))*/
348
- char szGoToNode[256 ] = " ^(?:(?<comments>\\ /\\ /.*)|(?=\" ?%s\" ?)|(?<braces>{(?:(?&comments)|(?&braces)|(?"es)|(?&misc))*})|(?<quotes>\" (?:\\\\ .|[^\" ])*\" )|(?<misc>\\ s|[^\" {}]))*" ;
349
- Format (szGoToNode, sizeof (szGoToNode), szGoToNode, szNode);
350
- Regex pGoToNode = new Regex (szGoToNode);
351
-
352
- sb.Close ();
353
- return true ;
354
- }
355
-
356
- public static void AppendLine (StringBuilder sb, const char [] szText, int indent)
357
- {
358
- ImportUtil.Indent (sb, indent);
359
- sb.Append (szText);
360
- sb.Append (" \n " );
361
- }
362
-
363
- public static void Indent (StringBuilder sb, int indent)
364
- {
365
- for (int i = 0 ; i < indent; i++)
366
- sb.Append (" \t " );
367
- }
368
471
}
0 commit comments