/*
 * test strtol ++jrb and michal jaegermann
 *
 */

#include <stdio.h>
#include <errno.h>
extern int errno;

#if __STDC__
#include <stdlib.h>
#include <limits.h>
#else
extern long strtol();
#define const /* */
#define LONG_MAX 2147483647L
#define LONG_MIN (-2147483648L)
#endif

#ifndef OK
#define OK 0
#endif

#ifndef EXIT_FAILURE
#define EXIT_FAILURE 1
#endif

#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#endif

struct test {
  const char	*string;	/* the string 		*/
  long		val;		/* expected result 	*/
  int		err;		/* expected errno 	*/
  int		endp;		/* index of expected end ptr	*/
} tests [] = {
  { "0",		0L,		OK,      1	 },
  { "-12345",		-12345L,	OK,      6	 },
  { "12345",		12345L,		OK,      5	 },
  { "-0x12345",		-0x12345L,	OK,      8	 },
  { "0x12345",		0x12345L,	OK,      7	 },
  { "-012345",		-012345L,	OK,      7	 },
  { "012345",		012345L,	OK,      6	 },
  { "10]",	     	 10L,		OK,      2	 },
					         
  { "2147483645L",	2147483645L,	OK,      10	 },
  { "2147483646L",	2147483646L,	OK,      10	 },
  { "2147483647L",	2147483647L,	OK,      10	 },
  { "2147483648L",	2147483647L,	ERANGE,  10	 },
  { "2147483649L",	2147483647L,	ERANGE,  10	 },
					         
  { "-2147483646L",	-2147483646L,	OK,      11	 },
  { "-2147483647L",	-2147483647L,	OK,      11	 },
  { "-2147483648L",	-2147483648L,	OK,      11	 },
  { "-2147483649L",	-2147483648L,	ERANGE,  11	 },
  { "-2147484648L",	-2147483648L,	ERANGE,  11	 },
					         
  { "       567L",	567L,		OK,      10	 },
  { "\t      567 ",	567L,		OK,      10	 },
  { "      -567]",     -567L,		OK,      10	 },
					         
  { "ZZZZZZ",		  0L,		OK,      0	 },
  { "0xGZZZZZ",		  0L,		OK,      1	 },
  { "08ZZZZZZ",		  0L,		OK,      1	 },
  { "+0x1ZZZZZZ",	  1L,		OK,      4	 },
  { " -07188888",      -071L,		OK,      5	 },
					         
  { " +017777777777+",	LONG_MAX,	OK,      14	 },
  { " +027777777777+",	LONG_MAX,	ERANGE,  14	 },
  { " -017777777777+",	LONG_MIN+1,	OK,      14	 },
  { " -020000000000+",	LONG_MIN,	OK,      14	 },
  { " -037777777777+",	LONG_MIN,	ERANGE,  14	 },
  { "-037777777777+",	LONG_MIN,	ERANGE,  13	 },
  { "037777777777+",	LONG_MAX,	ERANGE,  12	 },
					         
  { ""		    ,          0,       OK,      0	 },
  { "\t\t"	    ,          0,       OK,      0	 },
  { "+"		    ,          0,       OK,      0	 },
  { "-"		    ,          0,       OK,      0	 },
  { NULL,		       0,	OK,      0	 }
};

void fail(i, test, res, err, endp)
int i;
struct test *test;
long res;
int err;
char *endp;
{
    printf("Test %d (\"%s\") failed\n", i, test->string);
    printf("\tExpecting:\t%10ld\t%3d\t%x\n", test->val, test->err,
 &(test->string[(test->endp)]));
    printf("\tGot:\t\t%10ld\t%3d\t%x\n", res, err, endp);
}

int main()
{
    int i, errs = 0;
    long res;
    char *endp;

    for(i = 0; tests[i].string; i++)
    {
	errno = OK;
	res = strtol(tests[i].string, &endp, 0);
	if(res != tests[i].val)
	{
	   fail(i, &tests[i], res, errno, endp);
	   errs++;
	}
	else if(tests[i].err != errno)
	{
	   fail(i, &tests[i], res, errno, endp);
	   errs++;
	}
	else if( &(tests[i].string[(tests[i].endp)]) != endp)
	{
	   fail(i, &tests[i], res, errno, endp);
	   errs++;
	}
    }

    if (errs) printf("%d error(s)\n", errs);
    return errs ?  EXIT_FAILURE : EXIT_SUCCESS;
}
