#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

#define MAXL 32
#define NMAX 64

long xstrtol (char *p, char **ep, int base);
long *realloc_long (long *lp, unsigned long *n);
void prn_stats (long *a, size_t n);

int main (void)
{
    long *array = NULL;             /* ptr to array of long     */
    char buffer[MAXL] = {0};        /* buffer for number string */
    char *ep = buffer;              /* end ptr for strtol       */
    size_t idx = 0;                 /* array index / counter    */
    size_t bidx = 0;                /* buffer index / counter   */
    unsigned long nmax = NMAX;      /* reallocation counter     */
    int c = 0;                      /* variable for getchar()   */

    /* allocate array of NMAX long using calloc to initialize to 0 */
    if (!(array = calloc (NMAX, sizeof *array))) {
        fprintf (stderr, "error: memory allocation failed.");
        return 1;
    }

    /* read each value from csv file into array */
    while ((c = getchar()) != EOF)
    {
        if (c == '-') {                                 /* if sign character    */
            buffer[bidx++] = c;                         /* store, read next c   */
            if ((c = getchar()) == EOF) break;          /* if EOF, done         */
            if (c < '0' || c > '9')                     /* if c not a digit     */
                { bidx = 0; continue; }                 /* reset bidx, continue */
        }
        while (c >= '0' && c <= '9') {                  /* while c is a digit   */
            buffer[bidx++] = c;                         /* add c to buffer      */
            if ((c = getchar()) == EOF) break;          /* read next char       */
        }
        if (bidx) {                                     /* if chars in buffer   */
            buffer[bidx] = 0;                           /* null-terminate       */
            array[idx] = xstrtol (buffer, &ep, 10);     /* convert to long      */
            if (errno == 0) idx++;                      /* if OK, increment idx */
            if (idx == nmax)                            /* check idx == nmax    */
                array = realloc_long (array, &nmax);    /* realloc if required  */
            bidx = 0;                                   /* reset bidx for next  */
        }
    }

    prn_stats (array, idx); /* output min/max/avg.. */

    free (array);           /* free allocated mem   */

    return 0;
}

/*  reallocate array of long values, increase to 2 * '*n'.
 *  returns pointer to newly allocated zeroed block of memory
 *  on success, otherwise program exits. value at 'n' is
 *  updated to reflect the new allocation size.
 */
long *realloc_long (long *lp, unsigned long *n)
{
    long *tmp = realloc (lp, 2 * *n * sizeof *lp);
#ifdef DEBUG
    printf ("  reallocating %lu to %lu\n", *n, *n * 2);
#endif
    if (!tmp) {
        fprintf (stderr, "%s() error: reallocation failed.\n", __func__);
        // return NULL;
        exit (EXIT_FAILURE);
    }
    lp = tmp;
    memset (lp + *n, 0, *n * sizeof *lp); /* memset new ptrs 0 */
    *n *= 2;

    return lp;
}

/*  a simple strtol implementation with error checking.
 *  any failed conversion will cause program exit. Adjust
 *  response to failed conversion as required.
 */
long xstrtol (char *p, char **ep, int base)
{
    errno = 0;

    long tmp = strtol (p, ep, base);

    /* Check for various possible errors */
    if ((errno == ERANGE && (tmp == LONG_MIN || tmp == LONG_MAX)) ||
        (errno != 0 && tmp == 0)) {
        perror ("strtol");
        exit (EXIT_FAILURE);
    }

    if (*ep == p) {
        fprintf (stderr, "No digits were found\n");
        exit (EXIT_FAILURE);
    }

    return tmp;
}

/*  simple output routine for min, max, avg, total and array values
 *  note: the array index output is formatted to 2 places below,
 *  adjust as necessary to meet your needs.
 */
void prn_stats (long *a, size_t n)
{
    long min = (long)(INT_MAX);
    long max = (long)(-INT_MAX - 1);
    long avg = 0;
    long total = 0;
    size_t i = 0;

    /* find min, max, iompute total & average & output */
    for (i = 0; i < n; i++)
    {
        min = a[i] < min ? a[i] : min;
        max = a[i] > max ? a[i] : max;
        total += a[i];
    }

    avg = n > 0 ? total/n : 0;

    printf("\nvalues  : %ld\n", n);
    printf("minimum : %ld\n", min);
    printf("maximum : %ld\n", max);
    printf("total   : %ld\n", total);
    printf("average : %ld\n\n", avg);

    int sf = n > 50 ? n / 50 : 1;  /* scale factor to limit to 50 lines */
    for (i = 0; i < n; i+=sf)
        printf (" a[%2zu] : %ld\n", i, a[i]);
    printf ("\n");
}