/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#include "hdf.h"
#include "mfhdf.h"

#include "hdiff.h"

/*
 * convert pathname of netcdf file into name for cdl unit, by taking
 * last component of path and stripping off any extension.
 */
char *
name_path(char *path)
{
    char *cp, *newc;

#ifdef MSDOS
#define FILE_DELIMITER '\\'
#endif
#ifndef FILE_DELIMITER /* default to unix */
#define FILE_DELIMITER '/'
#endif
    cp = strrchr(path, FILE_DELIMITER);
    if (cp == 0) /* no delimiter */
        cp = path;
    else /* skip delimiter */
        cp++;
    newc = (char *)malloc((unsigned)(strlen(cp) + 1));
    if (newc == 0) {
        fprintf(stderr, "Out of memory!\n");
        exit(EXIT_FAILURE);
    }
    (void)strcpy(newc, cp); /* copy last component of path */
    if ((cp = strrchr(newc, '.')) != NULL)
        *cp = '\0'; /* strip off any extension */
    return newc;
}

const char *
type_name(nc_type type)
{
    switch (type) {
        case DFNT_INT8:
            return "byte";
        case DFNT_CHAR:
            return "char";
        case DFNT_INT16:
            return "short";
        case DFNT_INT32:
            return "long";
        case DFNT_FLOAT:
            return "float";
        case DFNT_DOUBLE:
            return "double";
        default:
            fprintf(stderr, "type_name: bad type %d", type);
            return "bogus";
    }
}

/*
 * Remove trailing zeros (after decimal point) but not trailing decimal
 * point from ss, a string representation of a floating-point number that
 * might include an exponent part.
 */
void
tztrim(char *ss)
/* returned string representing dd */
{
    char *cp, *ep;

    cp = ss;
    if (*cp == '-')
        cp++;
    while (isdigit((int)*cp) || *cp == '.')
        cp++;
    if (*--cp == '.')
        return;
    ep = cp + 1;
    while (*cp == '0')
        cp--;
    cp++;
    if (cp == ep)
        return;
    while (*ep)
        *cp++ = *ep++;
    *cp = '\0';
    return;
}

/*
 * Print list of attribute values.  Attribute values must be printed with
 * explicit type tags, because their types are not declared.
 */
void
pr_att_vals(nc_type type, int len, void *vals)
{
    int iel;
    union {
        char    *cp;
        int16   *sp;
        int32   *lp;
        float32 *fp;
        float64 *dp;
    } gp;
    char         *sp;
    unsigned char uc;
    char          gps[30]; /* for ascii of a float or double precision */
    const char   *f_fmt = "%#.8g";
    const char   *d_fmt = "%#.16g";

    switch (type) {
        case DFNT_INT8:
            gp.cp = (char *)vals;
            for (iel = 0; iel < len; iel++)
                if (isprint(uc = *gp.cp++ & 0377))
                    printf("'%c'%s", uc, iel < len - 1 ? ", " : "");
                else
                    printf("'\\%o'%s", uc, iel < len - 1 ? ", " : "");
            break;
        case DFNT_CHAR:
            gp.cp = (char *)vals;
            printf("\"");
            /* adjust len so trailing nulls don't get printed */
            sp = gp.cp + len - 1;
            while (*sp-- == '\0' && len > 0)
                len--;
            for (iel = 0; iel < len; iel++)
                switch (uc = *gp.cp++ & 0377) {
                    case '\b':
                        printf("\\b");
                        break;
                    case '\f':
                        printf("\\f");
                        break;
                    case '\n': /* generate linebreaks after new-lines */
                        printf("\\n\",\n    \"");
                        break;
                    case '\r':
                        printf("\\r");
                        break;
                    case '\t':
                        printf("\\t");
                        break;
                    case '\v':
                        printf("\\v");
                        break;
                    case '\\':
                        printf("\\\\");
                        break;
                    case '\'':
                        printf("\\'");
                        break;
                    case '\"':
                        printf("\\\"");
                        break;
                    default:
                        printf("%c", uc);
                        break;
                }
            printf("\"");
            break;
        case DFNT_INT16:
            gp.sp = (int16 *)vals;
            for (iel = 0; iel < len; iel++)
                printf("%ds%s", *gp.sp++, iel < len - 1 ? ", " : "");
            break;
        case DFNT_INT32:
            gp.lp = (int32 *)vals;
            for (iel = 0; iel < len; iel++)
                printf("%d%s", *gp.lp++, iel < len - 1 ? ", " : "");
            break;
        case DFNT_FLOAT:
            gp.fp = (float32 *)vals;
            for (iel = 0; iel < len; iel++) {
                int ll;
                (void)sprintf(gps, f_fmt, (double)*gp.fp++);
                /* append a trailing "f" for floating-point attributes */
                ll          = strlen(gps);
                gps[ll + 1] = '\0';
                gps[ll]     = 'f';
                tztrim(gps); /* trim trailing 0's after '.' */
                printf("%s%s", gps, iel < len - 1 ? ", " : "");
            }
            break;
        case DFNT_DOUBLE:
            gp.dp = (float64 *)vals;
            for (iel = 0; iel < len; iel++) {
                (void)sprintf(gps, d_fmt, *gp.dp++);
                tztrim(gps); /* trim trailing 0's after '.' */
                printf("%s%s", gps, iel < len - 1 ? ", " : "");
            }
            break;
        default:
            fprintf(stderr, "pr_att_vals: bad type - %d", type);
    }
}

void
make_vars(char *optarg, diff_opt_t *opt, int option)
{
    char  *cp    = optarg;
    int    nvars = 1;
    char **cpp;

    /* compute number of variable names in comma-delimited list */
    if (option == 1)
        opt->nlvars = 1;
    else
        opt->nuvars = 1;

    while (*cp++)
        if (*cp == ',')
            nvars++;

    if (option == 1) {
        opt->lvars = (char **)malloc(nvars * sizeof(char *));
        if (!opt->lvars) {
            fprintf(stderr, "Out of memory!\n");
            exit(EXIT_FAILURE);
        }
        cpp = opt->lvars;
    }
    else {
        opt->uvars = (char **)malloc(nvars * sizeof(char *));
        if (!opt->uvars) {
            fprintf(stderr, "Out of memory!\n");
            exit(EXIT_FAILURE);
        }
        cpp = opt->uvars;
    }

    /* copy variable names into list */
    for (cp = strtok(optarg, ","); cp != NULL; cp = strtok((char *)NULL, ",")) {

        *cpp = (char *)malloc(strlen(cp) + 1);
        if (!*cpp) {
            fprintf(stderr, "Out of memory!\n");
            exit(EXIT_FAILURE);
        }
        strcpy(*cpp, cp);
        cpp++;
    }
    if (option == 1)
        opt->nlvars = nvars;
    else
        opt->nuvars = nvars;
}
