/* || ---------------------------------------------------------------------------- || || SLLIB.C (c) Copyright Leland Lucius, 2000-2006 || Released under terms of the Q Public License. || || Library for managing Standard Label tapes. || || ---------------------------------------------------------------------------- */ #include "hstdinc.h" #define _SLLIB_C_ #define _HTAPE_DLL_ #include "hercules.h" #include "sllib.h" /* || Local constant data */ /* || Label IDs in EBCDIC */ static const char *sl_elabs[] = { "\x00\x00\x00", /* Placeholder */ "\xE5\xD6\xD3", /* EBCDIC characters "VOL" */ "\xC8\xC4\xD9", /* EBCDIC characters "HDR" */ "\xE4\xC8\xD3", /* EBCDIC characters "UHL" */ "\xC5\xD6\xC6", /* EBCDIC characters "EOF" */ "\xC5\xD6\xE5", /* EBCDIC characters "EOV" */ "\xE4\xE3\xD3", /* EBCDIC characters "UTL" */ }; #define SL_ELABS_MAX ( sizeof( sl_elabs ) / sizeof( sl_elabs[ 0 ] ) ) /* || Label IDs in ASCII */ static const char *sl_alabs[] = { "\x00\x00\x00", /* Placeholder */ "\x56\x4f\x4c", /* ASCII characters "VOL" */ "\x48\x44\x52", /* ASCII characters "HDR" */ "\x55\x48\x4c", /* ASCII characters "UHL" */ "\x45\x4f\x46", /* ASCII characters "EOF" */ "\x45\x4f\x56", /* ASCII characters "EOV" */ "\x55\x54\x4c", /* ASCII characters "UTL" */ }; #define SL_ALABS_MAX ( sizeof( sl_alabs ) / sizeof( sl_alabs[ 0 ] ) ) /* || Minimum and maximum ranges for each label type */ static const struct { int min; int max; } sl_ranges[] = { { 0, 0 }, /* Placeholder */ { 1, 1 }, /* ASCII characters "VOL" */ { 1, 2 }, /* ASCII characters "HDR" */ { 1, 8 }, /* ASCII characters "UHL" */ { 1, 2 }, /* ASCII characters "EOF" */ { 1, 2 }, /* ASCII characters "EOV" */ { 1, 8 }, /* ASCII characters "UTL" */ }; /* || Text descriptions for errors */ static const char *sl_errstr[] = { "No error", "Block size out of range", "Data set sequence out of range", "Invalid expiration date", "Missing or invalid job name", "Missing or invalid record length", "Owner string invalid or too long", "Missing or invalid record format", "Missing or invalid step name", "Invalid recording technique", "Volume sequence out of range", "Missing or invalid volume serial", "User data too long", "Label type invalid", "Label number invalid", "Invalid error code", }; #define SL_ERRSTR_MAX ( sizeof( sl_errstr) / sizeof( sl_errstr[ 0 ] ) ) /* || Valid characters for a Standard Label || (from: SC26-4565-01 "3.4 Label Definition and Organization") */ static const char sl_cset[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !\"%&'()*+,-./:;<=>?" }; /* || Valid record formats */ static const struct { char *recfm; char f; char b; char c; } valfm[] = { { "U", 'U', ' ', ' ' }, { "UA", 'U', ' ', 'A' }, { "UM", 'U', ' ', 'M' }, { "F", 'F', ' ', ' ' }, { "FA", 'F', ' ', 'A' }, { "FM", 'F', ' ', 'M' }, { "FB", 'F', 'B', ' ' }, { "FBA", 'F', 'B', 'A' }, { "FBM", 'F', 'B', 'M' }, { "FS", 'F', 'S', ' ' }, { "FSA", 'F', 'S', 'A' }, { "FSM", 'F', 'S', 'M' }, { "FBS", 'F', 'R', ' ' }, { "FBSA", 'F', 'R', 'A' }, { "FBSM", 'F', 'R', 'M' }, { "V", 'V', ' ', ' ' }, { "VA", 'V', ' ', 'A' }, { "VM", 'V', ' ', 'M' }, { "VB", 'V', 'B', ' ' }, { "VBA", 'V', 'B', 'A' }, { "VBM", 'V', 'B', 'M' }, { "VS", 'V', 'S', ' ' }, { "VSA", 'V', 'S', 'A' }, { "VSM", 'V', 'S', 'M' }, { "VBS", 'V', 'R', ' ' }, { "VBSA", 'V', 'R', 'A' }, { "VBSM", 'V', 'R', 'M' }, }; #define VALFMCNT ( sizeof( valfm ) / sizeof( valfm[ 0 ] ) ) /*==DOC== NAME sl_atoe - Translate input buffer from ASCII to EBCDIC SYNOPSIS #include "sllib.h" char *sl_atoe( void *dbuf, void *sbuf, int slen ) DESCRIPTION Translates, and optionally copies, "sbuf" from ASCII to EBCDIC for "slen" characters. If "dbuf" is specified as NULL, then "sbuf" is translated in place. Otherwise, "dbuf" specifies the buffer where the translated characters will be stored. RETURN VALUE The return value will be either "sbuf" or "dbuf" depending on whether "dbuf" was passed as NULL. EXAMPLE // // Convert buffer // #include "sllib.h" unsigned char ascii[] = "\x48\x65\x72\x63\x75\x6c\x65\x73\x2e\x2e\x2e" "\x20\x52\x65\x73\x75\x72\x72\x65\x63\x74\x69" "\x6e\x67\x20\x74\x68\x65\x20\x64\x69\x6e\x6f" "\x73\x61\x75\x72\x73\x21"; unsigned char ebcdic[ sizeof( ascii ) ]; int main( int argc, char *argv[] ) { int len; int i; len = strlen( ascii ); sl_atoe( ebcdic, ascii, len ); printf( "ascii string: " ); for( i = 0 ; i < len ; i++ ) { printf( "%02x ", ascii[ i ] ); } printf( "\nebcdic string: " ); for( i = 0 ; i < len ; i++ ) { printf( "%02x ", ebcdic[ i ] ); } printf( "\n" ); return( 0 ); } SEE ALSO ==DOC==*/ DLL_EXPORT char * sl_atoe( void *dbuf, void *sbuf, int slen ) { unsigned char *sptr; unsigned char *dptr; sptr = sbuf; dptr = dbuf; if( dptr == NULL ) { dptr = sptr; } while( slen > 0 ) { slen--; dptr[ slen ] = host_to_guest( sptr[ slen ] ); } return( (char *)dptr ); } /*==DOC== NAME sl_etoa - Translate input buffer from EBCDIC to ASCII SYNOPSIS #include "sllib.h" char *sl_etoa( void *dbuf, void *sbuf, int slen ) DESCRIPTION Translates, and optionally copies, "sbuf" from EBCDIC to ASCII for "slen" characters. If "dbuf" is specified as NULL, then "sbuf" is translated in place. Otherwise, "dbuf" specifies the buffer where the translated characters will be stored. RETURN VALUE The return value will be either "sbuf" or "dbuf" depending on whether "dbuf" was passed as NULL. EXAMPLE // // Convert buffer // #include "sllib.h" unsigned char ebcdic[] = "\xc8\x85\x99\x83\xa4\x93\x85\xa2\x4b\x4b\x4b" "\x40\xd9\x85\xa2\xa4\x99\x99\x85\x83\xa3\x89" "\x95\x87\x40\xa3\x88\x85\x40\x84\x89\x95\x96" "\xa2\x81\xa4\x99\xa2\x5a"; unsigned char ascii[ sizeof( ebcdic ) ]; int main( int argc, char *argv[] ) { int len; int i; len = strlen( ebcdic ); sl_etoa( ascii, ebcdic, len ); printf( "ebcdic string: " ); for( i = 0 ; i < len ; i++ ) { printf( "%02x ", ebcdic[ i ] ); } printf( "\nascii string: " ); for( i = 0 ; i < len ; i++ ) { printf( "%02x ", ascii[ i ] ); } printf( "\n" ); return( 0 ); } SEE ALSO ==DOC==*/ DLL_EXPORT char * sl_etoa( void *dbuf, void *sbuf, int slen ) { unsigned char *sptr; unsigned char *dptr; sptr = sbuf; dptr = dbuf; if( dptr == NULL ) { dptr = sptr; } while( slen > 0 ) { slen--; dptr[ slen ] = guest_to_host( sptr[ slen ] ); } return( (char *)dptr ); } /*==DOC== NAME sl_islabel - Determines if passed data represents a standard label SYNOPSIS #include "sllib.h" int sl_islabel( SLLABEL *dlab, void *buf, int len ) DESCRIPTION This function performs several tests to determine if the "buf" parameter points to a valid standard label. The "len" parameter must be the length of the data pointed to by the "buf" parameter. If "dlab" does not contain NULL, then the data pointed to by "buf" will be converted to ASCII and placed at the "dlab" location. RETURN VALUE TRUE is returned if the data appears to be a standard label. Otherwise, FALSE is returned. NOTES The input label may be in either ASCII or EBCDIC. Currently, the tests are quite trival, but they may become more strict. EXAMPLE // // Test validity of a label // #include "sllib.h" int main( int argc, char *argv[] ) { SLLABEL sllab = { 0 }; printf( "Label is%s valid\n", ( sl_islabel( NULL, &sllab, sizeof( sllab ) ? "" : " not" ) ); sl_vol1( &sllab, "HET001", "HERCULES" ); printf( "Label is: %s valid\n", ( sl_islabel( NULL, &sllab, sizeof( sllab ) ? "" : " not" ) ); return( 0 ); } SEE ALSO sl_vol1() ==DOC==*/ DLL_EXPORT int sl_islabel( SLLABEL *lab, void *buf, int len ) { int i; int num; unsigned char *ptr; if( len != sizeof( SLLABEL ) ) { return FALSE; } for( i = 1 ; i < (int)SL_ELABS_MAX ; i++ ) { if( memcmp( sl_elabs[ i ], buf, 3 ) == 0 ) { ptr = buf; num = ptr[ 3 ] - (unsigned char) '\xF0'; if( ( num >= sl_ranges[ i ].min ) && ( num <= sl_ranges[ i ].max ) ) { if( lab != NULL ) { sl_etoa( lab, buf, len ); } return( TRUE ); } } if( memcmp( sl_alabs[ i ], buf, 3 ) == 0 ) { ptr = buf; num = ptr[ 3 ] - (unsigned char) '\x30'; if( ( num >= sl_ranges[ i ].min ) && ( num <= sl_ranges[ i ].max ) ) { if( lab != NULL ) { memcpy( lab, buf, len ); } return( TRUE ); } } } return( FALSE ); } /*==DOC== NAME sl_istype - Verifies data is of specified standard label type SYNOPSIS #include "sllib.h" int sl_istype( void *buf, int type, int num ) DESCRIPTION This function verifies that the data pointed to by the "buf" parameter contains a standard label as determined by the "type" and "num" parameters. The "type" parameter can be one of the "SLT_*" defines found in the "sllib.h" header file. The "num" parameter further defines the type and is usually 1 or 2. However, 0 may be specified to only test using the "type" parameter. RETURN VALUE TRUE is returned if the data is of the given type. Otherwise, FALSE is returned. NOTES The input data may be in either ASCII or EBCDIC. This routine is "usually" not called directly by user programs. The "sl_is*" macros in "sllib.h" should be used instead. EXAMPLE // // Determine if data is a VOL1 or HDR2 label. // #include "sllib.h" int main( int argc, char *argv[] ) { SLLABEL sllab = { 0 }; sl_vol1( &sllab, "HET001", "HERCULES" ); printf( "Label is%s a VOL1\n", ( sl_istype( &sllab, SLT_VOL, 1 ) ? "" : " not" ) ); printf( "Label is%s a HDR2\n", ( sl_istype( &sllab, SLT_HDR, 2 ) ? "" : " not" ) ); return( 0 ); } SEE ALSO sl_vol1() ==DOC==*/ DLL_EXPORT int sl_istype( void *buf, int type, int num ) { unsigned char *ptr; ptr = buf; /* || Check EBCDIC table */ if( memcmp( buf, sl_elabs[ type ], 3 ) == 0 ) { if( ( num == 0 ) || ( ptr[ 3 ] == ( ( (unsigned char) '\xF0' ) + num ) ) ) { return( TRUE ); } } /* || Check ASCII table */ if( memcmp( buf, sl_alabs[ type ], 3 ) == 0 ) { if( ( num == 0 ) || ( ptr[ 3 ] == ( ( (unsigned char) '\x30') + num ) ) ) { return( TRUE ); } } return( FALSE ); } /*==DOC== NAME sl_fmtdate - Converts dates to/from SL format SYNOPSIS #include "sllib.h" char *sl_fmtdate( char *dest, char *src, int fromto ) DESCRIPTION Converts the "src" date from or to the SL format and places the result at the "dest" location. If the "src" parameter is specified as NULL, then the current date will automatically be supplied. The "fromto" parameter controls the type of conversion. Specify FALSE to convert to SL format and TRUE from convert from SL format. When converting to the SL format, the "src" parameter must contain a valid Julian date in one of the following formats: YYDDD YY.DDD YYYYDDD YYYY.DDD RETURN VALUE If "src" contains an invalid date, then NULL will be returned. Otherwise, the "dest" value is returned. EXAMPLE // // Convert julian date to SL format // #include "sllib.h" char sldate[ SL_DATELEN ]; char jdate[] = "1998.212"; int main( int argc, char *argv[] ) { sl_fmtdate( sldate, jdate, FALSE ); printf( "Julian date : %s\n", jdate ); printf( "SL date : %-6.6s\n", sldate ); return( 0 ); } SEE ALSO ==DOC==*/ DLL_EXPORT char * sl_fmtdate( char *dest, char *src, int fromto ) { char wbuf[ 9 ]; char sbuf[ 9 ]; char *ptr; time_t curtime; struct tm tm; int ret; /* || If source represents an SL date, then convert it to julian */ if( fromto ) { if( src == NULL ) { return( NULL ); } if( src[ 5 ] == '0' ) { dest[ 0 ] = src[ 1 ]; dest[ 1 ] = src[ 2 ]; } else if( src[ 0 ] == ' ' ) { dest[ 0 ] = '1'; dest[ 1 ] = '9'; } else { dest[ 0 ] = '2'; dest[ 1 ] = src[ 0 ]; } memcpy( &dest[ 2 ], &src[ 1 ] , 2 ); dest[ 4 ] = '.'; memcpy( &dest[ 5 ], &src[ 3 ] , 3 ); } else { /* || Supply current date if source is null */ if( src == NULL ) { strftime( sbuf, sizeof( sbuf ), "%Y%j", localtime( &curtime ) ); src = sbuf; } /* || Base initial guess at format on length of src date */ switch( strlen( src ) ) { case 5: ptr = "%2u%3u"; break; case 6: ptr = "%2u.%3u"; break; case 7: ptr = "%4u%3u"; break; case 8: ptr = "%4u.%3u"; break; default: return( NULL ); break; } /* || Convert src to "tm" format */ ret = sscanf( src, ptr, &tm.tm_year, &tm.tm_yday ); if( ret != 2 || tm.tm_yday < 1 || tm.tm_yday > 366 ) { return( NULL ); } tm.tm_yday--; /* || Now, convert to SL tape format */ strftime( wbuf, sizeof( wbuf ), "%Y%j", &tm ); if( tm.tm_year < 100 ) { /* || 1900s are indicated by a blank. */ wbuf[ 1 ] = ' '; } /* || Finally, copy SL date to destination */ memcpy( dest, &wbuf[ 1 ], 6 ); } /* || Return dest pointer */ return( dest ); } /*==DOC== NAME sl_fmtlab - Transforms an SL label from raw to cooked format SYNOPSIS #include "sllib.h" void sl_fmtlab( SLFMT *fmt, SLLABEL *lab ) DESCRIPTION Converts the SL label specified by "lab" into a "cooked" format that's easier to process. Text descriptions are supplied for each field are also supplied. RETURN VALUE Nothing is returned. NOTES The input label may be in either ASCII or EBCDIC. It will be converted to ASCII before building the cooked version. The first two fields of the SLFMT structure are arrays that contain the text description and value for each field based on the label type. The arrays are terminated with NULL pointers. EXAMPLE // // Convert an SL label to cooked format // #include "sllib.h" int main( int argc, char *argv[] ) { SLFMT slfmt; SLLABEL sllab; int i; sl_vol1( &sllab, "HET001", "HERCULES" ); sl_fmtlab( &slfmt, &sllab ); for( i = 0 ; slfmt.key[ i ] != NULL ; i++ ) { printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] ); } return( 0 ); } SEE ALSO sl_vol1() ==DOC==*/ #define lab2fmt( i1, f2, l3, k4 ) \ fmt->key[ i1 ] = k4; \ fmt->val[ i1 ] = fmt->f2; \ memcpy( fmt->f2, lab->f2, l3 ); DLL_EXPORT void sl_fmtlab( SLFMT *fmt, SLLABEL *lab ) { SLLABEL templab; /* || Initialize */ memset( fmt, 0, sizeof( SLFMT ) ); /* || If label appears to be EBCDIC, convert to ASCII before processing */ if( sl_islabel( &templab, lab, sizeof( SLLABEL ) ) == FALSE ) { return; } lab = &templab; /* || Store label type (combine ID and NUM) */ fmt->key[ 0 ] = "Label"; fmt->val[ 0 ] = fmt->type; memcpy( fmt->type, lab->id, 4 ); /* || Build remaining fields based on label type */ if( memcmp( lab->id, "VOL", 3 ) == 0 ) { if( lab->num[ 0 ] == '1' ) { lab2fmt( 1, slvol.volser, 6, "Volume Serial" ); lab2fmt( 2, slvol.idrc, 1, "Improved Data Rec." ); lab2fmt( 3, slvol.owner, 10, "Owner Code" ); } } else if( ( memcmp( lab->id, "HDR", 3 ) == 0 ) || ( memcmp( lab->id, "EOF", 3 ) == 0 ) || ( memcmp( lab->id, "EOV", 3 ) == 0 ) ) { if( lab->num[ 0 ] == '1' ) { lab2fmt( 1, slds1.dsid, 17, "Dataset ID" ); lab2fmt( 2, slds1.volser, 6, "Volume Serial" ); lab2fmt( 3, slds1.volseq, 4, "Volume Sequence" ); lab2fmt( 4, slds1.dsseq, 4, "Dataset Sequence" ); lab2fmt( 5, slds1.genno, 4, "GDG Number" ); lab2fmt( 6, slds1.verno, 2, "GDG Version" ); lab2fmt( 7, slds1.crtdt, 6, "Creation Date" ); lab2fmt( 8, slds1.expdt, 6, "Expiration Date" ); lab2fmt( 9, slds1.dssec, 1, "Dataset Security" ); lab2fmt( 10, slds1.blklo, 6, "Block Count Low" ); lab2fmt( 11, slds1.syscd, 13, "System Code" ); lab2fmt( 12, slds1.blkhi, 4, "Block Count High" ); } else if( lab->num[ 0 ] == '2' ) { lab2fmt( 1, slds2.recfm, 1, "Record Format" ); lab2fmt( 2, slds2.blksize, 5, "Block Size" ); lab2fmt( 3, slds2.lrecl, 5, "Record Length" ); lab2fmt( 4, slds2.den, 1, "Density" ); lab2fmt( 5, slds2.dspos, 1, "Dataset Position" ); lab2fmt( 6, slds2.jobid, 17, "Job/Step ID" ); lab2fmt( 7, slds2.trtch, 2, "Recording Technique" ); lab2fmt( 8, slds2.ctrl, 1, "Control Character" ); lab2fmt( 9, slds2.blkattr, 1, "Block Attribute" ); lab2fmt( 10, slds2.devser, 6, "Device Serial" ); lab2fmt( 11, slds2.ckptid, 1, "Checkpoint ID" ); lab2fmt( 12, slds2.lblkln, 10, "Large Block Length" ); } } else if( memcmp( lab->id, "USR", 3 ) == 0 ) { lab2fmt( 1, slusr.data, 76, "User Data" ); } return; } #undef lab2fmt /*==DOC== NAME sl_vol - Generate a volume label SYNOPSIS #include "sllib.h" int sl_vol( SLLABEL *lab, char *volser, char *owner ) DESCRIPTION This function builds a volume label based on the parameters provided and places it at the location pointed to by the "lab" parameter in EBCDIC. The remaining parameters correspond to fields within the label and are converted to EBCDIC before storing. The "owner" parameter may be specified as NULL, in which case blanks are supplied. RETURN VALUE The return value will be >= 0 if no errors are detected. If an error is detected, then the return value will be < 0 and will be one of the following: SLE_VOLSER Missing or invalid volume serial SLE_OWNER Owner string too long NOTES This routine is normally accessed using the supplied "sl_vol1" macro. Only the "most common" label fields have corresponding parameters so the user must supply any other desired values. EXAMPLE // // Create a VOL1 label // #include "sllib.h" int main( int argc, char *argv[] ) { SLFMT slfmt; SLLABEL sllab; int i; sl_vol( &sllab, "HET001", "HERCULES" ); sl_fmtlab( &slfmt, &sllab ); for( i = 0 ; slfmt.key[ i ] != NULL ; i++ ) { printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] ); } return( 0 ); } SEE ALSO sl_fmtlab() ==DOC==*/ DLL_EXPORT int sl_vol( SLLABEL *lab, char *volser, char *owner ) { int len; /* || Initialize */ memset( lab, ' ', sizeof( SLLABEL ) ); /* || Label ID */ memcpy( lab->id, sl_alabs[ SLT_VOL ], 3 ); /* || Label number */ lab->num[ 0 ] = '1'; /* || Volser */ if( volser == NULL ) { return( SLE_VOLSER ); } len = strlen( volser ); if( ( len > 6 ) || ( (int)strspn( volser, sl_cset ) != len ) ) { return( SLE_VOLSER ); } memcpy( lab->slvol.volser, volser, len ); /* || Owner */ if( owner != NULL ) { len = strlen( owner ); if( len > 10 ) { return( SLE_OWNER ); } memcpy( lab->slvol.owner, owner, len ); } /* || Convert to EBCDIC */ sl_atoe( NULL, lab, sizeof( SLLABEL ) ); return 0; } /*==DOC== NAME sl_ds1 - Generate a data set label 1 SYNOPSIS #include "sllib.h" int sl_ds1( SLLABEL *lab, int type, char *dsn, char *volser, int volseq, int dsseq, char *expdt, int blocks ) DESCRIPTION This function builds a data set label 1 based on the parameters provided and places it at the location pointed to by the "lab" parameter in EBCDIC. The "type" parameter must be "SLT_HDR", "SLT_EOF", or "SLT_EOV". The remaining parameters correspond to fields within the label and are converted to EBCDIC before storing. The "dsn" parameter may be set to "SL_INITDSN" if "SLT_HDR" is specified for the "type" parameter. This will create an IEHINITT format HDR1 label. The "blocks" parameter is forced to 0 for "SLT_HDR" types. RETURN VALUE The return value will be >= 0 if no errors are detected. If an error is detected, then the return value will be < 0 and will be one of the following: SLE_INVALIDTYPE Invalid label type specified SLE_VOLSER Missing or invalid volume serial SLE_OWNER Owner string too long NOTES This routine is normally accessed using the supplied "sl_hdr1", "sl_eof1", or "sl_eov1" macros. Only the "most common" label fields have corresponding parameters so the user must supply any other desired values. EXAMPLE // // Create a EOF1 label // #include "sllib.h" int main( int argc, char *argv[] ) { SLFMT slfmt; SLLABEL sllab; int i; sl_ds1( &sllab, SLT_EOF, "HERCULES.TAPE.G0010V00", "HERC01", 1, 1, "2001.321", 289 ); sl_fmtlab( &slfmt, &sllab ); for( i = 0 ; slfmt.key[ i ] != NULL ; i++ ) { printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] ); } return( 0 ); } SEE ALSO sl_fmtlab() ==DOC==*/ DLL_EXPORT int sl_ds1( SLLABEL *lab, int type, char *dsn, char *volser, int volseq, int dsseq, char *expdt, int blocks ) { int gdg; int len; int ndx; char wbuf[ 80 ]; /* || Initialize */ memset( lab, ' ', sizeof( SLLABEL ) ); /* || Label ID */ if( ( type != SLT_HDR ) && ( type != SLT_EOF ) && ( type != SLT_EOV ) ) { return( SLE_INVALIDTYPE ); } memcpy( lab->id, sl_alabs[ type ], 3 ); /* || Label number */ lab->num[ 0 ] = '1'; /* || Special IEHINITT dataset name? */ if( ( type == SLT_HDR ) && ( strcmp( dsn, SL_INITDSN ) == 0 ) ) { memset( &lab->slds1, '0', sizeof( lab->slds1 ) ); sl_atoe( NULL, lab, sizeof( SLLABEL ) ); return( 0 ); } /* || Dataset ID */ ndx = 0; len = strlen( dsn ); if( len > 17 ) { ndx = len - 17; len = 17; } memcpy( lab->slds1.dsid, &dsn[ ndx ], len ); /* || GDG generation and version */ if( len > 9 ) { gdg = 0; gdg += ( dsn[ len - 9 ] == '.' ); gdg += ( dsn[ len - 8 ] == 'G' ); gdg += ( isdigit( dsn[ len - 7 ] ) != 0 ); gdg += ( isdigit( dsn[ len - 6 ] ) != 0 ); gdg += ( isdigit( dsn[ len - 5 ] ) != 0 ); gdg += ( isdigit( dsn[ len - 4 ] ) != 0 ); gdg += ( dsn[ len - 3 ] == 'V' ); gdg += ( isdigit( dsn[ len - 2 ] ) != 0 ); gdg += ( isdigit( dsn[ len - 1 ] ) != 0 ); if( gdg == 9 ) { memcpy( lab->slds1.genno, &dsn[ len - 7 ], 4 ); memcpy( lab->slds1.verno, &dsn[ len - 2 ], 2 ); } } /* || Volser */ len = strlen( volser ); if( len > 6 ) { return( SLE_VOLSER ); } memcpy( lab->slds1.volser, volser, len ); /* || Volume sequence */ if( volseq > 9999 ) { return( SLE_VOLSEQ ); } sprintf( wbuf, "%04u", volseq ); memcpy( lab->slds1.volseq, wbuf, 4 ); /* || Dataset sequence */ if( dsseq > 9999 ) { return( SLE_DSSEQ ); } sprintf( wbuf, "%04u", dsseq ); memcpy( lab->slds1.dsseq, wbuf, 4 ); /* || Creation Date */ sl_fmtdate( lab->slds1.crtdt, NULL, FALSE ); /* || Expiration Date */ if( sl_fmtdate( lab->slds1.expdt, expdt, FALSE ) == NULL ) { return( SLE_EXPDT ); } /* || Dataset security */ memset( lab->slds1.dssec, '0', 1 ); /* || Block count - low */ if( type == SLT_HDR ) { blocks = 0; } sprintf( wbuf, "%010u", blocks ); memcpy( lab->slds1.blklo, &wbuf[ 4 ], 6 ); /* || System code */ memcpy( lab->slds1.syscd, "IBM OS/VS 370", 13 ); /* || Block count - high */ sprintf( wbuf, "%10u", blocks ); memcpy( lab->slds1.blkhi, wbuf, 4 ); /* || Convert to EBCDIC */ sl_atoe( NULL, lab, sizeof( SLLABEL ) ); return 0; } /*==DOC== NAME sl_ds2 - Generate a data set label 2 SYNOPSIS #include "sllib.h" int sl_ds2( SLLABEL *lab, int type, char *recfm, int lrecl, int blksize, char *jobname, char *stepname, char *trtch ) DESCRIPTION This function builds a data set label 2 based on the parameters provided and places it at the location pointed to by the "lab" parameter in EBCDIC. The "type" parameter must be "SLT_HDR", "SLT_EOF", or "SLT_EOV". The remaining parameters correspond to fields within the label and are converted to EBCDIC before storing. The "recfm" parameter may be one of the following: F FS V VS U FA FSA VA VSA UA FM FSM VM VSM UM FB FBS VB VBS FBA FBSA VBA VBSA FBM FBSM VBM VBSM The "trtch" parameter may be blank or one of the following: T C E ET P RETURN VALUE The return value will be >= 0 if no errors are detected. If an error is detected, then the return value will be < 0 and will be one of the following: SLE_INVALIDTYPE Invalid label type specified SLE_RECFM Missing or invalid record format SLE_LRECL Invalid record length SLE_BLKSIZE Block size out of range SLE_JOBNAME Missing or invalid job name SLE_STEPNAME Missing or invalid step name SLE_TRTCH Invalid recording technique NOTES This routine is normally accessed using the supplied "sl_hdr1", "sl_eof1", or "sl_eov1" macros. Only the "most common" label fields have corresponding parameters so the user must supply any other desired values. EXAMPLE // // Create a EOV2 label // #include "sllib.h" int main( int argc, char *argv[] ) { SLFMT slfmt; SLLABEL sllab; int i; sl_ds2( &sllab, SLT_EOF, "FB", 80, 32720, "HERCJOB", "HERCSTEP", "P" ); sl_fmtlab( &slfmt, &sllab ); for( i = 0 ; slfmt.key[ i ] != NULL ; i++ ) { printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] ); } return( 0 ); } SEE ALSO sl_fmtlab() ==DOC==*/ DLL_EXPORT int sl_ds2( SLLABEL *lab, int type, char *recfm, int lrecl, int blksize, char *jobname, char *stepname, char *trtch ) { int i; int len; char wbuf[ 80 ]; /* || Initialize */ memset( lab, ' ', sizeof( SLLABEL ) ); /* || Label ID */ if( ( type != SLT_HDR ) && ( type != SLT_EOF ) && ( type != SLT_EOV ) ) { return( SLE_INVALIDTYPE ); } memcpy( lab->id, sl_alabs[ type ], 3 ); /* || Label number */ lab->num[ 0 ] = '1'; /* || Record format/Block Attribute/Control */ if( recfm == NULL ) { return( SLE_RECFM ); } for( i = 0 ; i < (int)VALFMCNT ; i++ ) { if( strcmp( recfm, valfm[ i ].recfm ) == 0 ) { break; } } if( i == VALFMCNT ) { return( SLE_RECFM ); } lab->slds2.recfm[ 0 ] = valfm[ i ].f; lab->slds2.blkattr[ 0 ] = valfm[ i ].b; lab->slds2.ctrl[ 0 ] = valfm[ i ].c; /* || Block size */ if( blksize == 0 ) { return( SLE_BLKSIZE ); } if( blksize > 32760 ) { sprintf( wbuf, "%10u", blksize ); memcpy( lab->slds2.lblkln, wbuf, 10 ); memcpy( lab->slds2.blksize, "00000", 5 ); } else { sprintf( wbuf, "%05u", blksize ); memcpy( lab->slds2.blksize, wbuf, 5 ); } /* || Logical record length */ switch( lab->slds2.recfm[ 0 ] ) { case 'F': if( ( valfm[ i ].b == 'S' ) || ( valfm[ i ].b == ' ' ) ) { if( lrecl != blksize ) { return( SLE_LRECL ); } } else { if( ( blksize % lrecl ) != 0 ) { return( SLE_LRECL ); } } break; case 'V': if( valfm[ i ].b == ' ' ) { if( ( lrecl + 4 ) != blksize ) { return( SLE_LRECL ); } } else if( valfm[ i ].b == 'B' ) { if( ( lrecl + 4 ) > blksize ) { return( SLE_LRECL ); } } break; case 'U': if( lrecl != 0 ) { return( SLE_LRECL ); } break; } sprintf( wbuf, "%05u", lrecl ); memcpy( lab->slds2.lrecl, wbuf, 5 ); /* || Jobname and stepname */ if( jobname != NULL ) { if( stepname == NULL ) { return( SLE_STEPNAME ); } len = strlen( jobname ); if( len > 8 ) { return( SLE_JOBNAME ); } len = strlen( stepname ); if( len > 8 ) { return( SLE_STEPNAME ); } } else { if( stepname != NULL ) { return( SLE_JOBNAME ); } } sprintf( wbuf, "%-8.8s/%-8.8s", jobname, stepname ); memcpy( lab->slds2.jobid, wbuf, 17 ); /* || Density */ lab->slds2.den[ 0 ] = '0'; /* || Dataset position */ lab->slds2.dspos[ 0 ] = '0'; /* || Tape recording technique */ if( trtch != NULL ) { len = strlen( trtch ); if( len < 1 || len > 2 ) { return( SLE_TRTCH ); } switch( trtch[ 0 ] ) { case 'T': case 'C': case 'P': case ' ': lab->slds2.trtch[ 0 ] = trtch[ 0 ]; break; case 'E': lab->slds2.trtch[ 0 ] = trtch[ 0 ]; if( len == 2 ) { if( trtch[ 1 ] != 'T' ) { return( SLE_TRTCH ); } lab->slds2.trtch[ 1 ] = trtch[ 1 ]; } break; default: return( SLE_TRTCH ); break; } } /* || Device serial number */ sprintf( wbuf, "%06u", rand() ); memcpy( lab->slds2.devser, wbuf, 6 ); /* || Checkpoint dataset identifier */ lab->slds2.ckptid[ 0 ] = ' '; /* || Convert to EBCDIC */ sl_atoe( NULL, lab, sizeof( SLLABEL ) ); return 0; } /*==DOC== NAME sl_usr - Generate a user label SYNOPSIS #include "sllib.h" int sl_usr( SLLABEL *lab, int type, int num, char *data ) DESCRIPTION This function builds a user label based on the parameters provided and places it at the location pointed to by the "lab" parameter in EBCDIC. The "type" parameter must be "SLT_UHL" or "SLT_UTL" and the "num" parameter must be 1 through 8. The remaining parameter corresponds to fields within the label and is converted to EBCDIC before storing. RETURN VALUE The return value will be >= 0 if no errors are detected. If an error is detected, then the return value will be < 0 and will be one of the following: SLE_DATA Missing or invalid user data NOTES This routine is normally accessed using the supplied "sl_uhl*" or "sl_utl*" macros. EXAMPLE // // Create a UHL6 label // #include "sllib.h" int main( int argc, char *argv[] ) { SLFMT slfmt; SLLABEL sllab; int i; sl_usr( &sllab, SLT_EOF, 6, "Hercules Emulated Tape" ); sl_fmtlab( &slfmt, &sllab ); for( i = 0 ; slfmt.key[ i ] != NULL ; i++ ) { printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] ); } return( 0 ); } SEE ALSO sl_fmtlab() ==DOC==*/ DLL_EXPORT int sl_usr( SLLABEL *lab, int type, int num, char *data ) { int len; /* || Initialize */ memset( lab, ' ', sizeof( SLLABEL ) ); /* || Label ID */ if( ( type != SLT_UHL ) && ( type != SLT_UTL ) ) { return( SLE_INVALIDTYPE ); } memcpy( lab->id, sl_elabs[ type ], 3 ); /* || Label number */ if( ( num < 1 ) || ( num > 8 ) ) { return( SLE_INVALIDNUM ); } lab->num[ 0 ] = '0' + num; /* || User data */ if( data == NULL ) { return( SLE_DATA ); } len = strlen( data ); if( len == 0 || len > 76 ) { return( SLE_DATA ); } memcpy( lab->slusr.data, data, len ); /* || Convert to EBCDIC */ sl_atoe( NULL, lab, sizeof( SLLABEL ) ); return 0; } /*==DOC== NAME sl_error - Returns a text message for an SL error code SYNOPSIS #include "sllib.h" char *sl_error( int rc ) DESCRIPTION Simply returns a pointer to a string that describes the error code passed in the "rc" parameter. RETURN VALUE The return value is always valid and no errors are returned. EXAMPLE // // Print text for SLE_DSSEQ. // #include "sllib.h" int main( int argc, char *argv[] ) { printf( "SLLIB error: %d = %s\n", SLE_DSSEQ, sl_error( SLE_DSSEQ ) ); return( 0 ); } SEE ALSO ==DOC==*/ DLL_EXPORT const char * sl_error( int rc ) { /* || If not an error just return the "OK" string */ if( rc >= 0 ) { rc = 0; } /* || Turn it into an index */ rc = -rc; /* || Within range? */ if( rc >= (int)SL_ERRSTR_MAX ) { rc = SL_ERRSTR_MAX - 1; } /* || Return string */ return( sl_errstr[ rc ] ); }