8080#include <io.h>
8181#include <fcntl.h>
8282
83- #define fstat _fstat64
84- #define ftello _ftelli64
83+ #define fstat _fstat64
84+ #define ftello _ftelli64
85+ #define fseeko _fseeki64
8586typedef signed long long myoff_t ;
8687typedef struct __stat64 mystat_t ;
8788#else
@@ -101,6 +102,7 @@ static void Usage();
101102int debugLevel = 0 ;
102103BOOL addEquals = TRUE;
103104BOOL printHeaders = TRUE;
105+ BOOL useRDW = TRUE;
104106BOOL sqlMode = FALSE;
105107commonFields_t commonF = {0 };
106108
@@ -148,6 +150,9 @@ int main( int argc, char *argv[] )
148150
149151 char * inputFile = NULL ;
150152 FILE * fp ;
153+ char * b ;
154+ char * basename ;
155+ myoff_t currentOffset = 0 ;
151156 myoff_t totalFileSize = 0 ;
152157 mystat_t statbuf ;
153158 unsigned int totalRecords = 0 ;
@@ -160,6 +165,7 @@ int main( int argc, char *argv[] )
160165 char * p ;
161166 qwhs * pqwhs ;
162167 unsigned char correlid [16 ];
168+ int offsetCorrection ;
163169
164170 BOOL error = FALSE;
165171 BOOL knownSubType = TRUE;
@@ -195,7 +201,7 @@ int main( int argc, char *argv[] )
195201 /* Parse command-line parameters */
196202 /******************************************************************/
197203 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 )
199205 {
200206 switch (c )
201207 {
@@ -205,6 +211,16 @@ int main( int argc, char *argv[] )
205211 case 'd' :
206212 debugLevel = atoi (mqoptarg );
207213 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 ;
208224 case 'h' :
209225 for (i = 0 ;i < strlen (mqoptarg );i ++ )
210226 mqoptarg [i ] = toupper (mqoptarg [i ]);
@@ -272,84 +288,110 @@ int main( int argc, char *argv[] )
272288 printf ("Total File Size = %lld\n" ,totalFileSize );
273289
274290 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" );
275299
276300 /********************************************************************/
277301 /* Loop until we have no more data or enough records have been read */
278302 /********************************************************************/
303+ currentOffset = 0 ;
279304 pSMFRecord = (SMFRecord_t * )& dataBuf ;
280305 do
281306 {
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 )
310315 {
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 )
330344 {
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+ {
331365
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 );
335369
336- if (debugLevel >=3 )
337- printf (" NextLen = %d bytes \n" ,nextLength );
370+ if (debugLevel >=3 )
371+ printf (" NextLen = %d bytes \n" ,nextLength );
338372
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+ }
344378
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*/
348382
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 ;
349394 }
350-
351- if (debugLevel >=3 )
352- printf ("Read a full record of %d bytes \n" ,offset );
353395
354396 totalRecords ++ ;
355397
@@ -360,7 +402,11 @@ int main( int argc, char *argv[] )
360402 /*********************************************************************/
361403 recordType = pSMFRecord -> Header .SMFRECRTY ;
362404
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 );
364410 if (subTypesValid )
365411 recordSubType = conv16 (pSMFRecord -> Header .SMFRECSTY );
366412 else
@@ -442,9 +488,6 @@ int main( int argc, char *argv[] )
442488 hund );
443489 }
444490
445- if (debugLevel >= 2 )
446- printDEBUG ("FULL RECORD" ,dataBuf ,offset );
447-
448491 if (recordType == 116 || recordType == 115 )
449492 {
450493 /*******************************************************************/
@@ -509,12 +552,49 @@ int main( int argc, char *argv[] )
509552 /* into a local array, doing the endianness conversion on the way. */
510553 /* That makes it look a bit easier rather than than having convxxx */
511554 /* 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. */
512557 /*********************************************************************/
513- for (i = 0 ;i < sectionCount ;i ++ )
514558 {
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 );
518598 }
519599
520600
@@ -667,7 +747,7 @@ int main( int argc, char *argv[] )
667747 /* If nothing has been done with DNS in this interval, the
668748 record seems to be present but contain garbage.
669749 */
670- case 5 : if (triplet [i ].l == sizeof (qct_dns ))
750+ case 5 : if (triplet [i ].l == sizeof (qct_dns ))
671751 printQCTDNS ((qct_dns * )p );
672752 break ;
673753 default : break ;
@@ -853,7 +933,8 @@ FILE * fopenext(const char * basename, const char *ext, BOOL *newFile)
853933
854934 fseek (fp ,0 ,SEEK_END );
855935 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 */
857938
858939 if (pos == 0 ) /* Have we just created the file, even for "append" mode */
859940 * newFile = TRUE;
@@ -935,9 +1016,10 @@ static void Usage(void)
9351016{
9361017 printf ("Usage: mqsmfcsv [-o <output dir>] [-a] [ -d <level> ]\n" );
9371018 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" );
9391020 printf (" -a Append to files if they exist. Default is overwrite.\n" );
9401021 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" );
9411023 printf (" -h yes|no Print column headers for new output files. Default is yes.\n" );
9421024 printf (" -i <Input file> Default is to read from stdin.\n" );
9431025 printf (" -m <Max records> End after formatting M records. Default to process all.\n" );
0 commit comments