diff options
author | Paul Gilbert | 2019-05-17 14:48:01 -1000 |
---|---|---|
committer | Paul Gilbert | 2019-05-24 18:21:06 -0700 |
commit | f607792fa4e1f024dd8265034ac84425bde4aee7 (patch) | |
tree | 19372287bea6cc0b4cbfdc717510cc9419fd9b04 /engines/glk/tads/tads2/line_source_file.cpp | |
parent | 105a1b94bd9d5a0f10752e135671f4e9a4b0d8da (diff) | |
download | scummvm-rg350-f607792fa4e1f024dd8265034ac84425bde4aee7.tar.gz scummvm-rg350-f607792fa4e1f024dd8265034ac84425bde4aee7.tar.bz2 scummvm-rg350-f607792fa4e1f024dd8265034ac84425bde4aee7.zip |
GLK: TADS2: More code files implemented
Diffstat (limited to 'engines/glk/tads/tads2/line_source_file.cpp')
-rw-r--r-- | engines/glk/tads/tads2/line_source_file.cpp | 1037 |
1 files changed, 1037 insertions, 0 deletions
diff --git a/engines/glk/tads/tads2/line_source_file.cpp b/engines/glk/tads/tads2/line_source_file.cpp index 26536c06a4..b5da3d1a3c 100644 --- a/engines/glk/tads/tads2/line_source_file.cpp +++ b/engines/glk/tads/tads2/line_source_file.cpp @@ -21,12 +21,1049 @@ */ #include "glk/tads/tads2/line_source_file.h" +#include "glk/tads/tads2/character_map.h" +#include "glk/tads/tads2/error.h" +#include "glk/tads/tads2/memory_cache_heap.h" +#include "glk/tads/tads2/tokenizer.h" +#include "glk/tads/os_glk.h" namespace Glk { namespace TADS { namespace TADS2 { +/* initialize a pre-allocated linfdef, skipping debugger page setup */ +void linfini2(mcmcxdef *mctx, linfdef *linf, + char *filename, int flen, osfildef *fp, int new_line_records) +{ + /* set up method pointers */ + linf->linflin.lingetp = linfget; + linf->linflin.linclsp = linfcls; + linf->linflin.linppos = linfppos; + linf->linflin.linglop = (new_line_records ? linfglop2 : linfglop); + linf->linflin.linwrtp = linfwrt; + linf->linflin.lincmpp = linfcmp; + linf->linflin.linactp = linfact; + linf->linflin.lindisp = linfdis; + linf->linflin.lintellp = linftell; + linf->linflin.linseekp = linfseek; + linf->linflin.linreadp = linfread; + linf->linflin.linpaddp = linfpadd; + linf->linflin.linqtopp = linfqtop; + linf->linflin.lingetsp = linfgets; + linf->linflin.linnamp = linfnam; + linf->linflin.linlnump = linflnum; + linf->linflin.linfindp = linffind; + linf->linflin.lingotop = linfgoto; + linf->linflin.linofsp = linfofs; + linf->linflin.linrenp = linfren; + linf->linflin.lindelp = linfdelnum; + + /* set up instance data */ + linf->linflin.linbuf = linf->linfbuf; + linf->linflin.linflg = 0; + memcpy(linf->linfnam, filename, (size_t)flen); + linf->linfnam[flen] = '\0'; + linf->linfbuf[0] = '\0'; + linf->linfbufnxt = 0; + linf->linfnxtlen = 0; + linf->linffp = fp; + linf->linfnum = 0; + linf->linflin.linlln = 4; /* OPCLINE operand is seek offset in file */ + linf->linfmem = mctx; /* save memory manager context */ + linf->linfcrec = 0; /* no debugger records written yet */ +} + +/* + * Initialize a file line source object. If must_find_file is true, + * we'll fail if we can't find the file. Otherwise, we'll create the + * linfdef even if we can't find the file, reserving the maximum space + * for its path name to be filled in later. + */ +linfdef *linfini(mcmcxdef *mctx, errcxdef *ec, char *filename, + int flen, tokpdef *path, int must_find_file, + int new_line_records) +{ + int i; + objnum *objp; + linfdef *linf; + osfildef *fp; + char fbuf[OSFNMAX + 1]; + tokpdef fakepath; + int len; + + if (!path) + { + path = &fakepath; + fakepath.tokpnxt = (tokpdef *)0; + fakepath.tokplen = 0; + } + + /* search through the path list */ + for ( ; path ; path = path->tokpnxt) + { + char last; + + /* prefix the current path */ + if ((len = path->tokplen) != 0) + { + memcpy(fbuf, path->tokpdir, (size_t)len); + last = fbuf[len - 1]; + if (last == OSPATHCHAR || + (OSPATHALT && strchr(OSPATHALT, last))) + /* do nothing */ ; + else + { + /* append path separator character */ + fbuf[len++] = OSPATHCHAR; + } + } + + /* add the filename and null-terminate */ + memcpy(fbuf + len, filename, (size_t)flen); + fbuf[len + flen] = '\0'; + + /* attempt to open this file */ + if ((fp = osfoprs(fbuf, OSFTTEXT)) != 0) + break; + } + + /* + * If no file opened yet, search tads path; if that doesn't work, + * let the debugger UI try to find the file. If nothing works, give + * up and return failure. + */ + if (fp == 0 + && (!os_locate(filename, flen, (char *)0, fbuf, sizeof(fbuf)) + || (fp = osfoprs(fbuf, OSFTTEXT)) == 0)) + { + /* + * Ask the debugger UI for advice. If the debugger isn't + * present, we'll get a failure code from this routine. + */ + if (!dbgu_find_src(filename, flen, fbuf, sizeof(fbuf), + must_find_file)) + return 0; + + /* try opening the file */ + if (fbuf[0] == '\0') + { + /* + * we didn't get a filename - the UI wants to defer finding + * the file until later + */ + fp = 0; + } + else + { + /* we got a filename from the UI - try opening it */ + fp = osfoprs(fbuf, OSFTTEXT); + } + + /* + * if the file isn't present, and we're required to find it, + * return failure + */ + if (fp == 0 && must_find_file) + return 0; + } + + /* figure out how much space we need for the file's full name */ + if (fp == 0) + { + /* + * we didn't find the file, so we don't yet know its name - use + * the maximum possible filename length for the buffer size, so + * that we can store the final filename if we should figure out + * where the file is later on + */ + fbuf[0] = '\0'; + len = sizeof(fbuf); + } + else + { + /* + * we found the file, so we have its final name - allocate space + * for the known name + */ + len = (int)strlen(fbuf); + } + + /* allocate the linfdef */ + linf = (linfdef *)mchalo(ec, (ushort)(sizeof(linfdef) + flen + + len + 1), "linfini"); + + /* do the basic initialization */ + linfini2(mctx, linf, filename, flen, fp, new_line_records); + + memcpy(linf->linfnam + flen + 1, fbuf, (size_t)len); + linf->linfnam[flen + 1 + len] = '\0'; + + /* set all debugger pages to not-yet-allocated */ + for (i = LINFPGMAX, objp = linf->linfpg ; i ; ++objp, --i) + *objp = MCMONINV; + + /* return the new line source object */ + return linf; +} + +int linfget(lindef *lin) +{ +# define linf ((linfdef *)lin) + char *p; + size_t rdlen; + int nl_len; + + /* remember seek position of start of current line */ + linf->linfseek = osfpos(linf->linffp); + + /* + * if we have data left in the buffer after the end of this line, + * move it to the start of the buffer + */ + if (linf->linfnxtlen != 0) + { + /* move the data down */ + memmove(linf->linfbuf, linf->linfbuf + linf->linfbufnxt, + linf->linfnxtlen); + + /* + * adjust the seek position to account for the fact that we've + * read ahead in the file + */ + linf->linfseek -= linf->linfnxtlen; + + /* + * Fill up the rest of the buffer. Leave one byte for a null + * terminator and one byte for a possible extra newline pair + * character (see below), hence fill to sizeof(buf)-2. + */ + rdlen = osfrbc(linf->linffp, linf->linfbuf + linf->linfnxtlen, + sizeof(linf->linfbuf) - linf->linfnxtlen - 2); + + /* + * the total space is the amount we had left over plus the + * amount we just read + */ + rdlen += linf->linfnxtlen; + } + else + { + /* + * We have nothing in the buffer - fill it up. Fill to + * sizeof(buf)-2 to leave room for a null terminator plus a + * possible extra newline pair character (see below). + */ + rdlen = osfrbc(linf->linffp, linf->linfbuf, + sizeof(linf->linfbuf) - 2); + } + + /* + * if there's nothing in the buffer at this point, we've reached the + * end of the file + */ + if (rdlen == 0) + return TRUE; + + /* + * if the last line was not a continuation line, increment the line + * counter for the start of a new line + */ + if (!(lin->linflg & LINFMORE)) + ++(linf->linfnum); + + /* null-terminate the buffer contents */ + linf->linfbuf[rdlen] = '\0'; + + /* perform character mapping on th new part only */ + for (p = linf->linfbuf + linf->linfnxtlen ; *p != '\0' ; ++p) + *p = cmap_n2i(*p); + + /* + * scan the for the first newline in the buffer, allowing newline + * conventions that involve either CR or LF + */ + for (p = linf->linfbuf ; *p != '\n' && *p != '\r' && *p != '\0' ; ++p) ; + + /* + * Check to see if this character is followed by its newline pair + * complement, to allow for either CR-LF or LF-CR sequences, as well + * as plain single-byte newline (CR or LF) sequences. + * + * First, though, one weird special case: if this character is at + * the read limit in the buffer, the complementary character might + * be lurking in the next byte that we haven't read. In this case, + * use that one-byte reserve we have left (we filled the buffer only + * to length-2 so far) and read the next byte. + */ + if (*p != '\0' && p + 1 == linf->linfbuf + sizeof(linf->linfbuf) - 2) + { + /* + * we've filled the buffer to but not including the reserve for + * just this case - fetch the extra character + */ + if (osfrbc(linf->linffp, p + 1, 1) == 1) + { + /* increase the total read length for the extra byte */ + ++rdlen; + *(p+2) = '\0'; + } + } + + /* + * now we can check for the newline type, since we have definitely + * read the full paired sequence + */ + if (*p == '\0') + { + /* there's no newline in the buffer - we'll return a partial line */ + nl_len = 0; + + /* set the partial line flag */ + lin->linflg |= LINFMORE; + + /* return the entire buffer */ + lin->linlen = rdlen; + + /* there's nothing left for the next time through */ + linf->linfnxtlen = 0; + } + else + { + /* check for a complementary pair */ + if ((*p == '\n' && *(p+1) == '\r') || (*p == '\r' && *(p+1) == '\n')) + { + /* we have a paired newline */ + nl_len = 2; + } + else + { + /* we have but a single-character newline sequence */ + nl_len = 1; + } + + /* this is the end of a line */ + lin->linflg &= ~LINFMORE; + + /* + * return only the part of the buffer up to, but not including, + * the newline + */ + lin->linlen = (p - linf->linfbuf); + + /* null-terminate the buffer at the newline */ + *p = '\0'; + + /* + * anything remaining after the newline sequence is available + * for reading the next time through + */ + linf->linfbufnxt = ((p + nl_len) - linf->linfbuf); + linf->linfnxtlen = rdlen - linf->linfbufnxt; + } + + /* make sure buffer pointer is correct */ + lin->linbuf = linf->linfbuf; + + LINFDEBUG(printf("%s\n", linf->linfbuf)); + + /* success */ + return FALSE; + +# undef linf +} + +/* make printable string from position in file (for error reporting) */ +void linfppos(lindef *lin, char *buf, uint buflen) +{ + VARUSED(buflen); + + sprintf(buf, "%s(%lu): ", ((linfdef *)lin)->linfnam, + ((linfdef *)lin)->linfnum); +} + +/* close line source */ +void linfcls(lindef *lin) +{ + osfcls(((linfdef *)lin)->linffp); +} + +/* generate operand of OPCLINE (source-line debug) instruction */ +void linfglop(lindef *lin, uchar *buf) +{ + oswp4(buf, ((linfdef *)lin)->linfseek); /* save seek position of line */ +} + +/* generate new-style operand of OPCLINE instruction */ +void linfglop2(lindef *lin, uchar *buf) +{ + oswp4(buf, ((linfdef *)lin)->linfnum); /* save seek position of line */ +} + +/* save line source information to binary (.gam) file; TRUE ==> error */ +int linfwrt(lindef *lin, osfildef *fp) +{ +# define linf ((linfdef *)lin) + uchar buf[UCHAR_MAX + 6]; + size_t len; + uint pgcnt; + uchar *objp; + mcmon *objn; + + buf[0] = lin->linid; + len = strlen(linf->linfnam); + if (len > UCHAR_MAX) + return FALSE; + buf[1] = (uchar)len; + oswp4(buf + 2, linf->linfcrec); + memcpy(buf + 6, linf->linfnam, (size_t)buf[1]); + if (osfwb(fp, buf, (int)(buf[1] + 6))) return(TRUE); + + /* write the debug source pages */ + if (!linf->linfcrec) return(FALSE); /* no debug records at all */ + pgcnt = 1 + ((linf->linfcrec - 1) >> 10); /* figure number of pages */ + + for (objn = linf->linfpg ; pgcnt ; ++objn, --pgcnt) + { + objp = mcmlck(linf->linfmem, *objn); + if (osfwb(fp, objp, (1024 * DBGLINFSIZ))) return(TRUE); + mcmunlck(linf->linfmem, *objn); + } + + return(FALSE); + +# undef linf +} + +/* load a file-line-source from binary (.gam) file */ +int linfload(osfildef *fp, dbgcxdef *dbgctx, errcxdef *ec, tokpdef *path) +{ + linfdef *linf; + uchar buf[UCHAR_MAX + 6]; + uint pgcnt; + uchar *objp; + mcmon *objn; + + /* read the source's description from the file */ + if (osfrb(fp, buf, 6) + || osfrb(fp, buf + 6, (int)buf[1])) + return TRUE; + + /* initialize the linfdef */ + if (!(linf = linfini(dbgctx->dbgcxmem, ec, (char *)buf + 6, + (int)buf[1], path, FALSE, FALSE))) + { + errlog1(ec, ERR_NOSOURC, ERRTSTR, + errstr(ec, (char *)buf+6, (int)buf[1])); + return TRUE; + } + + /* if we opened the file, close it - don't hold all files open */ + if (linf->linffp != 0) + { + osfcls(linf->linffp); + linf->linffp = 0; + } + + /* link into debug line source chain */ + linf->linflin.linnxt = dbgctx->dbgcxlin; + dbgctx->dbgcxlin = &linf->linflin; + linf->linflin.linid = buf[0]; + linf->linfcrec = osrp4(buf + 2); + + /* make sure the max line id is set above current line */ + if (buf[0] >= dbgctx->dbgcxfid) + dbgctx->dbgcxfid = buf[0] + 1; + + /* make sure we have some debug records */ + if (!linf->linfcrec) + return FALSE; + + /* figure number of pages */ + pgcnt = 1 + ((linf->linfcrec - 1) >> 10); + + /* allocate and read the debug source pages */ + for (objn = linf->linfpg ; pgcnt ; ++objn, --pgcnt) + { + objp = mcmalo(linf->linfmem, (ushort)(1024 * DBGLINFSIZ), objn); + if (osfrb(fp, objp, (1024 * DBGLINFSIZ))) return(TRUE); + mcmunlck(linf->linfmem, *objn); + } + + /* success */ + return FALSE; +} + +/* add a debugger line record for the current line being compiled */ +void linfcmp(lindef *lin, uchar *buf) +{ + uint pg; + uchar *objptr; +# define linf ((linfdef *)lin) + + /* figure out which page to use, and lock it */ + pg = linf->linfcrec >> 10; /* 2^10 records per page */ + if (pg >= LINFPGMAX) + errsig(linf->linfmem->mcmcxgl->mcmcxerr, ERR_MANYDBG); + if (linf->linfpg[pg] == MCMONINV) + objptr = mcmalo(linf->linfmem, (ushort)(1024 * DBGLINFSIZ), + &linf->linfpg[pg]); + else + objptr = mcmlck(linf->linfmem, linf->linfpg[pg]); + + /* write the record to the appropriate offset within the page */ + memcpy(objptr + (linf->linfcrec & 1023) * DBGLINFSIZ, buf, + (size_t)DBGLINFSIZ); + + /* increment counter of line records so far */ + ++(linf->linfcrec); + + /* done with page - touch it and unlock it */ + mcmtch(linf->linfmem, linf->linfpg[pg]); + mcmunlck(linf->linfmem, linf->linfpg[pg]); + +# undef linf +} + +/* + * Renumber an existing object. Searches through all line records for + * any with the given object number, and changes the number to the new + * number if found. + */ +void linfren(lindef *lin, objnum oldnum, objnum newnum) +{ +# define linf ((linfdef *)lin) + uint pgcnt; + uchar *objp; + mcmon *pgobjn; + int i; + int pgtot; + int tot; + + /* figure the number of pages - if no lines, stop now */ + tot = linf->linfcrec; + if (tot == 0) + return; + + /* calculate the number of pages to check */ + pgcnt = 1 + ((tot - 1) >> 10); + + /* scan each page */ + for (pgobjn = linf->linfpg ; pgcnt ; ++pgobjn, --pgcnt, tot -= 1024) + { + /* lock the page */ + objp = mcmlck(linf->linfmem, *pgobjn); + + /* figure the number on this page */ + pgtot = (tot > 1024 ? 1024 : tot); + + /* scan each record on this page */ + for (i = 0 ; i < pgtot ; ++i, objp += DBGLINFSIZ) + { + /* check this one */ + if (osrp2(objp) == oldnum) + { + /* it matches - renumber it */ + oswp2(objp, newnum); + } + } + + /* done with the page - touch it and unlock it */ + mcmtch(linf->linfmem, *pgobjn); + mcmunlck(linf->linfmem, *pgobjn); + } + +# undef linf +} + +/* + * Delete an existing object. Searches through all line records for any + * with the given object number, and removes line records for the object + * number if found. + */ +void linfdelnum(lindef *lin, objnum objn) +{ +# define linf ((linfdef *)lin) + uint pgcnt; + uchar *objp; + uchar *objp_orig; + mcmon *pgobjn; + int i; + int pgtot; + int tot; + + /* figure the number of pages - if no lines, stop now */ + tot = linf->linfcrec; + if (tot == 0) + return; + + /* calculate the number of pages to check */ + pgcnt = 1 + ((tot - 1) >> 10); + + /* scan each page */ + for (pgobjn = linf->linfpg ; pgcnt ; ++pgobjn, --pgcnt, tot -= 1024) + { + /* lock the page */ + objp = objp_orig = mcmlck(linf->linfmem, *pgobjn); + + /* figure the number on this page */ + pgtot = (tot > 1024 ? 1024 : tot); + + /* scan each record on this page */ + for (i = 0 ; i < pgtot ; ++i, objp += DBGLINFSIZ) + { + int j; + + /* check this one */ + if (osrp2(objp) == objn) + { + uchar *nxtp; + uint pg; + int delcnt; + int totrem; + + /* + * it matches - delete it, along with any subsequent + * contiguous entries that also match it + */ + for (delcnt = 1, j = i + 1 ; j < pgtot ; ++j, ++delcnt) + { + /* + * if this one doesn't match, we've found the end of + * the contiguous records for this object + */ + if (osrp2(objp + (j - i)*DBGLINFSIZ) != objn) + break; + } + + /* close up the gap on this page */ + if (j < pgtot) + memmove(objp, objp + delcnt*DBGLINFSIZ, + (pgtot - j)*DBGLINFSIZ); + + /* + * if this isn't the last page, copy the bottom of the + * next page to the gap at the top of this page + */ + if (pgcnt > 1) + { + /* lock the next page */ + nxtp = mcmlck(linf->linfmem, *(pgobjn + 1)); + + /* + * copy from the beginning of the next page to the + * end of this page + */ + memcpy(objp_orig + (pgtot - delcnt)*DBGLINFSIZ, + nxtp, delcnt*DBGLINFSIZ); + + /* done with the page */ + mcmunlck(linf->linfmem, *(pgobjn + 1)); + } + else + { + /* + * this is the last page, so there's no next page to + * copy items from - reduce the count of items on + * this page accordingly + */ + pgtot -= delcnt; + } + + /* + * Now rearrange all subsequent pages to accommodate the + * gap we just created + */ + for (totrem = tot, pg = 1 ; pg < pgcnt ; + totrem -= 1024, ++pg) + { + uchar *curp; + int curtot; + + /* figure how many we have on this page */ + curtot = (totrem > 1024 ? 1024 : totrem); + + /* lock this page */ + curp = mcmlck(linf->linfmem, *(pgobjn + pg)); + + /* delete from the start of this page */ + memmove(curp, curp + delcnt*DBGLINFSIZ, + (curtot - delcnt)*DBGLINFSIZ); + + /* if there's another page, copy from it */ + if (pg + 1 < pgcnt) + { + /* lock the next page */ + nxtp = mcmlck(linf->linfmem, *(pgobjn + pg + 1)); + + /* + * copy from the start of the next page to the + * end of this page + */ + memcpy(curp + (curtot - delcnt)*DBGLINFSIZ, + nxtp, delcnt*DBGLINFSIZ); + + /* unlock it */ + mcmunlck(linf->linfmem, *(pgobjn + pg + 1)); + } + + /* done with the page - touch it and unlock it */ + mcmtch(linf->linfmem, *(pgobjn + pg)); + mcmunlck(linf->linfmem, *(pgobjn + pg)); + } + + /* deduct the removed records from the total */ + linf->linfcrec -= delcnt; + } + } + + /* done with the page - touch it and unlock it */ + mcmtch(linf->linfmem, *pgobjn); + mcmunlck(linf->linfmem, *pgobjn); + } + +# undef linf +} + + +/* find the nearest line record to a file seek location */ +void linffind(lindef *lin, char *buf, objnum *objp, uint *ofsp) +{ +# define linf ((linfdef *)lin) + uint pg; + uchar *objptr; + uchar *bufptr; + long first; + long last; + long cur; + ulong seekpos; + ulong curpos = 0; + objnum objn; + uint ofs; + + /* get desired seek position out of buffer */ + seekpos = osrp4(buf); + + /* we haven't traversed any records yet */ + objn = MCMONINV; + ofs = 0; + + /* run a binary search for the indicated line record */ + first = 0; + last = linf->linfcrec - 1; + for (;;) + { + /* make sure we're not out of records entirely */ + if (first > last) + { + /* return the most recent record found - it's closest */ + *objp = objn; + *ofsp = ofs; + + /* set the position to that of the line we actually found */ + oswp4(buf, curpos); + return; + } + + /* split the difference */ + cur = first + (last - first)/2; + + /* calculate the page containing this item */ + pg = cur >> 10; + + /* get object + offset corresponding to current source line */ + objptr = mcmlck(linf->linfmem, linf->linfpg[pg]); + bufptr = objptr + ((cur & 1023) * DBGLINFSIZ); + objn = osrp2(bufptr); + ofs = osrp2(bufptr + 2); + mcmunlck(linf->linfmem, linf->linfpg[pg]); + + /* read user data out of the object's OPCLINE record */ + objptr = mcmlck(linf->linfmem, (mcmon)objn); + bufptr = objptr + ofs + 5; + curpos = osrp4(bufptr); + mcmunlck(linf->linfmem, (mcmon)objn); + + /* see what we have */ + if (curpos == seekpos) + { + *objp = objn; + *ofsp = ofs; + return; + } + else if (curpos < seekpos) + first = (cur == first ? first + 1 : cur); + else + last = (cur == last ? last - 1 : cur); + } + +# undef linf +} + +/* + * copy line records to an array of linfinfo structures + */ +void linf_copy_linerecs(linfdef *linf, struct linfinfo *info) +{ + uint pg; + uint prvpg; + uchar *objptr; + uchar *bufptr; + long last; + long cur; + + /* note the last element */ + last = linf->linfcrec; + + /* if there are no records, there's nothing to do */ + if (last == 0) + return; + + /* load the first page of records */ + prvpg = 0; + pg = 0; + objptr = mcmlck(linf->linfmem, linf->linfpg[0]); + + /* scan the records */ + for (cur = 0 ; cur < last ; ++cur, ++info) + { + uchar *codeptr; + + /* calculate the page containing this item */ + pg = cur >> 10; + + /* if it's different than the last page, load the next page */ + if (pg != prvpg) + { + /* unlock the previous page */ + mcmunlck(linf->linfmem, linf->linfpg[prvpg]); + + /* load the next page */ + objptr = mcmlck(linf->linfmem, linf->linfpg[pg]); + + /* this is now the previous page */ + prvpg = pg; + } + + /* get object + offset corresponding to current source line */ + bufptr = objptr + ((cur & 1023) * DBGLINFSIZ); + info->objn = osrp2(bufptr); + info->ofs = osrp2(bufptr + 2); + + /* read source location data out of the object's OPCLINE record */ + codeptr = mcmlck(linf->linfmem, (mcmon)info->objn); + bufptr = codeptr + info->ofs + 5; + info->fpos = osrp4(bufptr); + mcmunlck(linf->linfmem, (mcmon)info->objn); + } + + /* unlock the last page */ + mcmunlck(linf->linfmem, linf->linfpg[prvpg]); +} + +/* disactivate line source under debugger - close file */ +void linfdis(lindef *lin) +{ +# define linf ((linfdef *)lin) + + if (linf->linffp) + { + osfcls(linf->linffp); + linf->linffp = (osfildef *)0; + } + +# undef linf +} + +/* activate line source under debugger - open file */ +void linfact(lindef *lin) +{ + char *fname; +# define linf ((linfdef *)lin) + + /* get the name buffer, and advance to the full path name portion */ + fname = linf->linfnam; + fname += strlen(fname) + 1; + + /* + * If the full path name is empty, it means that the UI told us to + * defer searching for the file until we actually need the file. At + * this point, we actually need the file. Ask the UI again to find + * the file. + */ + if (fname[0] != '\0' + || dbgu_find_src(linf->linfnam, strlen(linf->linfnam), + fname, OSFNMAX, TRUE)) + { + /* open the file */ + linf->linffp = osfoprs(fname, OSFTTEXT); + } + else + { + /* there's no file to open */ + linf->linffp = 0; + } + +# undef linf +} + +/* get current seek position */ +void linftell(lindef *lin, uchar *pos) +{ +# define linf ((linfdef *)lin) + long seekpos; + + seekpos = osfpos(linf->linffp); + oswp4(pos, seekpos); + +# undef linf +} + +/* seek to a new position */ +void linfseek(lindef *lin, uchar *pos) +{ +# define linf ((linfdef *)lin) + long seekpos; + + seekpos = osrp4(pos); + osfseek(linf->linffp, seekpos, OSFSK_SET); + +# undef linf +} + +/* read bytes - fread-style interface */ +int linfread(lindef *lin, uchar *buf, uint siz) +{ +# define linf ((linfdef *)lin) + + return osfrbc(linf->linffp, buf, siz); + +# undef linf +} + +/* add a signed delta to a seek position */ +void linfpadd(lindef *lin, uchar *pos, long delta) +{ +# define linf ((linfdef *)lin) + long seekpos; + + seekpos = osrp4(pos); + seekpos += delta; + if (seekpos < 0) seekpos = 0; + oswp4(pos, seekpos); + +# undef linf +} + +/* query whether we're at top of file */ +int linfqtop(lindef *lin, uchar *pos) +{ +# define linf ((linfdef *)lin) + + return(osrp4(pos) == 0); + +# undef linf +} + +/* read one line at current position - fgets-style interface */ +int linfgets(lindef *lin, uchar *buf, uint siz) +{ + int ret; + long startpos; + uchar *p; +# define linf ((linfdef *)lin) + + /* note the seek offset at the start of the line */ + startpos = osfpos(linf->linffp); + + /* read the next line */ + ret = (osfgets((char *)buf, siz, linf->linffp) != 0); + if (!ret) + return ret; + + /* scan for non-standard line endings */ + for (p = buf ; *p != '\0' && *p != '\r' && *p != '\n' ; ++p) ; + if (*p != '\0') + { + uchar *nxt; + + /* + * Scan for non-line-ending characters after this line-ending + * character. If we find any, we must have non-standard newline + * conventions in this file. To be tolerant of these, seek back + * to the start of the next line in these cases and read the + * next line from the new location. + */ + for (nxt = p + 1 ; *nxt == '\r' || *nxt == '\n' ; ++nxt) ; + if (*nxt == '\0') + { + /* + * we had only line-ending characters after the first + * line-ending character -- simply end the line after the + * first line-ending character + */ + *(p+1) = '\0'; + } + else + { + /* + * We had a line-ending character in the middle of other + * text, so we must have a file that doesn't conform to + * local newline conventions. Seek back to the next + * character following the last line-ending character so + * that we start the next line here, and end the current + * line after the first line-ending character. + */ + *(p+1) = '\0'; + osfseek(linf->linffp, startpos + (nxt - buf), OSFSK_SET); + } + } + + /* return the result */ + return ret; + +# undef linf +} + +/* get name of line source */ +void linfnam(lindef *lin, char *buf) +{ +# define linf ((linfdef *)lin) + + strcpy(buf, linf->linfnam); + +# undef linf +} + +/* get the current line number */ +ulong linflnum(lindef *lin) +{ +# define linf ((linfdef *)lin) + + return linf->linfnum; + +# undef linf +} + +/* go to top/bottom of line source */ +void linfgoto(lindef *lin, int where) +{ +# define linf ((linfdef *)lin) + + osfseek(linf->linffp, 0L, where); + +# undef linf +} + +/* return current seek offset within source */ +long linfofs(lindef *lin) +{ +# define linf ((linfdef *)lin) + + return(osfpos(linf->linffp)); + +# undef linf +} } // End of namespace TADS2 } // End of namespace TADS |