Figure 1. Example of Listing
All Members of a PDS/* this example shows how to create a list of members of a PDS */
/* part 1 of 2-other file is CCNGIP2 */
/*
* NODE_PTR pds_mem(const char *pds):
* pds must be a fully qualified pds name, for example,
* ID.PDS.DATASET * returns a * pointer to a linked list of
* nodes. Each node contains a member of the * pds and a
* pointer to the next node. If no members exist, the pointer
* is NULL.
*
* Note: Behavior is undefined if pds is the name of a sequential file.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ccngip2.h"
/*
* RECORD: each record of a pds will be read into one of these structures.
* The first 2 bytes is the record length, which is put into 'count',
* the remaining 254 bytes are put into rest. Each record is 256 bytes long.
*/
#define RECLEN 254
typedef struct {
unsigned short int count;
char rest[RECLEN];
} RECORD;
/* Local function prototypes */
static int gen_node(NODE_PTR *node, RECORD *rec, NODE_PTR *last_ptr);
static char *add_name(NODE_PTR *node, char *name, NODE_PTR *last_ptr);
NODE_PTR pds_mem(const char *pds) {
FILE *fp;
int bytes;
NODE_PTR node, last_ptr;
RECORD rec;
int list_end;
char *qual_pds;
node = NULL;
last_ptr = NULL;
/*
* Allocate a new variable, qual_pds, which will be the same as pds, except
* with single quotes around it, i.e. ID.PDS.DATASET ==> 'ID.PDS.DATA SET'
*/
qual_pds = (char *)malloc(strlen(pds) + 3);
if (qual_pds == NULL) {
fprintf(stderr,"malloc failed for %d bytes\n",strlen(pds) + 3);
exit(-1);
}
sprintf(qual_pds,"'%s'",pds);
|
/*
* Open the pds in binary read mode. The PDS directory will be read
one
* record at a time until either the end of the directory or end-of-file
* is detected. Call up gen_node() with every record read, to add
member
* names to the linked list
*/
fp = fopen(qual_pds,"rb");
if (fp == NULL)
return(NULL);
do
{ bytes = fread(&rec, 1, sizeof(rec), fp);
if ((bytes != sizeof(rec)) && !feof(fp)) {
perror("FREAD:");
fprintf(stderr,"Failed in %s, line %d\n"
"Expected to read %d bytes but read %d bytes\n",
__FILE__,__LINE__,sizeof(rec), bytes);
exit(-1);
}
list_end = gen_node(&node,&rec, &last_ptr);
} while (!feof(fp) && !list_end);
fclose(fp);
free(qual_pds);
return(node);
}
/*
* GEN_NODE() processes the record passed. The main loop scans through
the
* record until it has read at least rec->count bytes, or a directory
end
* marker is detected.
*
* Each record has the form:
*
* +------------+------+------+------+------+----------------+
* + # of bytes ¦Member¦Member¦......¦Member¦ Unused +
* + in record ¦ 1 ¦ 2 ¦ ¦ n ¦ +
* +------------+------+------+------+------+----------------+
* ¦--count---¦¦-----------------rest-----------------------¦
* (Note that the number stored in count includes its own
* two bytes)
*
* And, each member has the form:
*
* +--------+-------+----+-----------------------------------+
* + Member ¦TTR ¦info¦ +
* + Name ¦ ¦byte¦ User Data TTRN's (halfwords) +
* + 8 bytes¦3 bytes¦ ¦ +
* +--------+-------+----+-----------------------------------+
*/
#define TTRLEN 3 /* The TTR's are 3 bytes long */
/*
* bit 0 of the info-byte is '1' if the member is an alias,
* 0 otherwise. ALIAS_MASK is used to extract this information
*/
|
#define ALIAS_MASK ((unsigned int) 0x80)
/*
* The number of user data half-words is in bits 3-7 of the info byte.
* SKIP_MASK is used to extract this information. Since this number
is
* in half-words, it needs to be double to obtain the number of bytes.
*/
#define SKIP_MASK ((unsigned int) 0x1F)
/*
* 8 hex FF's mark the end of the directory
*/
char *endmark = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
static int gen_node(NODE_PTR *node, RECORD *rec, NODE_PTR *last_ptr) {
char *ptr, *name;
int skip, count = 2;
unsigned int info_byte, alias, ttrn;
char ttr[TTRLEN];
int list_end = 0;
ptr = rec->rest;
while(count < rec->count) {
if (!memcmp(ptr,endmark,NAMELEN)) {
list_end = 1;
break;
}
/* member name */
name = ptr;
ptr += NAMELEN;
/* ttr */
memcpy(ttr,ptr,TTRLEN);
ptr += TTRLEN;
/* info_byte */
info_byte = (unsigned int) (*ptr);
alias = info_byte & ALIAS_MASK;
if (!alias) add_name(node,name,last_ptr);
skip = (info_byte & SKIP_MASK) * 2 + 1;
ptr += skip;
count += (TTRLEN + NAMELEN + skip);
}
return(list_end);
}
/*
* ADD_NAME: Add a new member name to the linked node. The new member is
* added to the end so that the original ordering is maintained.
*/
static char *add_name(NODE_PTR *node, char *name, NODE_PTR *last_ptr) {
NODE_PTR newnode;
/*
* malloc space for the new node
*/
newnode = (NODE_PTR)malloc(sizeof(NODE));
if (newnode == NULL) {
fprintf(stderr,"malloc failed for %d bytes\n",sizeof(NODE));
exit(-1);
}
|
/* copy the name into the node and NULL terminate it */
memcpy(newnode->name,name,NAMELEN);
newnode->name[NAMELEN] = '\0';
newnode->next = NULL;
/*
* add the new node to the linked list
*/
if (*last_ptr != NULL) {
(*last_ptr)->next = newnode;
*last_ptr = newnode;
}
else {
*node = newnode;
*last_ptr = newnode;
}
return(newnode->name);
}
/*
* FREE_MEM: This function is not used by pds_mem(), but it should be used
* as soon as you are finished using the linked list. It frees the storage
* allocated by the linked list.
*/
void free_mem(NODE_PTR node) {
NODE_PTR next_node=node;
while (next_node != NULL) {
next_node = node->next;
free(node);
node = next_node;
}
return;
}
|