/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * Copyright by the Board of Trustees of the University of Illinois.         *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF.  The full HDF copyright notice, including       *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF/releases/.  *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "hdp.h"

const char *unknown_tag = "Unknown Tag";

char *
tagnum_to_name(int num)
{
    char *ret;

    if (num < 0)
        ret = NULL;
    else
        ret = HDgettagsname((uint16)num);
    if (ret == NULL)
        ret = strdup(unknown_tag);
    return (ret);
} /* end tagnum_to_name() */

int
tagname_to_num(const char *name)
{
    return (HDgettagnum(name));
} /* end tagname_to_num() */

/*
 *  Routines to create a list of file names from the command line
 */

/* assumes that curr_arg is pointing to the first file name */
filelist_t *
make_file_list(int curr_arg, int argc, char *argv[])
{
    int         i;
    filelist_t *ret;

    if (curr_arg > argc) /* consistency check */
        return (NULL);

    ret = (filelist_t *)malloc(sizeof(filelist_t));
    if (ret == NULL) {
        fprintf(stderr, "make_file_list: space allocation failed\n");
        return (NULL);
    }
    ret->file_arr = (char **)malloc(sizeof(char *) * (size_t)((argc - curr_arg) + 1));
    if (ret->file_arr == NULL) {
        fprintf(stderr, "make_file_list: space allocation failed\n");
        free(ret);
        return (NULL);
    }

    ret->max_files = (argc - curr_arg);
    ret->curr_file = 0;
    for (i = 0; curr_arg < argc; i++, curr_arg++)
        ret->file_arr[i] = strdup(argv[curr_arg]);
    return (ret);
} /* end make_file_list() */

char *
get_next_file(filelist_t *f_list, int advance)
{
    if (advance)
        f_list->curr_file++;
    if (f_list->curr_file >= f_list->max_files)
        return (NULL);
    return (f_list->file_arr[f_list->curr_file]);
} /* end get_next_file() */

/* free_node_vg_info_t frees a node of vgroup info */
vg_info_t *
free_node_vg_info_t(vg_info_t *aNode)
{
    int i;

    if (aNode != NULL) {
        if (aNode->children != NULL) {
            for (i = 0; i < aNode->n_entries; i++)
                if (aNode->children[i] != NULL) {
                    free(aNode->children[i]);
                    aNode->children[i] = NULL;
                }
            free(aNode->children);
            aNode->children = NULL;
        }
        if (aNode->type != NULL) {
            for (i = 0; i < aNode->n_entries; i++)
                if (aNode->type[i] != NULL) {
                    free(aNode->type[i]);
                    aNode->type[i] = NULL;
                }
            free(aNode->type);
            aNode->type = NULL;
        }
        free(aNode->vg_name);
        aNode->vg_name = NULL;
    }
    return (aNode);
} /* end of free_node_vg_info_t */

/* free_struct_list use free() to free the list of vgroup info structs */
vg_info_t **
free_vginfo_list(vg_info_t **nodelist, int32 num_items)
{
    int i;

    /* if the list is not NULL, free each node then reset the list to NULL */
    if (nodelist != NULL) {
        for (i = 0; i < num_items; i++)
            if (nodelist[i] != NULL) {
                nodelist[i] = free_node_vg_info_t(nodelist[i]);
                free(nodelist[i]);
                nodelist[i] = NULL;
            }
        free(nodelist);
    }
    return (NULL);
} /* end of free_vginfo_list */

/* free_struct_list use free() to free the list of vgroup info structs */
obj_chosen_t **
free_node_obj_chosen_t(obj_chosen_t *aNode)
{
    if (aNode != NULL) {
        if (aNode->name != NULL) {
            fprintf(stderr, " name = %s \n", aNode->name);
            free(aNode->name);
        }
        free(aNode->classname);
        free(aNode);
    }
    return (NULL);
} /* end of free_node_obj_chosen_t */

/* free_struct_list use free() to free the list of vgroup info structs */
void
free_obj_chosen_t_list(obj_chosen_t **nodelist, int32 num_items)
{
    int i;

    /* if the list is not NULL, free each node then reset the list to NULL */
    if ((*nodelist) != NULL) {
        for (i = 0; i < num_items; i++) {
            free((*nodelist)[i].name);
            free((*nodelist)[i].classname);
        }
        free((*nodelist));
        (*nodelist) = NULL;
    }
} /* end of free_obj_chosen_t_list */

/* free_str_list use free() to free the list of strings of characters */
char **
free_str_list(char **str_list, int32 num_items)
{
    int i;

    if (str_list != NULL) {
        for (i = 0; i < num_items; i++)
            free(str_list[i]);
        free(str_list);
    }
    return (NULL);
} /* end of free_str_list */

/* free_num_list use free() to free the list of integers; this routine
 * is short but can be used in many different places and very convenient
 */
int32 *
free_num_list(int32 *num_list)
{
    free(num_list);
    return (NULL);
} /* end of free_num_list */

void
free_file_list(filelist_t *f_list)
{
    int i;

    for (i = 0; i < f_list->max_files; i++)
        free(f_list->file_arr[i]);
    free(f_list->file_arr);
    free(f_list);
} /* end free_file_list() */

/*
 *  Routines to manipulate group lists
 */
groupinfo_t *
make_group_list(int32 fid, uint16 tag, uint16 ref)
{
    int          nobj;
    groupinfo_t *ret = NULL;
    int32        gid;

    if (tag == DFTAG_RIG || tag == DFTAG_SDG || tag == DFTAG_NDG) {
        if ((gid = DFdiread(fid, tag, ref)) == FAIL)
            return NULL;
        if ((nobj = DFdinobj(gid)) == FAIL)
            return NULL;
        if ((ret = (groupinfo_t *)malloc(sizeof(groupinfo_t))) == NULL) {
            fprintf(stderr, "make_group_list: space allocation failed\n");
            return NULL;
        }
        ret->max_dds = nobj;
        ret->curr_dd = 0;
        if (nobj > 0) {
            if ((ret->dd_arr = (DFdi *)calloc((size_t)nobj, sizeof(DFdi))) == NULL) {
                fprintf(stderr, "make_group_list: space allocation failed\n");
                free(ret);
                return NULL;
            }
            for (int i = 0; i < nobj; i++) {
                if (DFdiget(gid, &ret->dd_arr[i].tag, &ret->dd_arr[i].ref) == FAIL) {
                    free(ret->dd_arr);
                    free(ret);
                    return NULL;
                }
            }
        }
        else {
            ret->max_dds = ret->curr_dd = 0;
            ret->dd_arr                 = NULL;
        }
    }
    else { /* check for Vgroup? */
        int32 vkey;

        /* Yes, I know this wastes time, but at least it allows uniform access */
        /* to both types of groups in HDF files... */
        if (vinit_done == FALSE) { /* check whether we've already init'ed Vsets */
            vinit_done = TRUE;
            Vinitialize(fid);
        }
        if ((vkey = Vattach(fid, ref, "r")) != FAIL) {
            if ((nobj = Vntagrefs(vkey)) != FAIL) {
                if (nobj > 0) {
                    int32 *temp_tag;
                    int32 *temp_ref;

                    if ((temp_tag = (int32 *)calloc((size_t)nobj, sizeof(int32))) == NULL) {
                        fprintf(stderr, "make_group_list: space allocation failed\n");
                        Vdetach(vkey);
                        return NULL;
                    }
                    if ((temp_ref = (int32 *)malloc(sizeof(int32) * (size_t)nobj)) == NULL) {
                        fprintf(stderr, "make_group_list: space allocation failed\n");

                        Vdetach(vkey);
                        free(temp_tag);
                        return NULL;
                    }

                    if (Vgettagrefs(vkey, temp_tag, temp_ref, nobj) == FAIL) {
                        Vdetach(vkey);
                        free(temp_tag);
                        free(temp_ref);
                        return NULL;
                    }

                    if ((ret = (groupinfo_t *)malloc(sizeof(groupinfo_t))) == NULL) {
                        fprintf(stderr, "make_group_list: space allocation failed\n");

                        Vdetach(vkey);
                        free(temp_tag);
                        free(temp_ref);
                        return NULL;
                    }
                    ret->max_dds = nobj;
                    ret->curr_dd = 0;
                    if ((ret->dd_arr = (DFdi *)malloc(sizeof(DFdi) * (size_t)nobj)) == NULL) {
                        fprintf(stderr, "make_group_list: space allocation failed\n");

                        Vdetach(vkey);
                        free(temp_tag);
                        free(temp_ref);
                        free(ret);
                        return NULL;
                    }

                    for (int i = 0; i < nobj; i++) {
                        ret->dd_arr[i].tag = (uint16)temp_tag[i];
                        ret->dd_arr[i].ref = (uint16)temp_ref[i];
                    }

                    free(temp_tag);
                    free(temp_ref);
                } /* if nobj > 0 */
                /* BMR: 7/28/00 must add this one, otherwise, free fails later */
                else /* nobj <= 0 */
                    return NULL;
            }
            else
                /* bad vkey? */
                return NULL;
            Vdetach(vkey); /* release the Vgroup */
        }
        else
            /* failed to attach */
            return NULL;
    }
    return ret;
} /* end make_group_list() */

DFdi *
get_next_group(groupinfo_t *g_list, int advance)
{
    if (g_list == NULL)
        return (NULL);
    if (advance)
        g_list->curr_dd++;
    if (g_list->curr_dd >= g_list->max_dds)
        return (NULL);
    return (&g_list->dd_arr[g_list->curr_dd]);
} /* end get_next_group() */

int32
get_group_max(groupinfo_t *g_list)
{
    if (g_list != NULL)
        return (g_list->max_dds);
    return (FAIL);
} /* end get_group_max() */

void
free_group_list(groupinfo_t *g_list)
{
    if (g_list != NULL) {
        free(g_list->dd_arr);
        free(g_list);
    }
} /* end free_group_list() */

/*
 *  Routines to manipulate tag/ref lists
 */

objlist_t *
make_obj_list(int32 fid, uint32 options)
{
    int             nobj;     /* number of DDs in the file */
    int32           status;   /* status of various HDF calls */
    int32           aid;      /* temporary AID to use while getting DD info */
    int16           tmp_spec; /* temporary storage for special status */
    objlist_t      *obj_ret;  /* pointer to the dd list to return */
    objinfo_t      *obj_ptr;  /* temporary pointer to a working DD object */
    sp_info_block_t info;     /* temp. storage for special elem. info */
    int             n, m;     /* local counting variable */

    /* get the number of all objects in the file */
    nobj = Hnumber(fid, DFTAG_WILDCARD);
    if (nobj == FAIL || nobj <= 0) /* BMR: added check for nobj<=0 */
        return (NULL);

    /* allocate space for the object list - exit at failure??? */
    if ((obj_ret = (objlist_t *)malloc(sizeof(objlist_t))) == NULL) {
        fprintf(stderr, "make_obj_list: space allocation failed\n");
        return (NULL);
    }

    obj_ret->max_obj     = nobj; /* set the number of objects */
    obj_ret->curr_obj    = 0;
    obj_ret->raw_obj_arr = (objinfo_t *)malloc(sizeof(objinfo_t) * (size_t)nobj);

    /* should it exit on failure ??? */
    if (obj_ret->raw_obj_arr == NULL) {
        fprintf(stderr, "make_obj_list: space allocation failed\n");
        free(obj_ret);
        return (NULL);
    }

    /* Clear array of dd/object information */
    memset(obj_ret->raw_obj_arr, 0, sizeof(objinfo_t) * (size_t)nobj);

    /*
     * Read all the tag/ref's in the file into an array
     */
    /* start the reading of an access element */
    aid = Hstartread(fid, DFTAG_WILDCARD, DFREF_WILDCARD);
    if (aid == FAIL) {
        HEprint(stderr, 0);
        free(obj_ret->raw_obj_arr);
        free(obj_ret);
        return (NULL);
    } /* end if */

    /* for each element */
    for (n = 0, status = SUCCEED; (n < nobj) && (status != FAIL); n++) {
        Hinquire(aid, NULL, &(obj_ret->raw_obj_arr[n].tag), &(obj_ret->raw_obj_arr[n].ref),
                 &(obj_ret->raw_obj_arr[n].length), &(obj_ret->raw_obj_arr[n].offset), NULL, NULL, &tmp_spec);
        if (options & CHECK_SPECIAL) { /* are we looking for spec. elem. ? */
            obj_ret->raw_obj_arr[n].is_special = (tmp_spec != 0);
            if (obj_ret->raw_obj_arr[n].is_special) { /* get the special info. */
                if ((status = HDget_special_info(aid, &info)) == FAIL) {
                    obj_ret->raw_obj_arr[n].is_special = 0;
                }      /* end if */
                else { /* copy over special information we found */
                    obj_ret->raw_obj_arr[n].spec_info = (sp_info_block_t *)malloc(sizeof(sp_info_block_t));
                    if (obj_ret->raw_obj_arr[n].spec_info == NULL) {
                        fprintf(stderr, "make_obj_list: space allocation failed\n");
                        obj_ret->raw_obj_arr[n].is_special = 0;
                    }
                    else
                        memcpy(obj_ret->raw_obj_arr[n].spec_info, &info, sizeof(sp_info_block_t));
                } /* end else */
            }     /* end if */
        }         /* end if */
        status = Hnextread(aid, DFTAG_WILDCARD, DFREF_WILDCARD, DF_CURRENT);
    } /* end for */

    if (Hendaccess(aid) == FAIL) {
        HEprint(stderr, 0);
        free(obj_ret->raw_obj_arr);
        free(obj_ret);
        return (NULL);
    }

    /* Post-process the list of dd/objects, adding more information */
    /*  Also set up the pointers for the sorted list to be manipulated later */

    obj_ret->srt_obj_arr = (objinfo_t **)calloc((size_t)nobj, sizeof(objinfo_t *));
    if (obj_ret->srt_obj_arr == NULL) {
        fprintf(stderr, "make_obj_list: space allocation failed\n");
        free(obj_ret->raw_obj_arr);
        free(obj_ret);
        return (NULL);
    }

    /* Loop for more information */
    for (n = 0; n < nobj; n++) {
        obj_ptr = obj_ret->srt_obj_arr[n] = &obj_ret->raw_obj_arr[n];

        /* set the index value to a flag for later */
        obj_ptr->index = (-1);

        /* check for a group */
        if (options & CHECK_GROUP) { /* are we looking for groups ? */
            if (obj_ptr->tag == DFTAG_RIG || obj_ptr->tag == DFTAG_SDG || obj_ptr->tag == DFTAG_NDG ||
                obj_ptr->tag == DFTAG_VG) {
                obj_ptr->is_group   = TRUE;
                obj_ptr->group_info = make_group_list(fid, obj_ptr->tag, obj_ptr->ref);
                if (obj_ptr->group_info == NULL) {
                    /* do not free these because even this element has no group
                       list, it still can be displayed */
                    /*
                                   free(obj_ret->raw_obj_arr);
                                   free(obj_ret);
                                   return (NULL);
                    */
                } /* end if */
            }     /* end if */
        }         /* end if */
    }             /* end for */

    /* Loop once more to figure out the index information */
    for (n = 0, obj_ptr = &obj_ret->raw_obj_arr[0]; n < nobj; n++, obj_ptr++) {
        if (obj_ptr->index == (-1)) { /* first object of this type in the file */
            int32      temp_index = 0;
            objinfo_t *temp_ptr; /* temporary pointer to a working DD object */

            /* the object gets index of 0 */
            obj_ptr->index = 0;

            /* look for other objects of this tag */
            for (m = n, temp_ptr = obj_ptr + 1; m + 1 < nobj; m++, temp_ptr++) {
                if (temp_ptr->tag == obj_ptr->tag)
                    temp_ptr->index = ++temp_index; /* set next index */
            }                                       /* end for */
        }                                           /* end if */
    }                                               /* end for */

    obj_ret->options = options;
    return obj_ret;
} /* end make_dd_list() */

objinfo_t *
get_next_obj(objlist_t *o_list, int advance)
{
    if (advance)
        o_list->curr_obj++;
    if (o_list->curr_obj >= o_list->max_obj)
        return NULL;
    return o_list->srt_obj_arr[o_list->curr_obj];
} /* end get_next_obj() */

objinfo_t *
goto_nth_obj(objlist_t *o_list, int n)
{
    if (n >= 0 && n < o_list->max_obj)
        o_list->curr_obj = n;
    return o_list->srt_obj_arr[o_list->curr_obj];
} /* end goto_nth_obj() */

void
reset_obj_list(objlist_t *o_list)
{
    if (o_list != NULL)
        o_list->curr_obj = 0;
} /* end reset_obj_list() */

void
free_obj_list(objlist_t *o_list)
{
    objinfo_t *obj_ptr; /* temporary pointer to a working DD object */

    if (o_list != NULL) {
        obj_ptr = o_list->raw_obj_arr;
        for (int i = 0; i < o_list->max_obj; i++, obj_ptr++) {
            if (obj_ptr->is_group)
                free_group_list(obj_ptr->group_info);
            if (obj_ptr->is_special)
                free(obj_ptr->spec_info);
        }
        free(o_list->srt_obj_arr);
        free(o_list->raw_obj_arr);
        free(o_list);
    }
    else
        fprintf(stderr, ">>>free_obj_list failed - attempting to free a NULL list \n");
} /* end free_obj_list() */

int
sort_obj_list_by_tag(const void *p1, const void *p2)
{
    const objinfo_t *a = (const objinfo_t *)*((const void *const *)p1);
    const objinfo_t *b = (const objinfo_t *)*((const void *const *)p2);

    if (a->tag > b->tag)
        return 1;
    if (a->tag < b->tag)
        return -1;
    if (a->ref > b->ref)
        return 1;
    if (a->ref < b->ref)
        return -1;
    return 0;
} /* end sort_obj_info_by_tag() */

void
sort_obj_list(objlist_t *o_list, sort_t sort_type)
{
    switch (sort_type) {
        case OGROUP: /* sort by group order */
            break;   /* not currently implemented */

        case OTAG: /* sort by tag order */
            qsort(o_list->srt_obj_arr, (size_t)o_list->max_obj, sizeof(objinfo_t *), sort_obj_list_by_tag);
            break;

        case OFILE: /* sort by file order */
        default:
            break;
    }
} /* end sort_obj_list() */

/* Misc. utility functions */
int
int32_compare(const void *a, const void *b)
{
    if (*(const int32 *)a > *(const int32 *)b)
        return 1;
    else if (*(const int32 *)a < *(const int32 *)b)
        return -1;
    else
        return 0;
} /* end int32_compare() */

void
sort(int32 *chosen, int32 choices)
{
    qsort((void *)chosen, (size_t)choices, sizeof(int32), int32_compare);
}

/* resetBuff frees the passed-in pointer and resets it to NULL,
 * if it is not NULL.  Its purpose is to make cleaning up simpler
 * throughout the hdp code
 */
void
resetBuff(void **ptr)
{
    free(*ptr);
    *ptr = NULL;
}

/* parse_number_opts take a list of numbers separated by commas then
 * retrieves the numbers and stores them in the structure provided by
 * the caller.  This routine is used by all the routines
 * parse_dumpxx_opts to parse the index or ref list that accompanies
 * option -i or -r
 */
void
parse_number_opts(char *argv[], int *curr_arg, number_filter_t *filter)
{
    int32  numItems = 0, i;
    char  *tempPtr  = NULL;
    char  *ptr      = NULL;
    int32 *newlist;

    /* put a temp ptr at the beginning of the given list of numbers,
       separated by commas, for example, 1,2,3 */
    ptr = argv[*curr_arg];

    /* check if it's the end of the command */
    if (ptr == NULL) {
        printf("Missing values for option\n");
        exit(1);
    }

    /* then traverse the list and count the number of items in it */
    while ((tempPtr = strchr(ptr, ',')) != NULL) {
        numItems++;        /* count number of items in the list */
        ptr = tempPtr + 1; /* forward pointer to next item, after a comma */
    }                      /* end while */
    if (*ptr != '\0')      /* count the last item */
        numItems++;

    if (filter->num_list != NULL) {
        /* Update number of items that will be in the list */
        numItems = numItems + filter->num_items;

        /* Allocate a new list */
        newlist = (int32 *)calloc((size_t)numItems, sizeof(int));
        CHECK_ALLOC(newlist, "newlist", "parse_number_opts");

        /* If filter->num_list is already allocated, transfer pointers over
           to the new list and deallocate the old list of pointers */
        if (filter->num_list != NULL) {
            for (i = 0; i < filter->num_items; i++)
                newlist[i] = filter->num_list[i];
            free(filter->num_list);
        }

        /* Set _cdfs to the new list */
        filter->num_list = newlist;
        newlist          = NULL;
    }

    else {
        /* allocate space to hold all the items in the list */
        filter->num_list = (int32 *)calloc((size_t)numItems, sizeof(int));
        CHECK_ALLOC(filter->num_list, "filter->num_list", "parse_number_opts");
    }

    /* go back to the beginning of the list and read in the numbers */
    ptr = argv[*curr_arg];
    i   = 0; /* index of the list */
    while (i < numItems) {
        tempPtr = strchr(ptr, ',');
        if (tempPtr != NULL)
            *tempPtr = '\0';             /* end the string of digits */
        filter->num_list[i] = atoi(ptr); /* convert string to digits */
        ptr                 = tempPtr + 1;
        i++;
    }
    filter->num_items = numItems; /* save the number of items */
} /* parse_number_opts */

/* parse_string_opts take a list of strings separated by commas then
 * retrieves the strings and stores them in the structure provided by
 * the caller.  This routine is used by all the routines
 * parse_dumpxx_opts to parse the name or class list that accompanies
 * option -n or -c
 */
void
parse_string_opts(char *argv[], int *curr_arg, char_filter_t *filter)
{
    int32 numItems = 0, i;
    char *tempPtr  = NULL;
    char *ptr      = NULL;

    /* put a temp pointer at the beginning of the list of strings,
       separated by commas */
    ptr = argv[*curr_arg];

    /* check if it's the end of the command */
    if (ptr == NULL) {
        printf("Missing values for option\n");
        exit(1);
    }

    /* then traverse the list and count the number of strings in it */
    while ((tempPtr = strchr(ptr, ',')) != NULL) {
        numItems++;
        ptr = tempPtr + 1;
    }                 /* end while */
    if (*ptr != '\0') /* count the last item */
        numItems++;

    /* allocate space to hold pointers that will point to the given strings */
    filter->str_list = (char **)calloc((size_t)numItems, sizeof(char *));
    CHECK_ALLOC(filter->str_list, "filter->str_list", "parse_string_opts");

    /* go back to the beginning of the list and read in the given strings */
    ptr = argv[*curr_arg];
    i   = 0; /* init the index of the list */
    while (i < numItems) {
        tempPtr = strchr(ptr, ','); /* find the end of a string */
        if (tempPtr != NULL)
            *tempPtr = '\0'; /* end the string with a NULL char */

        /* allocate space for each string */
        filter->str_list[i] = (char *)malloc(sizeof(char) * (strlen(ptr) + 1));
        CHECK_ALLOC(filter->str_list[i], "filter->str_list[i]", "parse_string_opts");
        strcpy(filter->str_list[i], ptr); /* get the current string */
        ptr = tempPtr + 1;                /* move pointer to next item or end of list */
        i++;
    } /* end while */

    filter->num_items = numItems; /* save the number of items */

} /* parse_string_opts */

void
init_obj_chosen_node(obj_chosen_t *aNode)
{
    aNode->index        = -1;
    aNode->refnum       = -1;
    aNode->name         = NULL;
    aNode->classname    = NULL;
    aNode->type_of_info = INVALID;
}

void
parse_value_opts(char *argv[], int *curr_arg, dump_info_t **dump_opts, info_type_t info_type)
{
    int32         numItems = 0, i;
    char         *tempPtr  = NULL;
    char         *ptr      = NULL;
    obj_chosen_t *newlist  = NULL;

    /* put a temp ptr at the beginning of the given list of numbers,
       separated by commas, for example, 1,2,3 */
    ptr = argv[*curr_arg];

    /* check if it's the end of the command */
    if (ptr == NULL) {
        printf("Missing values for option\n");
        exit(1);
    }

    /* then traverse the list and count the number of items in it */
    while ((tempPtr = strchr(ptr, ',')) != NULL) {
        numItems++;        /* count number of items in the list */
        ptr = tempPtr + 1; /* forward pointer to next item, after a comma */
    }                      /* end while */
    if (*ptr != '\0')      /* count the last item */
        numItems++;

    if ((*dump_opts)->all_types != NULL) {
        /* Update number of chosen SDSs so far */
        int32 newItems = numItems + (*dump_opts)->num_chosen;

        /* Allocate a new list */
        newlist = (obj_chosen_t *)calloc((size_t)newItems, sizeof(obj_chosen_t));
        CHECK_ALLOC(newlist, "newlist", "parse_value_opts");

        /* transfer pointers from (*dump_opts)->all_types over to the new list
           and deallocate the old list of pointers */
        for (i = 0; i < (*dump_opts)->num_chosen; i++)
            newlist[i] = (*dump_opts)->all_types[i];
        for (i = (*dump_opts)->num_chosen; i < newItems; i++)
            init_obj_chosen_node(&newlist[i]);

        free((*dump_opts)->all_types);
        /* Set (*dump_opts)->all_types to the new list */
        (*dump_opts)->all_types = newlist;
        numItems                = newItems;
        newlist                 = NULL;
    }
    else {
        /* allocate space to hold all the items in the list */
        (*dump_opts)->all_types = (obj_chosen_t *)calloc((size_t)numItems, sizeof(obj_chosen_t));
        CHECK_ALLOC((*dump_opts)->all_types, "filter", "parse_value_opts");

        /* Initialize all nodes */
        for (i = 0; i < numItems; i++)
            init_obj_chosen_node(&(*dump_opts)->all_types[i]);
    }

    /* go back to the beginning of the list and read in the numbers */
    ptr = argv[*curr_arg];

    /* index of the list, it should start at 0 or at the number of SDSs chosen so far */
    i = (*dump_opts)->num_chosen != NO_SPECIFIC ? (*dump_opts)->num_chosen : 0;
    while (i < numItems) {
        tempPtr = strchr(ptr, ',');
        if (tempPtr != NULL)
            *tempPtr = '\0'; /* end the string of digits */
        switch (info_type) {
            case IS_INDEX:
                /* convert the string of characters to digits and store for refnum */
                (*dump_opts)->all_types[i].index = atoi(ptr);
                break;

            case IS_REFNUM:
                /* convert the string of characters to digits and store for refnum */
                (*dump_opts)->all_types[i].refnum = atoi(ptr);
                break;

            case IS_NAME:
                /* get the current string of characters for name */
                (*dump_opts)->all_types[i].name = (char *)malloc(sizeof(char) * (strlen(ptr) + 1));
                CHECK_ALLOC((*dump_opts)->all_types[i].name, "(*dump_opts)->all_types[i].name",
                            "parse_string_opts");
                strcpy((*dump_opts)->all_types[i].name, ptr);
                break;

            case IS_CLASS:
                /* get the current string of characters for class name */
                (*dump_opts)->all_types[i].classname = (char *)malloc(sizeof(char) * (strlen(ptr) + 1));
                CHECK_ALLOC((*dump_opts)->all_types[i].classname, "(*dump_opts)->all_types[i].classname",
                            "parse_string_opts");
                strcpy((*dump_opts)->all_types[i].classname, ptr);
                break;

            default:
                /* shouldn't be anything else */
                fprintf(stderr, "Calling function passed in incorrect info_type_t: %d\n", (int)info_type);
                exit(1);
                break;
        } /* end of switch */
        (*dump_opts)->all_types[i].type_of_info = info_type;
        ptr                                     = tempPtr + 1;
        i++;
    }
    (*dump_opts)->num_chosen = numItems; /* save the number of chosen SDSs so far */
} /* parse_value_opts */

/* If there are any specific datasets requested, alloc_index_list
 * allocates space for the list of indices of these requested items
 */
void
alloc_index_list(int32 **index_list, int32 num_chosen)
{
    int32 i = -1;

    *index_list = (int32 *)calloc((size_t)num_chosen, sizeof(int32));
    CHECK_ALLOC(*index_list, "index_list", "alloc_index_list");

    HDmemfill(*index_list, &i, sizeof(int32), (uint32)num_chosen);
} /* end of alloc_index_list */

/* Given a compression type code, returns a character string that
 * indicates that compression method
 */
const char *
comp_method_txt(comp_coder_t comp_type)
{
    switch (comp_type) {
        case COMP_CODE_NONE:
            return ("NONE");
        case COMP_CODE_RLE:
            return ("RLE");
        case COMP_CODE_NBIT:
            return ("NBIT");
        case COMP_CODE_SKPHUFF:
            return ("SKPHUFF");
        case COMP_CODE_DEFLATE:
            return ("DEFLATE");
        case COMP_CODE_SZIP:
            return ("SZIP");
        case COMP_CODE_JPEG:
            return ("JPEG");
        case COMP_CODE_IMCOMP:
            return ("IMCOMP");
        default:
            return ("INVALID");
    }
}
