#  extensive test of externals under various conditions
#
#  Because of externals to printf and puts, which write to the (unshared)
#  stdout buffer, this test cannot be run using multiprocessing on the Sequent.
#  This is disabled by "MPD_PARALLEL=0" in the Script file.

resource e ()
    optype stoi (string[*] s) returns int  i
    type timeval = rec (int sec, usec)
    type timezone = rec (int minw, dst)

    external func3 (int n) returns int v
    external func5 (int n) returns int v
    external func7 (int n) returns int v

    external stoi atoi
    external ctime (ptr int t)                         returns string[26] s
    external fprintf (file f, string[*] s, int v)
    external fputc (char c, file f)                   returns char  r
    external fputs (ptr char p, file f)
    external getenv (string[*] s)                      returns string[5] v
    external gettimeofday (res timeval tv, res timezone tz)
    external mktemp (var string[*] path)
    external printf (char c[*])
    external puts (string[*] s)
    external sprintf (res string[*] s, string[*] fmt, int v)
    external system (string[*] s)
    external time (ptr int t)                          returns int  n


    string[100] s
    char c, ca[1:10]
    int  t1, t2, n
    timeval tv
    timezone tz

    write("begin external test")

    # test simple int functions (these are mainly here to test mpdl)
    write(func3(19))
    write(func5(17))
    write(func7(13))

    # test file, string, and int arguments
    fprintf(stdout,"1988 in octal is %6o\n",1988)

    # test "ptr int" argument, and int return value
    t1 = 1
    t2 = 2
    t1 = time(@t2)
    if (t1 ~= t2 | t1 < 979000000 | t1 > 1300000000) {    # valid ~2001 - ~2011
	write("time is wrong: t1 =",t1,"  t2 =",t2)
    } else {
	write("time looks plausible")
    }

    # test that records are passed by reference
    gettimeofday(tv,tz)         # assume this happens no more than 5 sec later
    n = tv.sec - t1
    if (n < 0 or n > 5) {
	write("gettimeofday: sec =",tv.sec,"  usec = ",tv.usec,"  vs. t1 =",t1)
    } else {
	write("gettimeofday agrees")
    }

    # test ptr char and char array
    ca = chars("fputs ok\n\0")
    fputs(@ca[1],stdout)
    ca = chars("& printf \0")
    printf(ca)
    printf(chars("is too\n\0"))

    # test char argument, char return value
    c = 'y'
    writes("fputc(c,stdout): ")
    c = fputc(c,stdout)
    write(" => returned",c)
    writes("fputc('x',stdout): ")
    c = fputc('x',stdout)
    write(" => returned",c)

    # test function declared with optype
    write("atoi(\"93481\") =",atoi("93481"))
    s = "11213"
    n = atoi(s)
    writes("atoi(\"",s,"\") = ",n,'\n')

    # test res string argument
    s = "aaddssggddsassggddhhhhggggttgfdsaaddssggddsassggddhhhhggggttgggg"
    sprintf (s, "hex value is =(%x)=", 12345678x)
    write (s)

    # test var string argument
    s = "TEMPXXXXXX\0 this extra stuff inits a different string length"
    mktemp(s)
    if (length(s) != 10 | s[1:4] != "TEMP" | s[6:7] == "XX") {
	write("mktemp returned", s)
    } else {
	write("mktemp worked")
    }

    # test string valued function
    s = "ggkghhggdgkghhggdgkjjhhggfdgssssggaassaagdsassaaggaaasdfddssaaaa"
    s = ctime(@t1)
    if (length(s) != 25 | s[14] != ':' | s[25] != '\n') {
	writes("ctime(",t1,") returned \"(",s,"\"\n")
    } else {
	write("ctime worked")
    }

    # test string valued function returning NULL
    s = "zyxwvutsrqponmlkjihgfedcba"
    s = getenv("no-such-thing")
    writes("getenv(nonexistent) returned \"",s,"\"\n")

    # test truncation of return value from string function
    s = getenv("PATH")         # we assume PATH will be longer than 5!
    if (length(s) != 5) {
	write("PATH is",s)
    } else {
	write("getenv result truncated successfully")
    }
    write()

    # Now test the passing of string parameters in detail.  Besides testing that
    # the null character '\0' gets stored correctly, we'll try to verify that
    # sizes are big enough for the null to fit without stomping anything else.

    string[4] s4
    string[5] s5
    string[6] s6
    string[7] s7               # "worst case" -- no slop else null kills s8
    string[8] s8
    char  c5[1:5]

    s4 = "abcd"                # init all strings at maximum possible length
    s5 = "efghi"
    s6 = "jklmno"
    s7 = "pqrstuv"
    s8 = "wxyz0123"
    write(s4,s5,s6,s7,s8)       # dump them out to check
    puts(s4)                    # each call should insert a null
    puts(s5)
    puts(s6)
    puts(s7)
    puts(s8)
    write(s4,s5,s6,s7,s8)       # make sure the nulls didn't stomp anything

    # now shorten the strings and try again to be sure the nulls really
    # do get placed correctly.
    s4 = "in"
    s5 = "the"
    s6 = "east"
    s7 = "river"
    s8 = "garden"
    write(s4,s5,s6,s7,s8)
    puts(s4)
    puts(s5)
    puts(s6)
    puts(s7)
    puts(s8)
    write(s4,s5,s6,s7,s8)

    # try with other than string variables as arguments
    puts("23456789TJQKA")
    c5 = chars("aeiou")
    puts(string(c5))
    write(char(42))

    # test system call
    flush(stdout)
    system("echo *.mpd *.c")

    # all done
    write("done")

end
