[comp.lang.lisp.x] UGH! More XLISP bugs, and most are mine :

toma@tekgvs.LABS.TEK.COM (Tom Almy) (11/22/90)

ARGG! After sending out many copies of XLISP recently, I have found
yet another XLISP bug. In the past I fixed many problems handling the
ASCII NUL character in strings caused mainly by indescriminate use of
the C string library. Well last night I found another one when I
attempted to use READ-LINE to read a text file with embedded NULLs.


And if that wasn't bad enough, I discovered errors in my own new and
modified functions. Coerce wouldn't coerce NIL into an array or
string (should coerce into #() and "" respectively). The remove
functions on lists failed if :start and :end were other than the
complete list.  The delete functions on lists were totally messed up.
(Sorry for all of this, the last two errors were generated when I was
fixing things for proper operation with 16 bit integer compilers).

A lousy way to start the holiday season :-(

=======================

To fix xcoerce (in xlsys.c) change

    oldtype = ntype(arg);

to

    oldtype = (arg==NIL? CONS: ntype(arg));

======================

To fix remif() in xlseq.c, change the case CONS: to

        case CONS:{
            long s=start, l=end-start;
            for (; consp(seq); seq = cdr(seq)) {
                        /* check to see if this element should be deleted */
                /* force copy if count, as specified by end, is exhausted */
                if (s-- > 0 || l-- <= 0 || 
                    (expr?dotest2(x,car(seq),fcn)
                    :dotest1(car(seq),fcn)) != tresult) {
                    next = consa(car(seq));
                    if (val) rplacd(last,next);
                    else val = next;
                    last = next;
                }
            }
        }
        break;


(I declared and initialized s and l inside the for loop. A bad mistake!)

=======================

Replacement code for the case CONS: in delif() in file xlseq.c:

        case CONS:
            end -= start; /* gives length */
            /* delete leading matches, only if start is 0 */
            if (start == 0)
                while (consp(seq) && end > 0) {
                    end--;
                    if ((expr?dotest2(x,car(seq),fcn)
                        :dotest1(car(seq),fcn)) != tresult)
                            break;
                    seq = cdr(seq);
                }

            val = last = seq;

            /* delete embedded matches */
            if (consp(seq) && end > 0) {

                /* skip the first non-matching element, start == 0 */
                if (start == 0) seq = cdr(seq);

                /* skip first elements if start > 0, correct "last" */
                for (;consp(seq) && start-- > 0;last=seq, seq=cdr(seq));

                /* look for embedded matches */
                while (consp(seq) && end-- > 0) {

                    /* check to see if this element should be deleted */
                    if ((expr?dotest2(x,car(seq),fcn)
                        :dotest1(car(seq),fcn)) == tresult)
                        rplacd(last,cdr(seq));
                    else
                        last = seq;

                    /* move to the next element */
                    seq = cdr(seq);
                }
            }
            break;


=======================

Here, in its entirety, is the fixed and tested version of xreadline().


/* xreadline - read a line from a file */
LVAL xreadline()
{
    char buf[STRMAX+1],*p,*sptr;
    LVAL fptr,str,newstr;
    int len,blen,ch;

    /* protect some pointers */
    xlsave1(str);

    /* get file pointer */
    fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin));
    xllastarg();

    /* get character and check for eof */
    len = blen = 0; p = buf;
    while ((ch = xlgetc(fptr)) != EOF && ch != '\n') {

        /* check for buffer overflow TAA MOD to use memcpy instead of strcat*/
        if (blen >= STRMAX) {
            newstr = newstring(len + STRMAX + 1);
            sptr = getstring(newstr);
            if (str) memcpy((char *)sptr, (char *)getstring(str), len);
            memcpy((char *)sptr+len, (char *)buf, blen);
            p = buf; blen = 0;
            len += STRMAX;
            str = newstr;
        }

        /* store the character */
        *p++ = ch; ++blen;
    }

    /* check for end of file */
    if (len == 0 && p == buf && ch == EOF) {
        xlpop();
        return (NIL);
    }

    /* append the last substring */
    /* conditional removed because always true! TAA MOD*/
    /* changed to use memcpy instead of strcat TAA MOD */
    newstr = newstring(len + blen + 1);
    sptr = getstring(newstr);
    if (str) memcpy((char *)sptr, (char *)getstring(str), len);
    memcpy((char *)sptr+len, (char *)buf, blen);
    sptr[len+blen] = '\0';
    str = newstr;

    /* restore the stack */
    xlpop();

    /* return the string */
    return (str);
}



Enjoy!

Tom Almy
toma@tekgvs.labs.tek.com
Standard Disclaimers Apply