80
80
#include <io.h>
81
81
#include <fcntl.h>
82
82
83
- #define fstat _fstat64
84
- #define ftello _ftelli64
83
+ #define fstat _fstat64
84
+ #define ftello _ftelli64
85
+ #define fseeko _fseeki64
85
86
typedef signed long long myoff_t ;
86
87
typedef struct __stat64 mystat_t ;
87
88
#else
@@ -101,6 +102,7 @@ static void Usage();
101
102
int debugLevel = 0 ;
102
103
BOOL addEquals = TRUE;
103
104
BOOL printHeaders = TRUE;
105
+ BOOL useRDW = TRUE;
104
106
BOOL sqlMode = FALSE;
105
107
commonFields_t commonF = {0 };
106
108
@@ -148,6 +150,9 @@ int main( int argc, char *argv[] )
148
150
149
151
char * inputFile = NULL ;
150
152
FILE * fp ;
153
+ char * b ;
154
+ char * basename ;
155
+ myoff_t currentOffset = 0 ;
151
156
myoff_t totalFileSize = 0 ;
152
157
mystat_t statbuf ;
153
158
unsigned int totalRecords = 0 ;
@@ -160,6 +165,7 @@ int main( int argc, char *argv[] )
160
165
char * p ;
161
166
qwhs * pqwhs ;
162
167
unsigned char correlid [16 ];
168
+ int offsetCorrection ;
163
169
164
170
BOOL error = FALSE;
165
171
BOOL knownSubType = TRUE;
@@ -195,7 +201,7 @@ int main( int argc, char *argv[] )
195
201
/* Parse command-line parameters */
196
202
/******************************************************************/
197
203
printf ("MQ SMF CSV - Build %s %s\n" ,__DATE__ ,__TIME__ );
198
- while ((c = mqgetopt (argc , argv , "ad:h:i:m:o:rst:" )) != EOF )
204
+ while ((c = mqgetopt (argc , argv , "ad:f: h:i:m:o:rst:" )) != EOF )
199
205
{
200
206
switch (c )
201
207
{
@@ -205,6 +211,16 @@ int main( int argc, char *argv[] )
205
211
case 'd' :
206
212
debugLevel = atoi (mqoptarg );
207
213
break ;
214
+ case 'f' :
215
+ for (i = 0 ;i < strlen (mqoptarg );i ++ )
216
+ mqoptarg [i ] = toupper (mqoptarg [i ]);
217
+ if (!strcmp (mqoptarg ,"NORDW" ))
218
+ useRDW = FALSE;
219
+ else if (!strcmp (mqoptarg ,"RDW" ))
220
+ useRDW = TRUE;
221
+ else
222
+ error = TRUE;
223
+ break ;
208
224
case 'h' :
209
225
for (i = 0 ;i < strlen (mqoptarg );i ++ )
210
226
mqoptarg [i ] = toupper (mqoptarg [i ]);
@@ -272,84 +288,110 @@ int main( int argc, char *argv[] )
272
288
printf ("Total File Size = %lld\n" ,totalFileSize );
273
289
274
290
convInit (); /* Decide whether this is a big or little endian machine*/
291
+ b = strrchr (inputFile ,'/' );
292
+ if (!b )
293
+ b = strrchr (inputFile ,'\\' );
294
+ if (!b )
295
+ basename = inputFile ;
296
+ else
297
+ basename = b + 1 ;
298
+ printf ("Input file: %s. Format: %s.\n" ,basename , useRDW ?"RDW" :"Without RDW" );
275
299
276
300
/********************************************************************/
277
301
/* Loop until we have no more data or enough records have been read */
278
302
/********************************************************************/
303
+ currentOffset = 0 ;
279
304
pSMFRecord = (SMFRecord_t * )& dataBuf ;
280
305
do
281
306
{
282
- /********************************************************************/
283
- /* Start reading data and processing the MQ records */
284
- /* First, read the length of this file record (not necessarily the */
285
- /* same as the SMF record length). It comes from the first two */
286
- /* bytes of the Record Descriptor Word (RDW). */
287
- /********************************************************************/
288
-
289
- bytesRead = fread (& pSMFRecord -> Header .SMFLEN ,1 ,2 ,fp );
290
- if (bytesRead < 2 )
291
- continue ;
292
-
293
- /********************************************************************/
294
- /* The second half-word is the segment indicator. */
295
- /********************************************************************/
296
- fread (& pSMFRecord -> Header .SMFSEG ,1 ,2 ,fp );
297
-
298
- /********************************************************************/
299
- /* And then read the actual data, starting at the RECFLG field in */
300
- /* the structure. The amount of data to read is given by the length */
301
- /* minus the 4 bytes of the RDW. Check that we have read the right */
302
- /* amount. */
303
- /********************************************************************/
304
- nextLength = conv16 (pSMFRecord -> Header .SMFLEN ) - 4 ;
305
- if (debugLevel >=3 )
306
- printf (" NextLen = %d bytes \n" ,nextLength );
307
-
308
- bytesRead = fread (& pSMFRecord -> Header .SMFRECFLG , 1 , nextLength , fp );
309
- if (bytesRead != nextLength )
307
+ /**********************************************************************/
308
+ /* The mechanism for reading the file depends on whether the RDW */
309
+ /* field is available. If it is, we know how long to read for each */
310
+ /* record. If it is not, then we read the maximum length each time and*/
311
+ /* reset the pointer for the next read once we have parsed the record.*/
312
+ /**********************************************************************/
313
+ memset (dataBuf ,0 ,sizeof (dataBuf ));
314
+ if (useRDW )
310
315
{
311
- printf ("Error reading full record from input file\n" );
312
- goto mod_exit ;
313
- }
314
- offset = bytesRead + 4 ;
315
-
316
- /********************************************************************/
317
- /* If the segment indicator is non-zero, then we need to continue */
318
- /* reading the next record into the same buffer. There is no */
319
- /* SMF header on the subsequent segments, it's just raw data. So */
320
- /* we read the length of the next partial record, and its segment */
321
- /* value. Then the data itself. And loop until we get to */
322
- /* end-of-record indicator in the segment field. Regardless of */
323
- /* segmentation, no SMF record is meant to be >32768 bytes, so we */
324
- /* need to check that. Once again, ignore the RDW when working */
325
- /* out how much real data there is. */
326
- /********************************************************************/
327
- if (pSMFRecord -> Header .SMFSEG [0 ] != 0 )
328
- {
329
- do
316
+ /********************************************************************/
317
+ /* Start reading data and processing the MQ records */
318
+ /* First, read the length of this file record (not necessarily the */
319
+ /* same as the SMF record length). It comes from the first two */
320
+ /* bytes of the Record Descriptor Word (RDW). */
321
+ /********************************************************************/
322
+
323
+ bytesRead = fread (& pSMFRecord -> Header .SMFLEN ,1 ,2 ,fp );
324
+ if (bytesRead < 2 )
325
+ continue ;
326
+
327
+ /********************************************************************/
328
+ /* The second half-word is the segment indicator. */
329
+ /********************************************************************/
330
+ fread (& pSMFRecord -> Header .SMFSEG ,1 ,2 ,fp );
331
+
332
+ /********************************************************************/
333
+ /* And then read the actual data, starting at the RECFLG field in */
334
+ /* the structure. The amount of data to read is given by the length */
335
+ /* minus the 4 bytes of the RDW. Check that we have read the right */
336
+ /* amount. */
337
+ /********************************************************************/
338
+ nextLength = conv16 (pSMFRecord -> Header .SMFLEN ) - 4 ;
339
+ if (debugLevel >=3 )
340
+ printf (" NextLen = %d bytes \n" ,nextLength );
341
+
342
+ bytesRead = fread (& pSMFRecord -> Header .SMFRECFLG , 1 , nextLength , fp );
343
+ if (bytesRead != nextLength )
330
344
{
345
+ printf ("Error reading full record from input file\n" );
346
+ goto mod_exit ;
347
+ }
348
+ offset = bytesRead + 4 ;
349
+
350
+ /********************************************************************/
351
+ /* If the segment indicator is non-zero, then we need to continue */
352
+ /* reading the next record into the same buffer. There is no */
353
+ /* SMF header on the subsequent segments, it's just raw data. So */
354
+ /* we read the length of the next partial record, and its segment */
355
+ /* value. Then the data itself. And loop until we get to */
356
+ /* end-of-record indicator in the segment field. Regardless of */
357
+ /* segmentation, no SMF record is meant to be >32768 bytes, so we */
358
+ /* need to check that. Once again, ignore the RDW when working */
359
+ /* out how much real data there is. */
360
+ /********************************************************************/
361
+ if (pSMFRecord -> Header .SMFSEG [0 ] != 0 )
362
+ {
363
+ do
364
+ {
331
365
332
- fread (& nextLength ,1 ,2 ,fp );
333
- nextLength = conv16 (nextLength );
334
- fread (& pSMFRecord -> Header .SMFSEG ,1 ,2 ,fp );
366
+ fread (& nextLength ,1 ,2 ,fp );
367
+ nextLength = conv16 (nextLength );
368
+ fread (& pSMFRecord -> Header .SMFSEG ,1 ,2 ,fp );
335
369
336
- if (debugLevel >=3 )
337
- printf (" NextLen = %d bytes \n" ,nextLength );
370
+ if (debugLevel >=3 )
371
+ printf (" NextLen = %d bytes \n" ,nextLength );
338
372
339
- if (offset + nextLength > sizeof (dataBuf ))
340
- {
341
- printf ("SMF record appears to be too large for buffer\n" );
342
- goto mod_exit ;
343
- }
373
+ if (offset + nextLength > sizeof (dataBuf ))
374
+ {
375
+ printf ("SMF record appears to be too large for buffer\n" );
376
+ goto mod_exit ;
377
+ }
344
378
345
- bytesRead = fread (& dataBuf [offset ], 1 , nextLength - 4 , fp );
346
- offset += bytesRead ;
347
- } while (pSMFRecord -> Header .SMFSEG [0 ] != 0x02 );/* end of record indicator*/
379
+ bytesRead = fread (& dataBuf [offset ], 1 , nextLength - 4 , fp );
380
+ offset += bytesRead ;
381
+ } while (pSMFRecord -> Header .SMFSEG [0 ] != 0x02 );/* end of record indicator*/
348
382
383
+ }
384
+ offsetCorrection = 0 ;
385
+ }
386
+ else
387
+ {
388
+ fseeko (fp ,currentOffset ,SEEK_SET );
389
+ bytesRead = fread (& pSMFRecord -> Header .SMFRECFLG ,1 ,32768 ,fp );
390
+ offset = bytesRead ;
391
+ offsetCorrection = 4 ;
392
+ if (bytesRead <= 0 )
393
+ break ;
349
394
}
350
-
351
- if (debugLevel >=3 )
352
- printf ("Read a full record of %d bytes \n" ,offset );
353
395
354
396
totalRecords ++ ;
355
397
@@ -360,7 +402,11 @@ int main( int argc, char *argv[] )
360
402
/*********************************************************************/
361
403
recordType = pSMFRecord -> Header .SMFRECRTY ;
362
404
363
- subTypesValid = (pSMFRecord -> Header .SMFRECFLG & 0x02 );
405
+ /*********************************************************************/
406
+ /* zOS refers to bits from the left - reversed from what you might */
407
+ /* expect. So "bit 1" indicating subtypes is '0100 0000' == 0x40 */
408
+ /*********************************************************************/
409
+ subTypesValid = ((pSMFRecord -> Header .SMFRECFLG & 0x40 ) == 0x40 );
364
410
if (subTypesValid )
365
411
recordSubType = conv16 (pSMFRecord -> Header .SMFRECSTY );
366
412
else
@@ -442,9 +488,6 @@ int main( int argc, char *argv[] )
442
488
hund );
443
489
}
444
490
445
- if (debugLevel >= 2 )
446
- printDEBUG ("FULL RECORD" ,dataBuf ,offset );
447
-
448
491
if (recordType == 116 || recordType == 115 )
449
492
{
450
493
/*******************************************************************/
@@ -509,12 +552,49 @@ int main( int argc, char *argv[] )
509
552
/* into a local array, doing the endianness conversion on the way. */
510
553
/* That makes it look a bit easier rather than than having convxxx */
511
554
/* function calls everywhere else. */
555
+ /* We do not need to correct for the offset in non-RDW files as that */
556
+ /* space is still allocated at the front of the buffer. */
512
557
/*********************************************************************/
513
- for (i = 0 ;i < sectionCount ;i ++ )
514
558
{
515
- triplet [i ].offset = conv32 (pSMFRecord -> s [i ].offset );
516
- triplet [i ].l = conv16 (pSMFRecord -> s [i ].l );
517
- triplet [i ].n = conv16 (pSMFRecord -> s [i ].n );
559
+ int highestOffset = 0 ;
560
+ int h = -1 ;
561
+ int recLength = 0 ;
562
+ memset (triplet ,0 ,sizeof (triplet ));
563
+ for (i = 0 ;i < sectionCount ;i ++ )
564
+ {
565
+ triplet [i ].offset = conv32 (pSMFRecord -> s [i ].offset );
566
+ triplet [i ].l = conv16 (pSMFRecord -> s [i ].l );
567
+ triplet [i ].n = conv16 (pSMFRecord -> s [i ].n );
568
+ if (triplet [i ].offset > highestOffset &&
569
+ triplet [i ].offset > 0 &&
570
+ triplet [i ].n > 0 )
571
+ {
572
+ highestOffset = triplet [i ].offset ;
573
+ h = i ;
574
+ }
575
+ }
576
+ if (h < 0 ) {
577
+ if (subTypesValid )
578
+ {
579
+ recLength = sizeof (SMFHeader_t ) - offsetCorrection ;
580
+ }
581
+ else
582
+ {
583
+ recLength = offsetof(SMFHeader_t ,SMFRECSSID ) - offsetCorrection ;
584
+ }
585
+ } else {
586
+ recLength = triplet [h ].offset + triplet [h ].l * triplet [h ].n - offsetCorrection ;
587
+ }
588
+ currentOffset += recLength ;
589
+
590
+ if (debugLevel >= 3 )
591
+ {
592
+ printf ("Highest triple = %d RecLength = %d New Offset = %lld\n" ,
593
+ h , recLength ,currentOffset );
594
+ }
595
+
596
+ if (debugLevel >= 2 )
597
+ printDEBUG ("FULL RECORD" ,dataBuf + offsetCorrection ,recLength );
518
598
}
519
599
520
600
@@ -667,7 +747,7 @@ int main( int argc, char *argv[] )
667
747
/* If nothing has been done with DNS in this interval, the
668
748
record seems to be present but contain garbage.
669
749
*/
670
- case 5 : if (triplet [i ].l == sizeof (qct_dns ))
750
+ case 5 : if (triplet [i ].l == sizeof (qct_dns ))
671
751
printQCTDNS ((qct_dns * )p );
672
752
break ;
673
753
default : break ;
@@ -853,7 +933,8 @@ FILE * fopenext(const char * basename, const char *ext, BOOL *newFile)
853
933
854
934
fseek (fp ,0 ,SEEK_END );
855
935
pos = ftell (fp );
856
- /*setbuf(fp,0); */ /* useful to have this line when debugging */
936
+ if (debugLevel >= 0 )
937
+ setbuf (fp ,0 ); /* useful to have this line when debugging */
857
938
858
939
if (pos == 0 ) /* Have we just created the file, even for "append" mode */
859
940
* newFile = TRUE;
@@ -935,9 +1016,10 @@ static void Usage(void)
935
1016
{
936
1017
printf ("Usage: mqsmfcsv [-o <output dir>] [-a] [ -d <level> ]\n" );
937
1018
printf (" [-h yes|no] [ -i <input file> [-m <max records>]\n" );
938
- printf (" [-r ] [-t <ticker>]\n" );
1019
+ printf (" [-f RDW | NORDW] [- r ] [-t <ticker>]\n" );
939
1020
printf (" -a Append to files if they exist. Default is overwrite.\n" );
940
1021
printf (" -d <Level> Debug by dumping binary records (Level = 1 or 2).\n" );
1022
+ printf (" -f RDW | NORDW Input file format. Default is RDW.\n" );
941
1023
printf (" -h yes|no Print column headers for new output files. Default is yes.\n" );
942
1024
printf (" -i <Input file> Default is to read from stdin.\n" );
943
1025
printf (" -m <Max records> End after formatting M records. Default to process all.\n" );
0 commit comments