1 /* SLLIB.C      (c) Copyright Leland Lucius, 2000-2009               */
2 /*              Library for managing Standard Label tapes            */
3 
4 /*
5 || ----------------------------------------------------------------------------
6 ||
7 || SLLIB.C      (c) Copyright Leland Lucius, 2000-2009
8 ||              Released under terms of the Q Public License.
9 ||
10 || Library for managing Standard Label tapes.
11 ||
12 || ----------------------------------------------------------------------------
13 */
14 
15 #include "hstdinc.h"
16 
17 #define _SLLIB_C_
18 #define _HTAPE_DLL_
19 
20 #include "hercules.h"
21 #include "sllib.h"
22 
23 /*
24 || Local constant data
25 */
26 
27 /*
28 || Label IDs in EBCDIC
29 */
30 static const char *sl_elabs[] =
31 {
32     "\x00\x00\x00", /* Placeholder              */
33     "\xE5\xD6\xD3", /* EBCDIC characters "VOL"  */
34     "\xC8\xC4\xD9", /* EBCDIC characters "HDR"  */
35     "\xE4\xC8\xD3", /* EBCDIC characters "UHL"  */
36     "\xC5\xD6\xC6", /* EBCDIC characters "EOF"  */
37     "\xC5\xD6\xE5", /* EBCDIC characters "EOV"  */
38     "\xE4\xE3\xD3", /* EBCDIC characters "UTL"  */
39 };
40 #define SL_ELABS_MAX ( sizeof( sl_elabs ) / sizeof( sl_elabs[ 0 ] ) )
41 
42 /*
43 || Label IDs in ASCII
44 */
45 static const char *sl_alabs[] =
46 {
47     "\x00\x00\x00", /* Placeholder              */
48     "\x56\x4f\x4c", /* ASCII characters "VOL"   */
49     "\x48\x44\x52", /* ASCII characters "HDR"   */
50     "\x55\x48\x4c", /* ASCII characters "UHL"   */
51     "\x45\x4f\x46", /* ASCII characters "EOF"   */
52     "\x45\x4f\x56", /* ASCII characters "EOV"   */
53     "\x55\x54\x4c", /* ASCII characters "UTL"   */
54 };
55 #define SL_ALABS_MAX ( sizeof( sl_alabs ) / sizeof( sl_alabs[ 0 ] ) )
56 
57 /*
58 || Minimum and maximum ranges for each label type
59 */
60 static const struct
61 {
62     int min;
63     int max;
64 }
65 sl_ranges[] =
66 {
67     { 0, 0 },       /* Placeholder              */
68     { 1, 1 },       /* ASCII characters "VOL"   */
69     { 1, 2 },       /* ASCII characters "HDR"   */
70     { 1, 8 },       /* ASCII characters "UHL"   */
71     { 1, 2 },       /* ASCII characters "EOF"   */
72     { 1, 2 },       /* ASCII characters "EOV"   */
73     { 1, 8 },       /* ASCII characters "UTL"   */
74 };
75 
76 /*
77 || Text descriptions for errors
78 */
79 static const char *sl_errstr[] =
80 {
81     "No error",
82     "Block size out of range",
83     "Data set sequence out of range",
84     "Invalid expiration date",
85     "Missing or invalid job name",
86     "Missing or invalid record length",
87     "Owner string invalid or too long",
88     "Missing or invalid record format",
89     "Missing or invalid step name",
90     "Invalid recording technique",
91     "Volume sequence out of range",
92     "Missing or invalid volume serial",
93     "User data too long",
94     "Label type invalid",
95     "Label number invalid",
96     "Invalid error code",
97 };
98 #define SL_ERRSTR_MAX ( sizeof( sl_errstr) / sizeof( sl_errstr[ 0 ] ) )
99 
100 /*
101 || Valid characters for a Standard Label
102 || (from: SC26-4565-01 "3.4 Label Definition and Organization")
103 */
104 static const char
105 sl_cset[] =
106 {
107     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !\"%&'()*+,-./:;<=>?"
108 };
109 
110 /*
111 || Valid record formats
112 */
113 static const struct
114 {
115     char *recfm;
116     char f;
117     char b;
118     char c;
119 }
120 valfm[] =
121 {
122     { "U",    'U', ' ', ' ' },
123     { "UA",   'U', ' ', 'A' },
124     { "UM",   'U', ' ', 'M' },
125     { "F",    'F', ' ', ' ' },
126     { "FA",   'F', ' ', 'A' },
127     { "FM",   'F', ' ', 'M' },
128     { "FB",   'F', 'B', ' ' },
129     { "FBA",  'F', 'B', 'A' },
130     { "FBM",  'F', 'B', 'M' },
131     { "FS",   'F', 'S', ' ' },
132     { "FSA",  'F', 'S', 'A' },
133     { "FSM",  'F', 'S', 'M' },
134     { "FBS",  'F', 'R', ' ' },
135     { "FBSA", 'F', 'R', 'A' },
136     { "FBSM", 'F', 'R', 'M' },
137     { "V",    'V', ' ', ' ' },
138     { "VA",   'V', ' ', 'A' },
139     { "VM",   'V', ' ', 'M' },
140     { "VB",   'V', 'B', ' ' },
141     { "VBA",  'V', 'B', 'A' },
142     { "VBM",  'V', 'B', 'M' },
143     { "VS",   'V', 'S', ' ' },
144     { "VSA",  'V', 'S', 'A' },
145     { "VSM",  'V', 'S', 'M' },
146     { "VBS",  'V', 'R', ' ' },
147     { "VBSA", 'V', 'R', 'A' },
148     { "VBSM", 'V', 'R', 'M' },
149 };
150 #define VALFMCNT ( sizeof( valfm ) / sizeof( valfm[ 0 ] ) )
151 
152 /*==DOC==
153 
154     NAME
155             sl_atoe - Translate input buffer from ASCII to EBCDIC
156 
157     SYNOPSIS
158             #include "sllib.h"
159 
160             char *sl_atoe( void *dbuf, void *sbuf, int slen )
161 
162     DESCRIPTION
163             Translates, and optionally copies, "sbuf" from ASCII to
164             EBCDIC for "slen" characters.
165 
166             If "dbuf" is specified as NULL, then "sbuf" is translated in
167             place.  Otherwise, "dbuf" specifies the buffer where the
168             translated characters will be stored.
169 
170     RETURN VALUE
171             The return value will be either "sbuf" or "dbuf" depending on
172             whether "dbuf" was passed as NULL.
173 
174     EXAMPLE
175             //
176             // Convert buffer
177             //
178 
179             #include "sllib.h"
180 
181             unsigned char ascii[] =
182                 "\x48\x65\x72\x63\x75\x6c\x65\x73\x2e\x2e\x2e"
183                 "\x20\x52\x65\x73\x75\x72\x72\x65\x63\x74\x69"
184                 "\x6e\x67\x20\x74\x68\x65\x20\x64\x69\x6e\x6f"
185                 "\x73\x61\x75\x72\x73\x21";
186             unsigned char ebcdic[ sizeof( ascii ) ];
187 
188             int main( int argc, char *argv[] )
189             {
190                 int len;
191                 int i;
192 
193                 len = strlen( ascii );
194 
195                 sl_atoe( ebcdic, ascii, len );
196 
197                 printf( "ascii string:  " );
198 
199                 for( i = 0 ; i < len ; i++ )
200                 {
201                     printf( "%02x ", ascii[ i ] );
202                 }
203 
204                 printf( "\nebcdic string: " );
205 
206                 for( i = 0 ; i < len ; i++ )
207                 {
208                     printf( "%02x ", ebcdic[ i ] );
209                 }
210 
211                 printf( "\n" );
212 
213                 return( 0 );
214             }
215 
216     SEE ALSO
217 
218 ==DOC==*/
219 
220 DLL_EXPORT
221 char *
sl_atoe(void * dbuf,void * sbuf,int slen)222 sl_atoe( void *dbuf, void *sbuf, int slen )
223 {
224     unsigned char *sptr;
225     unsigned char *dptr;
226 
227     sptr = sbuf;
228     dptr = dbuf;
229 
230     if( dptr == NULL )
231     {
232         dptr = sptr;
233     }
234 
235     while( slen > 0 )
236     {
237         slen--;
238         dptr[ slen ] = host_to_guest( sptr[ slen ] );
239     }
240 
241     return( (char *)dptr );
242 }
243 
244 /*==DOC==
245 
246     NAME
247             sl_etoa - Translate input buffer from EBCDIC to ASCII
248 
249     SYNOPSIS
250             #include "sllib.h"
251 
252             char *sl_etoa( void *dbuf, void *sbuf, int slen )
253 
254     DESCRIPTION
255             Translates, and optionally copies, "sbuf" from EBCDIC to
256             ASCII for "slen" characters.
257 
258             If "dbuf" is specified as NULL, then "sbuf" is translated in
259             place.  Otherwise, "dbuf" specifies the buffer where the
260             translated characters will be stored.
261 
262     RETURN VALUE
263             The return value will be either "sbuf" or "dbuf" depending on
264             whether "dbuf" was passed as NULL.
265 
266     EXAMPLE
267             //
268             // Convert buffer
269             //
270 
271             #include "sllib.h"
272 
273             unsigned char ebcdic[] =
274                 "\xc8\x85\x99\x83\xa4\x93\x85\xa2\x4b\x4b\x4b"
275                 "\x40\xd9\x85\xa2\xa4\x99\x99\x85\x83\xa3\x89"
276                 "\x95\x87\x40\xa3\x88\x85\x40\x84\x89\x95\x96"
277                 "\xa2\x81\xa4\x99\xa2\x5a";
278             unsigned char ascii[ sizeof( ebcdic ) ];
279 
280             int main( int argc, char *argv[] )
281             {
282                 int len;
283                 int i;
284 
285                 len = strlen( ebcdic );
286 
287                 sl_etoa( ascii, ebcdic, len );
288 
289                 printf( "ebcdic string:  " );
290 
291                 for( i = 0 ; i < len ; i++ )
292                 {
293                     printf( "%02x ", ebcdic[ i ] );
294                 }
295 
296                 printf( "\nascii string: " );
297 
298                 for( i = 0 ; i < len ; i++ )
299                 {
300                     printf( "%02x ", ascii[ i ] );
301                 }
302 
303                 printf( "\n" );
304 
305                 return( 0 );
306             }
307 
308     SEE ALSO
309 
310 ==DOC==*/
311 
312 DLL_EXPORT
313 char *
sl_etoa(void * dbuf,void * sbuf,int slen)314 sl_etoa( void *dbuf, void *sbuf, int slen )
315 {
316     unsigned char *sptr;
317     unsigned char *dptr;
318 
319     sptr = sbuf;
320     dptr = dbuf;
321 
322     if( dptr == NULL )
323     {
324         dptr = sptr;
325     }
326 
327     while( slen > 0 )
328     {
329         slen--;
330         dptr[ slen ] = guest_to_host( sptr[ slen ] );
331     }
332 
333     return( (char *)dptr );
334 }
335 
336 /*==DOC==
337 
338     NAME
339             sl_islabel - Determines if passed data represents a standard label
340 
341     SYNOPSIS
342             #include "sllib.h"
343 
344             int sl_islabel( SLLABEL *dlab, void *buf, int len )
345 
346     DESCRIPTION
347             This function performs several tests to determine if the "buf"
348             parameter points to a valid standard label.  The "len" parameter
349             must be the length of the data pointed to by the "buf" parameter.
350             If "dlab" does not contain NULL, then the data pointed to by "buf"
351             will be converted to ASCII and placed at the "dlab" location.
352 
353     RETURN VALUE
354             TRUE is returned if the data appears to be a standard label.
355             Otherwise, FALSE is returned.
356 
357     NOTES
358             The input label may be in either ASCII or EBCDIC.
359 
360             Currently, the tests are quite trival, but they may become more
361             strict.
362 
363     EXAMPLE
364             //
365             // Test validity of a label
366             //
367 
368             #include "sllib.h"
369 
370             int main( int argc, char *argv[] )
371             {
372                 SLLABEL sllab = { 0 };
373 
374                 printf( "Label is%s valid\n",
375                     ( sl_islabel( NULL, &sllab, sizeof( sllab ) ? "" : " not" ) );
376 
377                 sl_vol1( &sllab, "HET001", "HERCULES" );
378 
379                 printf( "Label is: %s valid\n",
380                     ( sl_islabel( NULL, &sllab, sizeof( sllab ) ? "" : " not" ) );
381 
382                 return( 0 );
383             }
384 
385     SEE ALSO
386         sl_vol1()
387 
388 ==DOC==*/
389 
390 DLL_EXPORT
391 int
sl_islabel(SLLABEL * lab,void * buf,int len)392 sl_islabel( SLLABEL *lab, void *buf, int len )
393 {
394     int i;
395     int num;
396     unsigned char *ptr;
397 
398     if( len != sizeof( SLLABEL ) )
399     {
400         return FALSE;
401     }
402 
403     for( i = 1 ; i < (int)SL_ELABS_MAX ; i++ )
404     {
405         if( memcmp( sl_elabs[ i ], buf, 3 ) == 0 )
406         {
407             ptr = buf;
408             num = ptr[ 3 ] - (unsigned char) '\xF0';
409             if( ( num >= sl_ranges[ i ].min ) && ( num <= sl_ranges[ i ].max ) )
410             {
411                 if( lab != NULL )
412                 {
413                     sl_etoa( lab, buf, len );
414                 }
415                 return( TRUE );
416             }
417         }
418 
419         if( memcmp( sl_alabs[ i ], buf, 3 ) == 0 )
420         {
421             ptr = buf;
422             num = ptr[ 3 ] - (unsigned char) '\x30';
423             if( ( num >= sl_ranges[ i ].min ) && ( num <= sl_ranges[ i ].max ) )
424             {
425                 if( lab != NULL )
426                 {
427                     memcpy( lab, buf, len );
428                 }
429 
430                 return( TRUE );
431             }
432         }
433     }
434 
435     return( FALSE );
436 }
437 
438 /*==DOC==
439 
440     NAME
441             sl_istype - Verifies data is of specified standard label type
442 
443     SYNOPSIS
444             #include "sllib.h"
445 
446             int sl_istype( void *buf, int type, int num )
447 
448     DESCRIPTION
449             This function verifies that the data pointed to by the "buf"
450             parameter contains a standard label as determined by the "type"
451             and "num" parameters.
452 
453             The "type" parameter can be one of the "SLT_*" defines found in
454             the "sllib.h" header file.
455 
456             The "num" parameter further defines the type and is usually 1
457             or 2.  However, 0 may be specified to only test using the "type"
458             parameter.
459 
460     RETURN VALUE
461             TRUE is returned if the data is of the given type.  Otherwise,
462             FALSE is returned.
463 
464     NOTES
465             The input data may be in either ASCII or EBCDIC.
466 
467             This routine is "usually" not called directly by user programs.
468             The "sl_is*" macros in "sllib.h" should be used instead.
469 
470     EXAMPLE
471             //
472             // Determine if data is a VOL1 or HDR2 label.
473             //
474 
475             #include "sllib.h"
476 
477             int main( int argc, char *argv[] )
478             {
479                 SLLABEL sllab = { 0 };
480 
481                 sl_vol1( &sllab, "HET001", "HERCULES" );
482 
483                 printf( "Label is%s a VOL1\n",
484                     ( sl_istype( &sllab, SLT_VOL, 1 ) ? "" : " not" ) );
485 
486                 printf( "Label is%s a HDR2\n",
487                     ( sl_istype( &sllab, SLT_HDR, 2 ) ? "" : " not" ) );
488 
489                 return( 0 );
490             }
491 
492     SEE ALSO
493         sl_vol1()
494 
495 ==DOC==*/
496 
497 DLL_EXPORT
498 int
sl_istype(void * buf,int type,int num)499 sl_istype( void *buf, int type, int num )
500 {
501     unsigned char *ptr;
502 
503     ptr = buf;
504 
505     /*
506     || Check EBCDIC table
507     */
508     if( memcmp( buf, sl_elabs[ type ], 3 ) == 0 )
509     {
510         if( ( num == 0 ) || ( ptr[ 3 ] == ( ( (unsigned char) '\xF0' ) + num ) ) )
511         {
512             return( TRUE );
513         }
514     }
515 
516     /*
517     || Check ASCII table
518     */
519     if( memcmp( buf, sl_alabs[ type ], 3 ) == 0 )
520     {
521         if( ( num == 0 ) || ( ptr[ 3 ] == ( ( (unsigned char) '\x30') + num ) ) )
522         {
523             return( TRUE );
524         }
525     }
526 
527     return( FALSE );
528 }
529 
530 /*==DOC==
531 
532     NAME
533             sl_fmtdate - Converts dates to/from SL format
534 
535     SYNOPSIS
536             #include "sllib.h"
537 
538             char *sl_fmtdate( char *dest, char *src, int fromto )
539 
540     DESCRIPTION
541             Converts the "src" date from or to the SL format and places the
542             result at the "dest" location.  If the "src" parameter is specified
543             as NULL, then the current date will automatically be supplied.
544 
545             The "fromto" parameter controls the type of conversion.  Specify
546             FALSE to convert to SL format and TRUE from convert from SL format.
547 
548             When converting to the SL format, the "src" parameter must contain
549             a valid Julian date in one of the following formats:
550                 YYDDD
551                 YY.DDD
552                 YYYYDDD
553                 YYYY.DDD
554 
555     RETURN VALUE
556             If "src" contains an invalid date, then NULL will be returned.
557             Otherwise, the "dest" value is returned.
558 
559     EXAMPLE
560             //
561             // Convert julian date to SL format
562             //
563 
564             #include "sllib.h"
565 
566             char sldate[ SL_DATELEN ];
567             char jdate[] = "1998.212";
568 
569             int main( int argc, char *argv[] )
570             {
571 
572                 sl_fmtdate( sldate, jdate, FALSE );
573 
574                 printf( "Julian date : %s\n", jdate );
575                 printf( "SL date     : %-6.6s\n", sldate );
576 
577                 return( 0 );
578             }
579 
580     SEE ALSO
581 
582 ==DOC==*/
583 
584 DLL_EXPORT
585 char *
sl_fmtdate(char * dest,char * src,int fromto)586 sl_fmtdate( char *dest, char *src, int fromto )
587 {
588     char wbuf[ 9 ];
589     char sbuf[ 9 ];
590     char *ptr;
591     time_t curtime;
592     struct tm tm;
593     int ret;
594 
595     /*
596     || If source represents an SL date, then convert it to julian
597     */
598     if( fromto )
599     {
600         if( src == NULL )
601         {
602             return( NULL );
603         }
604 
605         if( src[ 5 ] == '0' )
606         {
607             dest[ 0 ] = src[ 1 ];
608             dest[ 1 ] = src[ 2 ];
609         }
610         else if( src[ 0 ] == ' ' )
611         {
612             dest[ 0 ] = '1';
613             dest[ 1 ] = '9';
614         }
615         else
616         {
617             dest[ 0 ] = '2';
618             dest[ 1 ] = src[ 0 ];
619         }
620 
621         memcpy( &dest[ 2 ], &src[ 1 ] , 2 );
622         dest[ 4 ] = '.';
623         memcpy( &dest[ 5 ], &src[ 3 ] , 3 );
624     }
625     else
626     {
627         /*
628         || Supply current date if source is null
629         */
630         if( src == NULL )
631         {
632             strftime( sbuf, sizeof( sbuf ), "%Y%j", localtime( &curtime ) );
633             src = sbuf;
634         }
635 
636         /*
637         || Base initial guess at format on length of src date
638         */
639         switch( strlen( src ) )
640         {
641             case 5:
642                 ptr = "%2u%3u";
643             break;
644 
645             case 6:
646                 ptr = "%2u.%3u";
647             break;
648 
649             case 7:
650                 ptr = "%4u%3u";
651             break;
652 
653             case 8:
654                 ptr = "%4u.%3u";
655             break;
656 
657             default:
658                 return( NULL );
659             break;
660         }
661 
662         /*
663         || Convert src to "tm" format
664         */
665         ret = sscanf( src, ptr, &tm.tm_year, &tm.tm_yday );
666         if( ret != 2 || tm.tm_yday < 1 || tm.tm_yday > 366 )
667         {
668             return( NULL );
669         }
670         tm.tm_yday--;
671 
672         /*
673         || Now, convert to SL tape format
674         */
675         strftime( wbuf, sizeof( wbuf ), "%Y%j", &tm );
676         if( tm.tm_year < 100 )
677         {
678             /*
679             || 1900s are indicated by a blank.
680             */
681             wbuf[ 1 ] = ' ';
682         }
683 
684         /*
685         || Finally, copy SL date to destination
686         */
687         memcpy( dest, &wbuf[ 1 ], 6 );
688     }
689 
690     /*
691     || Return dest pointer
692     */
693     return( dest );
694 }
695 
696 /*==DOC==
697 
698     NAME
699             sl_fmtlab - Transforms an SL label from raw to cooked format
700 
701     SYNOPSIS
702             #include "sllib.h"
703 
704             void sl_fmtlab( SLFMT *fmt, SLLABEL *lab )
705 
706     DESCRIPTION
707             Converts the SL label specified by "lab" into a "cooked" format
708             that's easier to process.  Text descriptions are supplied for
709             each field are also supplied.
710 
711     RETURN VALUE
712             Nothing is returned.
713 
714     NOTES
715             The input label may be in either ASCII or EBCDIC.  It will be
716             converted to ASCII before building the cooked version.
717 
718             The first two fields of the SLFMT structure are arrays that contain
719             the text description and value for each field based on the label
720             type.  The arrays are terminated with NULL pointers.
721 
722     EXAMPLE
723             //
724             // Convert an SL label to cooked format
725             //
726 
727             #include "sllib.h"
728 
729             int main( int argc, char *argv[] )
730             {
731                 SLFMT slfmt;
732                 SLLABEL sllab;
733                 int i;
734 
735                 sl_vol1( &sllab, "HET001", "HERCULES" );
736 
737                 sl_fmtlab( &slfmt, &sllab );
738 
739                 for( i = 0 ; slfmt.key[ i ] != NULL ; i++ )
740                 {
741                     printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] );
742                 }
743 
744                 return( 0 );
745             }
746 
747     SEE ALSO
748         sl_vol1()
749 
750 ==DOC==*/
751 
752 #define lab2fmt( i1, f2, l3, k4 ) \
753             fmt->key[ i1 ] = k4; \
754             fmt->val[ i1 ] = fmt->f2; \
755             memcpy( fmt->f2, lab->f2, l3 );
756 DLL_EXPORT
757 void
sl_fmtlab(SLFMT * fmt,SLLABEL * lab)758 sl_fmtlab( SLFMT *fmt, SLLABEL *lab )
759 {
760     SLLABEL templab;
761 
762     /*
763     || Initialize
764     */
765     memset( fmt, 0, sizeof( SLFMT ) );
766 
767     /*
768     || If label appears to be EBCDIC, convert to ASCII before processing
769     */
770     if( sl_islabel( &templab, lab, sizeof( SLLABEL ) ) == FALSE )
771     {
772         return;
773     }
774     lab = &templab;
775 
776     /*
777     || Store label type (combine ID and NUM)
778     */
779     fmt->key[ 0 ] = "Label";
780     fmt->val[ 0 ] = fmt->type;
781     memcpy( fmt->type, lab->id, 4 );
782 
783     /*
784     || Build remaining fields based on label type
785     */
786     if( memcmp( lab->id, "VOL", 3 ) == 0 )
787     {
788         if( lab->num[ 0 ] == '1' )
789         {
790             lab2fmt(  1, slvol.volser,      6,  "Volume Serial"         );
791             lab2fmt(  2, slvol.idrc,        1,  "Improved Data Rec."    );
792             lab2fmt(  3, slvol.owner,       10, "Owner Code"            );
793         }
794     }
795     else if( ( memcmp( lab->id, "HDR", 3 ) == 0 ) ||
796              ( memcmp( lab->id, "EOF", 3 ) == 0 ) ||
797              ( memcmp( lab->id, "EOV", 3 ) == 0 ) )
798     {
799         if( lab->num[ 0 ] == '1' )
800         {
801             lab2fmt( 1,  slds1.dsid,        17, "Dataset ID"            );
802             lab2fmt( 2,  slds1.volser,      6,  "Volume Serial"         );
803             lab2fmt( 3,  slds1.volseq,      4,  "Volume Sequence"       );
804             lab2fmt( 4,  slds1.dsseq,       4,  "Dataset Sequence"      );
805             lab2fmt( 5,  slds1.genno,       4,  "GDG Number"            );
806             lab2fmt( 6,  slds1.verno,       2,  "GDG Version"           );
807             lab2fmt( 7,  slds1.crtdt,       6,  "Creation Date"         );
808             lab2fmt( 8,  slds1.expdt,       6,  "Expiration Date"       );
809             lab2fmt( 9,  slds1.dssec,       1,  "Dataset Security"      );
810             lab2fmt( 10, slds1.blklo,       6,  "Block Count Low"       );
811             lab2fmt( 11, slds1.syscd,       13, "System Code"           );
812             lab2fmt( 12, slds1.blkhi,       4,  "Block Count High"      );
813         }
814         else if( lab->num[ 0 ] == '2' )
815         {
816             lab2fmt( 1,  slds2.recfm,       1,  "Record Format"         );
817             lab2fmt( 2,  slds2.blksize,     5,  "Block Size"            );
818             lab2fmt( 3,  slds2.lrecl,       5,  "Record Length"         );
819             lab2fmt( 4,  slds2.den,         1,  "Density"               );
820             lab2fmt( 5,  slds2.dspos,       1,  "Dataset Position"      );
821             lab2fmt( 6,  slds2.jobid,       17, "Job/Step ID"           );
822             lab2fmt( 7,  slds2.trtch,       2,  "Recording Technique"   );
823             lab2fmt( 8,  slds2.ctrl,        1,  "Control Character"     );
824             lab2fmt( 9,  slds2.blkattr,     1,  "Block Attribute"       );
825             lab2fmt( 10, slds2.devser,      6,  "Device Serial"         );
826             lab2fmt( 11, slds2.ckptid,      1,  "Checkpoint ID"         );
827             lab2fmt( 12, slds2.lblkln,      10, "Large Block Length"    );
828         }
829     }
830     else if( memcmp( lab->id, "USR", 3 ) == 0 )
831     {
832         lab2fmt(  1, slusr.data,            76, "User Data"             );
833     }
834 
835     return;
836 }
837 #undef lab2fmt
838 
839 /*==DOC==
840 
841     NAME
842             sl_vol - Generate a volume label
843 
844     SYNOPSIS
845             #include "sllib.h"
846 
847             int sl_vol( SLLABEL *lab,
848                         char *volser,
849                         char *owner )
850 
851     DESCRIPTION
852             This function builds a volume label based on the parameters
853             provided and places it at the location pointed to by the "lab"
854             parameter in EBCDIC.
855 
856             The remaining parameters correspond to fields within the label
857             and are converted to EBCDIC before storing.
858 
859             The "owner" parameter may be specified as NULL, in which case
860             blanks are supplied.
861 
862     RETURN VALUE
863             The return value will be >= 0 if no errors are detected.
864 
865             If an error is detected, then the return value will be < 0 and
866             will be one of the following:
867 
868             SLE_VOLSER          Missing or invalid volume serial
869             SLE_OWNER           Owner string too long
870 
871     NOTES
872             This routine is normally accessed using the supplied "sl_vol1"
873             macro.
874 
875             Only the "most common" label fields have corresponding parameters
876             so the user must supply any other desired values.
877 
878     EXAMPLE
879             //
880             // Create a VOL1 label
881             //
882 
883             #include "sllib.h"
884 
885             int main( int argc, char *argv[] )
886             {
887                 SLFMT slfmt;
888                 SLLABEL sllab;
889                 int i;
890 
891                 sl_vol( &sllab, "HET001", "HERCULES" );
892 
893                 sl_fmtlab( &slfmt, &sllab );
894 
895                 for( i = 0 ; slfmt.key[ i ] != NULL ; i++ )
896                 {
897                     printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] );
898                 }
899 
900                 return( 0 );
901             }
902 
903     SEE ALSO
904         sl_fmtlab()
905 
906 ==DOC==*/
907 
908 DLL_EXPORT
909 int
sl_vol(SLLABEL * lab,char * volser,char * owner)910 sl_vol( SLLABEL *lab,
911         char *volser,
912         char *owner )
913 {
914     size_t len;
915 
916     /*
917     || Initialize
918     */
919     memset( lab, ' ', sizeof( SLLABEL ) );
920 
921     /*
922     || Label ID
923     */
924     memcpy( lab->id, sl_alabs[ SLT_VOL ], 3 );
925 
926     /*
927     || Label number
928     */
929     lab->num[ 0 ] = '1';
930 
931     /*
932     || Volser
933     */
934     if( volser == NULL )
935     {
936         return( SLE_VOLSER );
937     }
938 
939     len = strlen( volser );
940     if( ( len > 6 ) || ( strspn( volser, sl_cset ) != len ) )
941     {
942         return( SLE_VOLSER );
943     }
944 
945     memcpy( lab->slvol.volser, volser, len );
946 
947     /*
948     || Owner
949     */
950     if( owner != NULL )
951     {
952         len = strlen( owner );
953         if( len > 10 )
954         {
955             return( SLE_OWNER );
956         }
957         memcpy( lab->slvol.owner, owner, len );
958     }
959 
960     /*
961     || Convert to EBCDIC
962     */
963     sl_atoe( NULL, lab, sizeof( SLLABEL ) );
964 
965     return 0;
966 }
967 
968 /*==DOC==
969 
970     NAME
971             sl_ds1 - Generate a data set label 1
972 
973     SYNOPSIS
974             #include "sllib.h"
975 
976             int sl_ds1( SLLABEL *lab,
977                         int type,
978                         char *dsn,
979                         char *volser,
980                         int volseq,
981                         int dsseq,
982                         char *expdt,
983                         int blocks )
984 
985     DESCRIPTION
986             This function builds a data set label 1 based on the parameters
987             provided and places it at the location pointed to by the "lab"
988             parameter in EBCDIC.
989 
990             The "type" parameter must be "SLT_HDR", "SLT_EOF", or "SLT_EOV".
991 
992             The remaining parameters correspond to fields within the label
993             and are converted to EBCDIC before storing.
994 
995             The "dsn" parameter may be set to "SL_INITDSN" if "SLT_HDR" is
996             specified for the "type" parameter.  This will create an IEHINITT
997             format HDR1 label.
998 
999             The "blocks" parameter is forced to 0 for "SLT_HDR" types.
1000 
1001     RETURN VALUE
1002             The return value will be >= 0 if no errors are detected.
1003 
1004             If an error is detected, then the return value will be < 0 and
1005             will be one of the following:
1006 
1007             SLE_INVALIDTYPE     Invalid label type specified
1008             SLE_VOLSER          Missing or invalid volume serial
1009             SLE_OWNER           Owner string too long
1010 
1011     NOTES
1012             This routine is normally accessed using the supplied "sl_hdr1",
1013             "sl_eof1", or "sl_eov1" macros.
1014 
1015             Only the "most common" label fields have corresponding parameters
1016             so the user must supply any other desired values.
1017 
1018     EXAMPLE
1019             //
1020             // Create a EOF1 label
1021             //
1022 
1023             #include "sllib.h"
1024 
1025             int main( int argc, char *argv[] )
1026             {
1027                 SLFMT slfmt;
1028                 SLLABEL sllab;
1029                 int i;
1030 
1031                 sl_ds1( &sllab,
1032                         SLT_EOF,
1033                         "HERCULES.TAPE.G0010V00",
1034                         "HERC01",
1035                         1,
1036                         1,
1037                         "2001.321",
1038                         289 );
1039 
1040                 sl_fmtlab( &slfmt, &sllab );
1041 
1042                 for( i = 0 ; slfmt.key[ i ] != NULL ; i++ )
1043                 {
1044                     printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] );
1045                 }
1046 
1047                 return( 0 );
1048             }
1049 
1050     SEE ALSO
1051         sl_fmtlab()
1052 
1053 ==DOC==*/
1054 
1055 DLL_EXPORT
1056 int
sl_ds1(SLLABEL * lab,int type,char * dsn,char * volser,int volseq,int dsseq,char * expdt,int blocks)1057 sl_ds1( SLLABEL *lab,
1058         int type,
1059         char *dsn,
1060         char *volser,
1061         int volseq,
1062         int dsseq,
1063         char *expdt,
1064         int blocks )
1065 {
1066     int gdg;
1067     size_t len;
1068     size_t ndx;
1069     char wbuf[ 80 ];
1070 
1071     /*
1072     || Initialize
1073     */
1074     memset( lab, ' ', sizeof( SLLABEL ) );
1075 
1076     /*
1077     || Label ID
1078     */
1079     if( ( type != SLT_HDR ) && ( type != SLT_EOF ) && ( type != SLT_EOV ) )
1080     {
1081         return( SLE_INVALIDTYPE );
1082     }
1083     memcpy( lab->id, sl_alabs[ type ], 3 );
1084 
1085     /*
1086     || Label number
1087     */
1088     lab->num[ 0 ] = '1';
1089 
1090     /*
1091     || Special IEHINITT dataset name?
1092     */
1093     if( ( type == SLT_HDR ) && ( strcmp( dsn, SL_INITDSN ) == 0 ) )
1094     {
1095         memset( &lab->slds1, '0', sizeof( lab->slds1 ) );
1096         sl_atoe( NULL, lab, sizeof( SLLABEL ) );
1097         return( 0 );
1098     }
1099 
1100     /*
1101     || Dataset ID
1102     */
1103     ndx = 0;
1104     len = strlen( dsn );
1105     if( len > 17 )
1106     {
1107         ndx = len - 17;
1108         len = 17;
1109     }
1110     memcpy( lab->slds1.dsid, &dsn[ ndx ], len );
1111 
1112     /*
1113     || GDG generation and version
1114     */
1115     if( len > 9 )
1116     {
1117         gdg  = 0;
1118         gdg += (          dsn[ len - 9 ]   == '.' );
1119         gdg += (          dsn[ len - 8 ]   == 'G' );
1120         gdg += ( isdigit( dsn[ len - 7 ] ) !=  0  );
1121         gdg += ( isdigit( dsn[ len - 6 ] ) !=  0  );
1122         gdg += ( isdigit( dsn[ len - 5 ] ) !=  0  );
1123         gdg += ( isdigit( dsn[ len - 4 ] ) !=  0  );
1124         gdg += (          dsn[ len - 3 ]   == 'V' );
1125         gdg += ( isdigit( dsn[ len - 2 ] ) !=  0  );
1126         gdg += ( isdigit( dsn[ len - 1 ] ) !=  0  );
1127 
1128         if( gdg == 9 )
1129         {
1130             memcpy( lab->slds1.genno, &dsn[ len - 7 ], 4 );
1131             memcpy( lab->slds1.verno, &dsn[ len - 2 ], 2 );
1132         }
1133     }
1134 
1135     /*
1136     || Volser
1137     */
1138     len = strlen( volser );
1139     if( len > 6 )
1140     {
1141         return( SLE_VOLSER );
1142     }
1143     memcpy( lab->slds1.volser, volser, len );
1144 
1145     /*
1146     || Volume sequence
1147     */
1148     if( volseq > 9999 )
1149     {
1150         return( SLE_VOLSEQ );
1151     }
1152     sprintf( wbuf, "%04u", volseq );
1153     memcpy( lab->slds1.volseq, wbuf, 4 );
1154 
1155     /*
1156     || Dataset sequence
1157     */
1158     if( dsseq > 9999 )
1159     {
1160         return( SLE_DSSEQ );
1161     }
1162     sprintf( wbuf, "%04u", dsseq );
1163     memcpy( lab->slds1.dsseq, wbuf, 4 );
1164 
1165     /*
1166     || Creation Date
1167     */
1168     sl_fmtdate( lab->slds1.crtdt, NULL, FALSE );
1169 
1170     /*
1171     || Expiration Date
1172     */
1173     if( sl_fmtdate( lab->slds1.expdt, expdt, FALSE ) == NULL )
1174     {
1175         return( SLE_EXPDT );
1176     }
1177 
1178     /*
1179     || Dataset security
1180     */
1181     memset( lab->slds1.dssec, '0', 1 );
1182 
1183     /*
1184     || Block count - low
1185     */
1186     if( type == SLT_HDR )
1187     {
1188         blocks = 0;
1189     }
1190     sprintf( wbuf, "%010u", blocks );
1191     memcpy( lab->slds1.blklo, &wbuf[ 4 ], 6 );
1192 
1193     /*
1194     || System code
1195     */
1196     memcpy( lab->slds1.syscd, "IBM OS/VS 370", 13 );
1197 
1198     /*
1199     || Block count - high
1200     */
1201     sprintf( wbuf, "%10u", blocks );
1202     memcpy( lab->slds1.blkhi, wbuf, 4 );
1203 
1204     /*
1205     || Convert to EBCDIC
1206     */
1207     sl_atoe( NULL, lab, sizeof( SLLABEL ) );
1208 
1209     return 0;
1210 }
1211 
1212 /*==DOC==
1213 
1214     NAME
1215             sl_ds2 - Generate a data set label 2
1216 
1217     SYNOPSIS
1218             #include "sllib.h"
1219 
1220             int sl_ds2( SLLABEL *lab,
1221                         int type,
1222                         char *recfm,
1223                         int lrecl,
1224                         int blksize,
1225                         char *jobname,
1226                         char *stepname,
1227                         char *trtch )
1228 
1229     DESCRIPTION
1230             This function builds a data set label 2 based on the parameters
1231             provided and places it at the location pointed to by the "lab"
1232             parameter in EBCDIC.
1233 
1234             The "type" parameter must be "SLT_HDR", "SLT_EOF", or "SLT_EOV".
1235 
1236             The remaining parameters correspond to fields within the label
1237             and are converted to EBCDIC before storing.
1238 
1239             The "recfm" parameter may be one of the following:
1240                 F       FS      V       VS      U
1241                 FA      FSA     VA      VSA     UA
1242                 FM      FSM     VM      VSM     UM
1243                 FB      FBS     VB      VBS
1244                 FBA     FBSA    VBA     VBSA
1245                 FBM     FBSM    VBM     VBSM
1246 
1247             The "trtch" parameter may be blank or one of the following:
1248                 T       C       E       ET      P
1249 
1250     RETURN VALUE
1251             The return value will be >= 0 if no errors are detected.
1252 
1253             If an error is detected, then the return value will be < 0 and
1254             will be one of the following:
1255 
1256             SLE_INVALIDTYPE     Invalid label type specified
1257             SLE_RECFM           Missing or invalid record format
1258             SLE_LRECL           Invalid record length
1259             SLE_BLKSIZE         Block size out of range
1260             SLE_JOBNAME         Missing or invalid job name
1261             SLE_STEPNAME        Missing or invalid step name
1262             SLE_TRTCH           Invalid recording technique
1263 
1264     NOTES
1265             This routine is normally accessed using the supplied "sl_hdr1",
1266             "sl_eof1", or "sl_eov1" macros.
1267 
1268             Only the "most common" label fields have corresponding parameters
1269             so the user must supply any other desired values.
1270 
1271     EXAMPLE
1272             //
1273             // Create a EOV2 label
1274             //
1275 
1276             #include "sllib.h"
1277 
1278             int main( int argc, char *argv[] )
1279             {
1280                 SLFMT slfmt;
1281                 SLLABEL sllab;
1282                 int i;
1283 
1284                 sl_ds2( &sllab,
1285                         SLT_EOF,
1286                         "FB",
1287                         80,
1288                         32720,
1289                         "HERCJOB",
1290                         "HERCSTEP",
1291                         "P" );
1292 
1293                 sl_fmtlab( &slfmt, &sllab );
1294 
1295                 for( i = 0 ; slfmt.key[ i ] != NULL ; i++ )
1296                 {
1297                     printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] );
1298                 }
1299 
1300                 return( 0 );
1301             }
1302 
1303     SEE ALSO
1304         sl_fmtlab()
1305 
1306 ==DOC==*/
1307 
1308 DLL_EXPORT
1309 int
sl_ds2(SLLABEL * lab,int type,char * recfm,int lrecl,int blksize,char * jobname,char * stepname,char * trtch)1310 sl_ds2( SLLABEL *lab,
1311         int type,
1312         char *recfm,
1313         int lrecl,
1314         int blksize,
1315         char *jobname,
1316         char *stepname,
1317         char *trtch )
1318 {
1319     int i;
1320     size_t len;
1321     char wbuf[ 80 ];
1322 
1323     /*
1324     || Initialize
1325     */
1326     memset( lab, ' ', sizeof( SLLABEL ) );
1327 
1328     /*
1329     || Label ID
1330     */
1331     if( ( type != SLT_HDR ) && ( type != SLT_EOF ) && ( type != SLT_EOV ) )
1332     {
1333         return( SLE_INVALIDTYPE );
1334     }
1335     memcpy( lab->id, sl_alabs[ type ], 3 );
1336 
1337     /*
1338     || Label number
1339     */
1340     lab->num[ 0 ] = '1';
1341 
1342     /*
1343     || Record format/Block Attribute/Control
1344     */
1345     if( recfm == NULL )
1346     {
1347         return( SLE_RECFM );
1348     }
1349 
1350     for( i = 0 ; i < (int)VALFMCNT ; i++ )
1351     {
1352         if( strcmp( recfm, valfm[ i ].recfm ) == 0 )
1353         {
1354             break;
1355         }
1356     }
1357 
1358     if( i == VALFMCNT )
1359     {
1360         return( SLE_RECFM );
1361     }
1362 
1363     lab->slds2.recfm[ 0 ]   = valfm[ i ].f;
1364     lab->slds2.blkattr[ 0 ] = valfm[ i ].b;
1365     lab->slds2.ctrl[ 0 ]    = valfm[ i ].c;
1366 
1367     /*
1368     || Block size
1369     */
1370     if( blksize == 0 )
1371     {
1372         return( SLE_BLKSIZE );
1373     }
1374 
1375     if( blksize > 32760 )
1376     {
1377         sprintf( wbuf, "%10u", blksize );
1378         memcpy( lab->slds2.lblkln, wbuf, 10 );
1379         memcpy( lab->slds2.blksize, "00000", 5 );
1380     }
1381     else
1382     {
1383         sprintf( wbuf, "%05u", blksize );
1384         memcpy( lab->slds2.blksize, wbuf, 5 );
1385     }
1386 
1387     /*
1388     || Logical record length
1389     */
1390     switch( lab->slds2.recfm[ 0 ] )
1391     {
1392         case 'F':
1393             if( ( valfm[ i ].b == 'S' ) || ( valfm[ i ].b == ' ' ) )
1394             {
1395                 if( lrecl != blksize )
1396                 {
1397                     return( SLE_LRECL );
1398                 }
1399             }
1400             else
1401             {
1402                 if( ( blksize % lrecl ) != 0 )
1403                 {
1404                     return( SLE_LRECL );
1405                 }
1406             }
1407         break;
1408 
1409         case 'V':
1410             if( valfm[ i ].b == ' ' )
1411             {
1412                 if( ( lrecl + 4 ) != blksize )
1413                 {
1414                     return( SLE_LRECL );
1415                 }
1416             }
1417             else if( valfm[ i ].b == 'B' )
1418             {
1419                 if( ( lrecl + 4 ) > blksize )
1420                 {
1421                     return( SLE_LRECL );
1422                 }
1423             }
1424         break;
1425 
1426         case 'U':
1427             if( lrecl != 0 )
1428             {
1429                 return( SLE_LRECL );
1430             }
1431         break;
1432     }
1433     sprintf( wbuf, "%05u", lrecl );
1434     memcpy( lab->slds2.lrecl, wbuf, 5 );
1435 
1436     /*
1437     || Jobname and stepname
1438     */
1439     if( jobname != NULL )
1440     {
1441         if( stepname == NULL )
1442         {
1443             return( SLE_STEPNAME );
1444         }
1445 
1446         len = strlen( jobname );
1447         if( len > 8 )
1448         {
1449             return( SLE_JOBNAME );
1450         }
1451 
1452         len = strlen( stepname );
1453         if( len > 8 )
1454         {
1455             return( SLE_STEPNAME );
1456         }
1457     }
1458     else
1459     {
1460         if( stepname != NULL )
1461         {
1462             return( SLE_JOBNAME );
1463         }
1464     }
1465     sprintf( wbuf, "%-8.8s/%-8.8s", jobname, stepname );
1466     memcpy( lab->slds2.jobid, wbuf, 17 );
1467 
1468     /*
1469     || Density
1470     */
1471     lab->slds2.den[ 0 ] = '0';
1472 
1473     /*
1474     || Dataset position
1475     */
1476     lab->slds2.dspos[ 0 ] = '0';
1477 
1478     /*
1479     || Tape recording technique
1480     */
1481     if( trtch != NULL )
1482     {
1483         len = strlen( trtch );
1484         if( len < 1 || len > 2 )
1485         {
1486             return( SLE_TRTCH );
1487         }
1488 
1489         switch( trtch[ 0 ] )
1490         {
1491             case 'T': case 'C': case 'P': case ' ':
1492                 lab->slds2.trtch[ 0 ] = trtch[ 0 ];
1493             break;
1494 
1495             case 'E':
1496                 lab->slds2.trtch[ 0 ] = trtch[ 0 ];
1497                 if( len == 2 )
1498                 {
1499                     if( trtch[ 1 ] != 'T' )
1500                     {
1501                         return( SLE_TRTCH );
1502                     }
1503                     lab->slds2.trtch[ 1 ] = trtch[ 1 ];
1504                 }
1505             break;
1506 
1507             default:
1508                 return( SLE_TRTCH );
1509             break;
1510         }
1511     }
1512 
1513     /*
1514     || Device serial number
1515     */
1516     sprintf( wbuf, "%06u", rand() );
1517     memcpy( lab->slds2.devser, wbuf, 6 );
1518 
1519     /*
1520     || Checkpoint dataset identifier
1521     */
1522     lab->slds2.ckptid[ 0 ] = ' ';
1523 
1524     /*
1525     || Convert to EBCDIC
1526     */
1527     sl_atoe( NULL, lab, sizeof( SLLABEL ) );
1528 
1529     return 0;
1530 }
1531 
1532 /*==DOC==
1533 
1534     NAME
1535             sl_usr - Generate a user label
1536 
1537     SYNOPSIS
1538             #include "sllib.h"
1539 
1540             int sl_usr( SLLABEL *lab,
1541                         int type,
1542                         int num,
1543                         char *data )
1544 
1545     DESCRIPTION
1546             This function builds a user label based on the parameters provided
1547             and places it at the location pointed to by the "lab" parameter in
1548             EBCDIC.
1549 
1550             The "type" parameter must be "SLT_UHL" or "SLT_UTL" and the "num"
1551             parameter must be 1 through 8.
1552 
1553             The remaining parameter corresponds to fields within the label
1554             and is converted to EBCDIC before storing.
1555 
1556     RETURN VALUE
1557             The return value will be >= 0 if no errors are detected.
1558 
1559             If an error is detected, then the return value will be < 0 and
1560             will be one of the following:
1561 
1562             SLE_DATA            Missing or invalid user data
1563 
1564     NOTES
1565             This routine is normally accessed using the supplied "sl_uhl*"
1566             or "sl_utl*" macros.
1567 
1568     EXAMPLE
1569             //
1570             // Create a UHL6 label
1571             //
1572 
1573             #include "sllib.h"
1574 
1575             int main( int argc, char *argv[] )
1576             {
1577                 SLFMT slfmt;
1578                 SLLABEL sllab;
1579                 int i;
1580 
1581                 sl_usr( &sllab,
1582                         SLT_EOF,
1583                         6,
1584                         "Hercules Emulated Tape" );
1585 
1586                 sl_fmtlab( &slfmt, &sllab );
1587 
1588                 for( i = 0 ; slfmt.key[ i ] != NULL ; i++ )
1589                 {
1590                     printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] );
1591                 }
1592 
1593                 return( 0 );
1594             }
1595 
1596     SEE ALSO
1597         sl_fmtlab()
1598 
1599 ==DOC==*/
1600 
1601 DLL_EXPORT
1602 int
sl_usr(SLLABEL * lab,int type,int num,char * data)1603 sl_usr( SLLABEL *lab,
1604         int type,
1605         int num,
1606         char *data )
1607 {
1608     size_t len;
1609 
1610     /*
1611     || Initialize
1612     */
1613     memset( lab, ' ', sizeof( SLLABEL ) );
1614 
1615     /*
1616     || Label ID
1617     */
1618     if( ( type != SLT_UHL ) && ( type != SLT_UTL ) )
1619     {
1620         return( SLE_INVALIDTYPE );
1621     }
1622     memcpy( lab->id, sl_elabs[ type ], 3 );
1623 
1624     /*
1625     || Label number
1626     */
1627     if( ( num < 1 ) || ( num > 8 ) )
1628     {
1629         return( SLE_INVALIDNUM );
1630     }
1631     lab->num[ 0 ] = '0' + num;
1632 
1633     /*
1634     || User data
1635     */
1636     if( data == NULL )
1637     {
1638         return( SLE_DATA );
1639     }
1640 
1641     len = strlen( data );
1642     if( len == 0 || len > 76 )
1643     {
1644         return( SLE_DATA );
1645     }
1646     memcpy( lab->slusr.data, data, len );
1647 
1648     /*
1649     || Convert to EBCDIC
1650     */
1651     sl_atoe( NULL, lab, sizeof( SLLABEL ) );
1652 
1653     return 0;
1654 }
1655 
1656 /*==DOC==
1657 
1658     NAME
1659             sl_error - Returns a text message for an SL error code
1660 
1661     SYNOPSIS
1662             #include "sllib.h"
1663 
1664             char *sl_error( int rc )
1665 
1666     DESCRIPTION
1667             Simply returns a pointer to a string that describes the error
1668             code passed in the "rc" parameter.
1669 
1670     RETURN VALUE
1671             The return value is always valid and no errors are returned.
1672 
1673     EXAMPLE
1674             //
1675             // Print text for SLE_DSSEQ.
1676             //
1677 
1678             #include "sllib.h"
1679 
1680             int main( int argc, char *argv[] )
1681             {
1682                 printf( "SLLIB error: %d = %s\n",
1683                     SLE_DSSEQ,
1684                     sl_error( SLE_DSSEQ ) );
1685 
1686                 return( 0 );
1687             }
1688 
1689     SEE ALSO
1690 
1691 ==DOC==*/
1692 
1693 DLL_EXPORT
1694 const char *
sl_error(int rc)1695 sl_error( int rc )
1696 {
1697     /*
1698     || If not an error just return the "OK" string
1699     */
1700     if( rc >= 0 )
1701     {
1702         rc = 0;
1703     }
1704 
1705     /*
1706     || Turn it into an index
1707     */
1708     rc = -rc;
1709 
1710     /*
1711     || Within range?
1712     */
1713     if( rc >= (int)SL_ERRSTR_MAX )
1714     {
1715         rc = SL_ERRSTR_MAX - 1;
1716     }
1717 
1718     /*
1719     || Return string
1720     */
1721     return( sl_errstr[ rc ] );
1722 }
1723