demo-reader 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -19,3 +19,7 @@ rdoc
19
19
  pkg
20
20
 
21
21
  ## PROJECT::SPECIFIC
22
+ *.o
23
+ ext/dm68/Makefile
24
+ ext/dm68/dm68.bundle
25
+
data/README.rdoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = demo-reader
2
2
 
3
- A library to parse warsow demo files
3
+ A library to parse warsow and q3 demo files
4
4
 
5
5
  == Note on Patches/Pull Requests
6
6
 
data/Rakefile CHANGED
@@ -5,8 +5,8 @@ begin
5
5
  require 'jeweler'
6
6
  Jeweler::Tasks.new do |gem|
7
7
  gem.name = "demo-reader"
8
- gem.summary = %Q{A library to read warsow demo files}
9
- gem.description = %Q{A library to read warsow demo files (.wd8, .wd9, .wd10, .wd11 files)}
8
+ gem.summary = %Q{A library to read warsow and q3 demo files}
9
+ gem.description = %Q{A library to read warsow demo files (.wd8, .wd9, .wd10, .wd11 files) and q3 demo files (*.dm68)}
10
10
  gem.email = "me@aekym.com"
11
11
  gem.homepage = "http://github.com/aekym/demo-reader"
12
12
  gem.authors = ["aekym"]
@@ -49,3 +49,4 @@ Rake::RDocTask.new do |rdoc|
49
49
  rdoc.rdoc_files.include('README*')
50
50
  rdoc.rdoc_files.include('lib/**/*.rb')
51
51
  end
52
+
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.1.0
data/demo-reader.gemspec CHANGED
@@ -5,13 +5,14 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{demo-reader}
8
- s.version = "0.0.2"
8
+ s.version = "0.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["aekym"]
12
- s.date = %q{2010-01-23}
13
- s.description = %q{A library to read warsow demo files (.wd8, .wd9, .wd10, .wd11 files)}
12
+ s.date = %q{2010-08-03}
13
+ s.description = %q{A library to read warsow demo files (.wd8, .wd9, .wd10, .wd11 files) and q3 demo files (*.dm68)}
14
14
  s.email = %q{me@aekym.com}
15
+ s.extensions = ["ext/dm68/extconf.rb"]
15
16
  s.extra_rdoc_files = [
16
17
  "LICENSE",
17
18
  "README.rdoc"
@@ -23,11 +24,31 @@ Gem::Specification.new do |s|
23
24
  "Rakefile",
24
25
  "VERSION",
25
26
  "demo-reader.gemspec",
27
+ "ext/dm68/README.txt",
28
+ "ext/dm68/common.c",
29
+ "ext/dm68/common.h",
30
+ "ext/dm68/dm68.c",
31
+ "ext/dm68/dump.c",
32
+ "ext/dm68/extconf.rb",
33
+ "ext/dm68/huff.c",
34
+ "ext/dm68/huff.h",
35
+ "ext/dm68/main.c",
36
+ "ext/dm68/main.h",
37
+ "ext/dm68/msg.c",
38
+ "ext/dm68/msg.h",
39
+ "ext/dm68/parse.c",
26
40
  "lib/demo-reader.rb",
41
+ "lib/demo_reader_defrag.rb",
27
42
  "lib/demo_reader_warsow.rb",
43
+ "test/demo_reader_defrag_dm_68_cpm_test.rb",
44
+ "test/demo_reader_defrag_dm_68_vq3_test.rb",
28
45
  "test/demo_reader_test.rb",
29
46
  "test/demo_reader_warsow_wd10_race_test.rb",
30
47
  "test/demo_reader_warsow_wd11_race_test.rb",
48
+ "test/fixtures/defrag/dm_68/cpm/pornchronostar_mdf.cpm_00.49.216_tyaz.germany.dm_68",
49
+ "test/fixtures/defrag/dm_68/cpm/puremotion_df.cpm_00.10.600_eS-Rody.russia.dm_68",
50
+ "test/fixtures/defrag/dm_68/vq3/runkull2_df.vq3_01.05.904_XunderBIRD.Germany.dm_68",
51
+ "test/fixtures/defrag/dm_68/vq3/un-dead029_df.vq3_00.16.912_uN-DeaD!WiNTeR.ru.dm_68",
31
52
  "test/fixtures/warsow/wd10/racesow_0.42.b2/dinirun2_racesow_0.42.b2.wd10",
32
53
  "test/fixtures/warsow/wd10/racesow_local/boris.wd10",
33
54
  "test/fixtures/warsow/wd10/racesow_local/die11.7.wd10",
@@ -53,10 +74,12 @@ Gem::Specification.new do |s|
53
74
  s.homepage = %q{http://github.com/aekym/demo-reader}
54
75
  s.rdoc_options = ["--charset=UTF-8"]
55
76
  s.require_paths = ["lib"]
56
- s.rubygems_version = %q{1.3.5}
57
- s.summary = %q{A library to read warsow demo files}
77
+ s.rubygems_version = %q{1.3.7}
78
+ s.summary = %q{A library to read warsow and q3 demo files}
58
79
  s.test_files = [
59
- "test/demo_reader_test.rb",
80
+ "test/demo_reader_defrag_dm_68_cpm_test.rb",
81
+ "test/demo_reader_defrag_dm_68_vq3_test.rb",
82
+ "test/demo_reader_test.rb",
60
83
  "test/demo_reader_warsow_wd10_race_test.rb",
61
84
  "test/demo_reader_warsow_wd11_race_test.rb",
62
85
  "test/helper.rb"
@@ -66,7 +89,7 @@ Gem::Specification.new do |s|
66
89
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
67
90
  s.specification_version = 3
68
91
 
69
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
92
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
70
93
  else
71
94
  end
72
95
  else
@@ -0,0 +1,14 @@
1
+ =================================================
2
+ Quake III *.dm_6? Demo Specifications
3
+
4
+ Copyright (C) 2003 Andrey '[SkulleR]' Nazarov
5
+ Based on Argus and Quake II source code
6
+ Also contains some stuff from Q3A SDK
7
+
8
+ Argus is Copyright (C) 2000 Martin Otten
9
+ Quake II and Quake III are Copyright (C) 1997-2001 ID Software, Inc
10
+ =================================================
11
+
12
+ dm_68 is an example application that parses *.dm_66, *.dm_67 or *.dm_68 demo files and dumps infostrings, server commands and obituaries. Source code included (under GPL).
13
+
14
+ Enjoy!
data/ext/dm68/common.c ADDED
@@ -0,0 +1,797 @@
1
+ // Copyright (C) 1999-2000 Id Software, Inc.
2
+ //
3
+ // q_shared.c -- stateless support routines that are included in each code dll
4
+ #include "common.h"
5
+
6
+ /*
7
+ =============
8
+ Q_strncpyz
9
+
10
+ Safe strncpy that ensures a trailing zero
11
+ =============
12
+ */
13
+ void Q_strncpyz( char *dest, const char *src, int destsize ) {
14
+ // bk001129 - also NULL dest
15
+ if ( !dest ) {
16
+ Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" );
17
+ }
18
+ if ( !src ) {
19
+ Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
20
+ }
21
+ if ( destsize < 1 ) {
22
+ Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
23
+ }
24
+
25
+ strncpy( dest, src, destsize-1 );
26
+ dest[destsize-1] = 0;
27
+ }
28
+
29
+ int Q_stricmpn (const char *s1, const char *s2, int n) {
30
+ int c1, c2;
31
+
32
+ // bk001129 - moved in 1.17 fix not in id codebase
33
+ if ( s1 == NULL ) {
34
+ if ( s2 == NULL )
35
+ return 0;
36
+ else
37
+ return -1;
38
+ }
39
+ else if ( s2==NULL )
40
+ return 1;
41
+
42
+
43
+
44
+ do {
45
+ c1 = *s1++;
46
+ c2 = *s2++;
47
+
48
+ if (!n--) {
49
+ return 0; // strings are equal until end point
50
+ }
51
+
52
+ if (c1 != c2) {
53
+ if (c1 >= 'a' && c1 <= 'z') {
54
+ c1 -= ('a' - 'A');
55
+ }
56
+ if (c2 >= 'a' && c2 <= 'z') {
57
+ c2 -= ('a' - 'A');
58
+ }
59
+ if (c1 != c2) {
60
+ return c1 < c2 ? -1 : 1;
61
+ }
62
+ }
63
+ } while (c1);
64
+
65
+ return 0; // strings are equal
66
+ }
67
+
68
+ int Q_strncmp (const char *s1, const char *s2, int n) {
69
+ int c1, c2;
70
+
71
+ do {
72
+ c1 = *s1++;
73
+ c2 = *s2++;
74
+
75
+ if (!n--) {
76
+ return 0; // strings are equal until end point
77
+ }
78
+
79
+ if (c1 != c2) {
80
+ return c1 < c2 ? -1 : 1;
81
+ }
82
+ } while (c1);
83
+
84
+ return 0; // strings are equal
85
+ }
86
+
87
+ int Q_stricmp (const char *s1, const char *s2) {
88
+ return (s1 && s2) ? Q_stricmpn (s1, s2, 99999) : -1;
89
+ }
90
+
91
+
92
+ // never goes past bounds or leaves without a terminating 0
93
+ void Q_strcat( char *dest, int size, const char *src ) {
94
+ int l1;
95
+
96
+ l1 = strlen( dest );
97
+ if ( l1 >= size ) {
98
+ Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
99
+ }
100
+ Q_strncpyz( dest + l1, src, size - l1 );
101
+ }
102
+
103
+
104
+ void Com_sprintf( char *dest, int size, const char *fmt, ...) {
105
+ int len;
106
+ va_list argptr;
107
+ char bigbuffer[32000]; // big, but small enough to fit in PPC stack
108
+
109
+ va_start (argptr,fmt);
110
+ len = vsprintf (bigbuffer,fmt,argptr);
111
+ va_end (argptr);
112
+ if ( len >= sizeof( bigbuffer ) ) {
113
+ Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
114
+ }
115
+ if (len >= size) {
116
+ Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
117
+ #ifdef _DEBUG
118
+ __asm {
119
+ int 3;
120
+ }
121
+ #endif
122
+ }
123
+ Q_strncpyz (dest, bigbuffer, size );
124
+ }
125
+
126
+
127
+ /*
128
+ ============
129
+ va
130
+
131
+ does a varargs printf into a temp buffer, so I don't need to have
132
+ varargs versions of all text functions.
133
+ FIXME: make this buffer size safe someday
134
+ ============
135
+ */
136
+ char *va( char *format, ... ) {
137
+ va_list argptr;
138
+ static char string[2][32000]; // in case va is called by nested functions
139
+ static int index = 0;
140
+ char *buf;
141
+
142
+ buf = string[index & 1];
143
+ index++;
144
+
145
+ va_start (argptr, format);
146
+ vsprintf (buf, format,argptr);
147
+ va_end (argptr);
148
+
149
+ return buf;
150
+ }
151
+
152
+
153
+ /*
154
+ =====================================================================
155
+
156
+ INFO STRINGS
157
+
158
+ =====================================================================
159
+ */
160
+
161
+ /*
162
+ ===============
163
+ Info_ValueForKey
164
+
165
+ Searches the string for the given
166
+ key and returns the associated value, or an empty string.
167
+ FIXME: overflow check?
168
+ ===============
169
+ */
170
+ char *Info_ValueForKey( const char *s, const char *key ) {
171
+ char pkey[BIG_INFO_KEY];
172
+ static char value[2][BIG_INFO_VALUE]; // use two buffers so compares
173
+ // work without stomping on each other
174
+ static int valueindex = 0;
175
+ char *o;
176
+
177
+ if ( !s || !key ) {
178
+ return "";
179
+ }
180
+
181
+ if ( strlen( s ) >= BIG_INFO_STRING ) {
182
+ Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
183
+ }
184
+
185
+ valueindex ^= 1;
186
+ if (*s == '\\')
187
+ s++;
188
+ while (1)
189
+ {
190
+ o = pkey;
191
+ while (*s != '\\')
192
+ {
193
+ if (!*s)
194
+ return "";
195
+ *o++ = *s++;
196
+ }
197
+ *o = 0;
198
+ s++;
199
+
200
+ o = value[valueindex];
201
+
202
+ while (*s != '\\' && *s)
203
+ {
204
+ *o++ = *s++;
205
+ }
206
+ *o = 0;
207
+
208
+ if (!Q_stricmp (key, pkey) )
209
+ return value[valueindex];
210
+
211
+ if (!*s)
212
+ break;
213
+ s++;
214
+ }
215
+
216
+ return "";
217
+ }
218
+
219
+
220
+ /*
221
+ ===================
222
+ Info_NextPair
223
+
224
+ Used to itterate through all the key/value pairs in an info string
225
+ ===================
226
+ */
227
+ void Info_NextPair( const char **head, char *key, char *value ) {
228
+ char *o;
229
+ const char *s;
230
+
231
+ s = *head;
232
+
233
+ if ( *s == '\\' ) {
234
+ s++;
235
+ }
236
+ key[0] = 0;
237
+ value[0] = 0;
238
+
239
+ o = key;
240
+ while ( *s != '\\' ) {
241
+ if ( !*s ) {
242
+ *o = 0;
243
+ *head = s;
244
+ return;
245
+ }
246
+ *o++ = *s++;
247
+ }
248
+ *o = 0;
249
+ s++;
250
+
251
+ o = value;
252
+ while ( *s != '\\' && *s ) {
253
+ *o++ = *s++;
254
+ }
255
+ *o = 0;
256
+
257
+ *head = s;
258
+ }
259
+
260
+
261
+ /*
262
+ ===================
263
+ Info_RemoveKey
264
+ ===================
265
+ */
266
+ void Info_RemoveKey( char *s, const char *key ) {
267
+ char *start;
268
+ char pkey[MAX_INFO_KEY];
269
+ char value[MAX_INFO_VALUE];
270
+ char *o;
271
+
272
+ if ( strlen( s ) >= MAX_INFO_STRING ) {
273
+ Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
274
+ }
275
+
276
+ if (strchr (key, '\\')) {
277
+ return;
278
+ }
279
+
280
+ while (1)
281
+ {
282
+ start = s;
283
+ if (*s == '\\')
284
+ s++;
285
+ o = pkey;
286
+ while (*s != '\\')
287
+ {
288
+ if (!*s)
289
+ return;
290
+ *o++ = *s++;
291
+ }
292
+ *o = 0;
293
+ s++;
294
+
295
+ o = value;
296
+ while (*s != '\\' && *s)
297
+ {
298
+ if (!*s)
299
+ return;
300
+ *o++ = *s++;
301
+ }
302
+ *o = 0;
303
+
304
+ if (!strcmp (key, pkey) )
305
+ {
306
+ strcpy (start, s); // remove this part
307
+ return;
308
+ }
309
+
310
+ if (!*s)
311
+ return;
312
+ }
313
+
314
+ }
315
+
316
+ /*
317
+ ===================
318
+ Info_RemoveKey_Big
319
+ ===================
320
+ */
321
+ void Info_RemoveKey_Big( char *s, const char *key ) {
322
+ char *start;
323
+ char pkey[BIG_INFO_KEY];
324
+ char value[BIG_INFO_VALUE];
325
+ char *o;
326
+
327
+ if ( strlen( s ) >= BIG_INFO_STRING ) {
328
+ Com_Error( ERR_DROP, "Info_RemoveKey_Big: oversize infostring" );
329
+ }
330
+
331
+ if (strchr (key, '\\')) {
332
+ return;
333
+ }
334
+
335
+ while (1)
336
+ {
337
+ start = s;
338
+ if (*s == '\\')
339
+ s++;
340
+ o = pkey;
341
+ while (*s != '\\')
342
+ {
343
+ if (!*s)
344
+ return;
345
+ *o++ = *s++;
346
+ }
347
+ *o = 0;
348
+ s++;
349
+
350
+ o = value;
351
+ while (*s != '\\' && *s)
352
+ {
353
+ if (!*s)
354
+ return;
355
+ *o++ = *s++;
356
+ }
357
+ *o = 0;
358
+
359
+ if (!strcmp (key, pkey) )
360
+ {
361
+ strcpy (start, s); // remove this part
362
+ return;
363
+ }
364
+
365
+ if (!*s)
366
+ return;
367
+ }
368
+
369
+ }
370
+
371
+
372
+
373
+
374
+ /*
375
+ ==================
376
+ Info_Validate
377
+
378
+ Some characters are illegal in info strings because they
379
+ can mess up the server's parsing
380
+ ==================
381
+ */
382
+ qboolean Info_Validate( const char *s ) {
383
+ if ( strchr( s, '\"' ) ) {
384
+ return qfalse;
385
+ }
386
+ if ( strchr( s, ';' ) ) {
387
+ return qfalse;
388
+ }
389
+ return qtrue;
390
+ }
391
+
392
+ /*
393
+ ==================
394
+ Info_SetValueForKey
395
+
396
+ Changes or adds a key/value pair
397
+ ==================
398
+ */
399
+ void Info_SetValueForKey( char *s, const char *key, const char *value ) {
400
+ char newi[MAX_INFO_STRING];
401
+
402
+ if ( strlen( s ) >= MAX_INFO_STRING ) {
403
+ Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
404
+ }
405
+
406
+ if (strchr (key, '\\') || strchr (value, '\\'))
407
+ {
408
+ Com_Printf ("Can't use keys or values with a \\\n");
409
+ return;
410
+ }
411
+
412
+ if (strchr (key, ';') || strchr (value, ';'))
413
+ {
414
+ Com_Printf ("Can't use keys or values with a semicolon\n");
415
+ return;
416
+ }
417
+
418
+ if (strchr (key, '\"') || strchr (value, '\"'))
419
+ {
420
+ Com_Printf ("Can't use keys or values with a \"\n");
421
+ return;
422
+ }
423
+
424
+ Info_RemoveKey (s, key);
425
+ if (!value || !strlen(value))
426
+ return;
427
+
428
+ Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
429
+
430
+ if (strlen(newi) + strlen(s) > MAX_INFO_STRING)
431
+ {
432
+ Com_Printf ("Info string length exceeded\n");
433
+ return;
434
+ }
435
+
436
+ strcat (newi, s);
437
+ strcpy (s, newi);
438
+ }
439
+
440
+ /*
441
+ ==================
442
+ Info_SetValueForKey_Big
443
+
444
+ Changes or adds a key/value pair
445
+ ==================
446
+ */
447
+ void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
448
+ char newi[BIG_INFO_STRING];
449
+
450
+ if ( strlen( s ) >= BIG_INFO_STRING ) {
451
+ Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
452
+ }
453
+
454
+ if (strchr (key, '\\') || strchr (value, '\\'))
455
+ {
456
+ Com_Printf ("Can't use keys or values with a \\\n");
457
+ return;
458
+ }
459
+
460
+ if (strchr (key, ';') || strchr (value, ';'))
461
+ {
462
+ Com_Printf ("Can't use keys or values with a semicolon\n");
463
+ return;
464
+ }
465
+
466
+ if (strchr (key, '\"') || strchr (value, '\"'))
467
+ {
468
+ Com_Printf ("Can't use keys or values with a \"\n");
469
+ return;
470
+ }
471
+
472
+ Info_RemoveKey_Big (s, key);
473
+ if (!value || !strlen(value))
474
+ return;
475
+
476
+ Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
477
+
478
+ if (strlen(newi) + strlen(s) > BIG_INFO_STRING)
479
+ {
480
+ Com_Printf ("BIG Info string length exceeded\n");
481
+ return;
482
+ }
483
+
484
+ strcat (s, newi);
485
+ }
486
+
487
+
488
+
489
+
490
+ //====================================================================
491
+
492
+ /*
493
+ ============
494
+ Com_Error
495
+ ============
496
+ */
497
+ void Com_Error( errorParm_t level, const char *error, ... ) {
498
+ va_list argptr;
499
+ char buffer[MAXPRINTMSG];
500
+
501
+ va_start( argptr, error );
502
+ vsprintf( buffer, error, argptr );
503
+ va_end( argptr );
504
+
505
+ printf( "*********************\n"
506
+ "ERROR: %s\n"
507
+ "*********************\n", buffer );
508
+ exit( EXIT_FAILURE );
509
+
510
+ }
511
+
512
+ /*
513
+ ============
514
+ Com_Printf
515
+ ============
516
+ */
517
+ void Com_Printf( const char *text, ... ) {
518
+ va_list argptr;
519
+ char buffer[MAXPRINTMSG];
520
+
521
+ va_start( argptr, text );
522
+ vsprintf( buffer, text, argptr );
523
+ va_end( argptr );
524
+
525
+ printf( "%s", buffer );
526
+ }
527
+
528
+ /*
529
+ =================
530
+ CopyString
531
+ =================
532
+ */
533
+ char *CopyString( const char *in ) {
534
+ char *out;
535
+
536
+ if( !in ) {
537
+ return NULL;
538
+ }
539
+
540
+ out = malloc( strlen( in ) + 1 );
541
+ strcpy( out, in );
542
+
543
+ return out;
544
+ }
545
+
546
+
547
+ /*
548
+ ==============
549
+ COM_Parse
550
+
551
+ Parse a token out of a string
552
+ ==============
553
+ */
554
+ char *COM_Parse (char **data_p)
555
+ {
556
+ int c;
557
+ int len;
558
+ char *data;
559
+ static char com_token[MAX_TOKEN_CHARS];
560
+
561
+ data = *data_p;
562
+ len = 0;
563
+ com_token[0] = 0;
564
+
565
+ if (!data)
566
+ {
567
+ *data_p = NULL;
568
+ return "";
569
+ }
570
+
571
+ // skip whitespace
572
+ skipwhite:
573
+ while ( (c = *data) <= ' ')
574
+ {
575
+ if (c == 0)
576
+ {
577
+ *data_p = NULL;
578
+ return "";
579
+ }
580
+ data++;
581
+ }
582
+
583
+ // skip // comments
584
+ if (c=='/' && data[1] == '/')
585
+ {
586
+ while (*data && *data != '\n')
587
+ data++;
588
+ goto skipwhite;
589
+ }
590
+
591
+ // handle quoted strings specially
592
+ if (c == '\"')
593
+ {
594
+ data++;
595
+ while (1)
596
+ {
597
+ c = *data++;
598
+ if (c=='\"' || !c)
599
+ {
600
+ com_token[len] = 0;
601
+ *data_p = data;
602
+ return com_token;
603
+ }
604
+ if (len < MAX_TOKEN_CHARS)
605
+ {
606
+ com_token[len] = c;
607
+ len++;
608
+ }
609
+ }
610
+ }
611
+
612
+ // parse a regular word
613
+ do
614
+ {
615
+ if (len < MAX_TOKEN_CHARS)
616
+ {
617
+ com_token[len] = c;
618
+ len++;
619
+ }
620
+ data++;
621
+ c = *data;
622
+ } while (c>32);
623
+
624
+ if (len == MAX_TOKEN_CHARS)
625
+ {
626
+ // Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
627
+ len = 0;
628
+ }
629
+ com_token[len] = 0;
630
+
631
+ *data_p = data;
632
+ return com_token;
633
+ }
634
+
635
+ static int cmd_argc;
636
+ static char *cmd_argv[MAX_STRING_TOKENS];
637
+ static char *cmd_null_string = "";
638
+ static char cmd_args[MAX_STRING_CHARS];
639
+
640
+ /*
641
+ ============
642
+ Cmd_Argc
643
+ ============
644
+ */
645
+ int Cmd_Argc (void)
646
+ {
647
+ return cmd_argc;
648
+ }
649
+
650
+ /*
651
+ ============
652
+ Cmd_Argv
653
+ ============
654
+ */
655
+ char *Cmd_Argv (int arg)
656
+ {
657
+ if ( (unsigned)arg >= cmd_argc )
658
+ return cmd_null_string;
659
+ return cmd_argv[arg];
660
+ }
661
+
662
+ /*
663
+ ============
664
+ Cmd_Args
665
+
666
+ Returns a single string containing argv(1) to argv(argc()-1)
667
+ ============
668
+ */
669
+ char *Cmd_Args (void)
670
+ {
671
+ return cmd_args;
672
+ }
673
+
674
+
675
+ /*
676
+ ============
677
+ Cmd_TokenizeString
678
+
679
+ Parses the given string into command line tokens.
680
+ $Cvars will be expanded unless they are in a quoted token
681
+ ============
682
+ */
683
+ void Cmd_TokenizeString (char *text)
684
+ {
685
+ int i;
686
+ char *com_token;
687
+
688
+ // clear the args from the last string
689
+ for (i=0 ; i<cmd_argc ; i++)
690
+ free (cmd_argv[i]);
691
+
692
+ cmd_argc = 0;
693
+ cmd_args[0] = 0;
694
+
695
+ if (!text)
696
+ return;
697
+
698
+ while (1)
699
+ {
700
+ // skip whitespace up to a /n
701
+ while (*text && *text <= ' ' && *text != '\n')
702
+ {
703
+ text++;
704
+ }
705
+
706
+ if (*text == '\n')
707
+ { // a newline seperates commands in the buffer
708
+ text++;
709
+ break;
710
+ }
711
+
712
+ if (!*text)
713
+ return;
714
+
715
+ // set cmd_args to everything after the first arg
716
+ if (cmd_argc == 1)
717
+ {
718
+ int l;
719
+
720
+ strcpy (cmd_args, text);
721
+
722
+ // strip off any trailing whitespace
723
+ l = strlen(cmd_args) - 1;
724
+ for ( ; l >= 0 ; l--)
725
+ if (cmd_args[l] <= ' ')
726
+ cmd_args[l] = 0;
727
+ else
728
+ break;
729
+ }
730
+
731
+ com_token = COM_Parse (&text);
732
+ if (!text)
733
+ return;
734
+
735
+ if (cmd_argc < MAX_STRING_TOKENS)
736
+ {
737
+ cmd_argv[cmd_argc] = malloc (strlen(com_token)+1);
738
+ strcpy (cmd_argv[cmd_argc], com_token);
739
+ cmd_argc++;
740
+ }
741
+ }
742
+
743
+ }
744
+
745
+
746
+ /*
747
+ ============
748
+ Info_Print
749
+ ============
750
+ */
751
+ void Info_Print( const char *s ) {
752
+ char key[MAXPRINTMSG];
753
+ char value[MAXPRINTMSG];
754
+ char *o;
755
+ int l;
756
+
757
+ if( *s == '\\' ) {
758
+ s++;
759
+ }
760
+
761
+ while( *s )
762
+ {
763
+ o = key;
764
+ while( *s && *s != '\\' ) // && o - key < MAXPRINTMSG )
765
+ {
766
+ *o++ = *s++;
767
+ }
768
+
769
+ l = o - key;
770
+ if( l < 20 ) {
771
+ memset( o, 0, 20-l );
772
+ key[20] = 0;
773
+ } else {
774
+ *o = 0;
775
+ }
776
+ append_result(" %s: ", key);
777
+
778
+ if( !*s ) {
779
+ Com_Printf( "MISSING VALUE\n" );
780
+ return;
781
+ }
782
+
783
+ o = value;
784
+ s++;
785
+ while( *s && *s != '\\' ) // && o - value < MAXPRINTMSG )
786
+ {
787
+ *o++ = *s++;
788
+ }
789
+ *o = 0;
790
+
791
+ if( *s ) {
792
+ s++;
793
+ }
794
+ append_result("\"%s\"\n", value);
795
+ }
796
+ }
797
+