~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to tads/tads2/linf.c

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Beucler
  • Date: 2009-09-11 20:09:43 UTC
  • Revision ID: james.westby@ubuntu.com-20090911200943-idgzoyupq6650zpn
Tags: upstream-2009-08-25
ImportĀ upstreamĀ versionĀ 2009-08-25

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifdef RCSID
 
2
static char RCSid[] =
 
3
"$Header: d:/cvsroot/tads/TADS2/LINF.C,v 1.3 1999/07/11 00:46:29 MJRoberts Exp $";
 
4
#endif
 
5
 
 
6
/* 
 
7
 *   Copyright (c) 1991, 2002 Michael J. Roberts.  All Rights Reserved.
 
8
 *   
 
9
 *   Please see the accompanying license file, LICENSE.TXT, for information
 
10
 *   on using and copying this software.  
 
11
 */
 
12
/*
 
13
Name
 
14
  linf.c - line source File implementation
 
15
Function
 
16
  Implementation of file line source
 
17
Notes
 
18
  None
 
19
Modified
 
20
  04/11/99 CNebel        - fix signed/unsigned mismatches
 
21
  04/25/93 JEras         - use new os_locate() to find include files
 
22
  08/14/91 MJRoberts     - creation
 
23
*/
 
24
 
 
25
#include <stdio.h>
 
26
#include <string.h>
 
27
#include <stdlib.h>
 
28
#include <limits.h>
 
29
 
 
30
#include "os.h"
 
31
#include "std.h"
 
32
#include "err.h"
 
33
#include "mch.h"
 
34
#include "tok.h"
 
35
#include "linf.h"
 
36
#include "dbg.h"
 
37
#include "cmap.h"
 
38
 
 
39
/* initialize a pre-allocated linfdef, skipping debugger page setup */
 
40
void linfini2(mcmcxdef *mctx, linfdef *linf,
 
41
              char *filename, int flen, osfildef *fp, int new_line_records)
 
42
{
 
43
    /* set up method pointers */
 
44
    linf->linflin.lingetp = linfget;
 
45
    linf->linflin.linclsp = linfcls;
 
46
    linf->linflin.linppos = linfppos;
 
47
    linf->linflin.linglop = (new_line_records ? linfglop2 : linfglop);
 
48
    linf->linflin.linwrtp = linfwrt;
 
49
    linf->linflin.lincmpp = linfcmp;
 
50
    linf->linflin.linactp = linfact;
 
51
    linf->linflin.lindisp = linfdis;
 
52
    linf->linflin.lintellp = linftell;
 
53
    linf->linflin.linseekp = linfseek;
 
54
    linf->linflin.linreadp = linfread;
 
55
    linf->linflin.linpaddp = linfpadd;
 
56
    linf->linflin.linqtopp = linfqtop;
 
57
    linf->linflin.lingetsp = linfgets;
 
58
    linf->linflin.linnamp = linfnam;
 
59
    linf->linflin.linlnump = linflnum;
 
60
    linf->linflin.linfindp = linffind;
 
61
    linf->linflin.lingotop = linfgoto;
 
62
    linf->linflin.linofsp = linfofs;
 
63
    linf->linflin.linrenp = linfren;
 
64
    linf->linflin.lindelp = linfdelnum;
 
65
 
 
66
    /* set up instance data */
 
67
    linf->linflin.linbuf = linf->linfbuf;
 
68
    linf->linflin.linflg = 0;
 
69
    memcpy(linf->linfnam, filename, (size_t)flen);
 
70
    linf->linfnam[flen] = '\0';
 
71
    linf->linfbuf[0] = '\0';
 
72
    linf->linfbufnxt = 0;
 
73
    linf->linfnxtlen = 0;
 
74
    linf->linffp = fp;
 
75
    linf->linfnum = 0;
 
76
    linf->linflin.linlln = 4;     /* OPCLINE operand is seek offset in file */
 
77
    linf->linfmem = mctx;                    /* save memory manager context */
 
78
    linf->linfcrec = 0;                  /* no debugger records written yet */
 
79
}
 
80
 
 
81
/* 
 
82
 *   Initialize a file line source object.  If must_find_file is true,
 
83
 *   we'll fail if we can't find the file.  Otherwise, we'll create the
 
84
 *   linfdef even if we can't find the file, reserving the maximum space
 
85
 *   for its path name to be filled in later. 
 
86
 */
 
87
linfdef *linfini(mcmcxdef *mctx, errcxdef *ec, char *filename,
 
88
                 int flen, tokpdef *path, int must_find_file,
 
89
                 int new_line_records)
 
90
{
 
91
    int       i;
 
92
    objnum   *objp;
 
93
    linfdef  *linf;
 
94
    osfildef *fp;
 
95
    char      fbuf[OSFNMAX + 1];
 
96
    tokpdef   fakepath;
 
97
    int       len;
 
98
    
 
99
    if (!path)
 
100
    {
 
101
        path = &fakepath;
 
102
        fakepath.tokpnxt = (tokpdef *)0;
 
103
        fakepath.tokplen = 0;
 
104
    }
 
105
 
 
106
    /* search through the path list */
 
107
    for ( ; path ; path = path->tokpnxt)
 
108
    {
 
109
        char last;
 
110
 
 
111
        /* prefix the current path */
 
112
        if ((len = path->tokplen) != 0)
 
113
        {
 
114
            memcpy(fbuf, path->tokpdir, (size_t)len);
 
115
            last = fbuf[len - 1];
 
116
            if (last == OSPATHCHAR ||
 
117
                (OSPATHALT && strchr(OSPATHALT, last)))
 
118
                /* do nothing */ ;
 
119
            else
 
120
            {
 
121
                /* append path separator character */
 
122
                fbuf[len++] = OSPATHCHAR;
 
123
            }
 
124
        }
 
125
 
 
126
        /* add the filename and null-terminate */
 
127
        memcpy(fbuf + len, filename, (size_t)flen);
 
128
        fbuf[len + flen] = '\0';
 
129
        
 
130
        /* attempt to open this file */
 
131
        if ((fp = osfoprs(fbuf, OSFTTEXT)) != 0)
 
132
            break;
 
133
    }
 
134
 
 
135
    /* 
 
136
     *   If no file opened yet, search tads path; if that doesn't work,
 
137
     *   let the debugger UI try to find the file.  If nothing works, give
 
138
     *   up and return failure.  
 
139
     */
 
140
    if (fp == 0
 
141
        && (!os_locate(filename, flen, (char *)0, fbuf, sizeof(fbuf))
 
142
            || (fp = osfoprs(fbuf, OSFTTEXT)) == 0))
 
143
    {
 
144
        /*
 
145
         *   Ask the debugger UI for advice.  If the debugger isn't
 
146
         *   present, we'll get a failure code from this routine. 
 
147
         */
 
148
        if (!dbgu_find_src(filename, flen, fbuf, sizeof(fbuf),
 
149
                           must_find_file))
 
150
            return 0;
 
151
 
 
152
        /* try opening the file */
 
153
        if (fbuf[0] == '\0')
 
154
        {
 
155
            /* 
 
156
             *   we didn't get a filename - the UI wants to defer finding
 
157
             *   the file until later 
 
158
             */
 
159
            fp = 0;
 
160
        }
 
161
        else
 
162
        {
 
163
            /* we got a filename from the UI - try opening it */
 
164
            fp = osfoprs(fbuf, OSFTTEXT);
 
165
        }
 
166
 
 
167
        /* 
 
168
         *   if the file isn't present, and we're required to find it,
 
169
         *   return failure 
 
170
         */
 
171
        if (fp == 0 && must_find_file)
 
172
            return 0;
 
173
    }
 
174
    
 
175
    /* figure out how much space we need for the file's full name */
 
176
    if (fp == 0)
 
177
    {
 
178
        /* 
 
179
         *   we didn't find the file, so we don't yet know its name - use
 
180
         *   the maximum possible filename length for the buffer size, so
 
181
         *   that we can store the final filename if we should figure out
 
182
         *   where the file is later on 
 
183
         */
 
184
        fbuf[0] = '\0';
 
185
        len = sizeof(fbuf);
 
186
    }
 
187
    else
 
188
    {
 
189
        /* 
 
190
         *   we found the file, so we have its final name - allocate space
 
191
         *   for the known name 
 
192
         */
 
193
        len = (int)strlen(fbuf);
 
194
    }
 
195
 
 
196
    /* allocate the linfdef */
 
197
    linf = (linfdef *)mchalo(ec, (ushort)(sizeof(linfdef) + flen
 
198
                                          + len + 1), "linfini");
 
199
 
 
200
    /* do the basic initialization */
 
201
    linfini2(mctx, linf, filename, flen, fp, new_line_records);
 
202
 
 
203
    memcpy(linf->linfnam + flen + 1, fbuf, (size_t)len);
 
204
    linf->linfnam[flen + 1 + len] = '\0';
 
205
    
 
206
    /* set all debugger pages to not-yet-allocated */
 
207
    for (i = LINFPGMAX, objp = linf->linfpg ; i ; ++objp, --i)
 
208
        *objp = MCMONINV;
 
209
 
 
210
    /* return the new line source object */
 
211
    return linf;
 
212
}
 
213
 
 
214
int linfget(lindef *lin)
 
215
{
 
216
#   define  linf ((linfdef *)lin)
 
217
    char   *p;
 
218
    size_t  rdlen;
 
219
    int     nl_len;
 
220
 
 
221
    /* remember seek position of start of current line */
 
222
    linf->linfseek = osfpos(linf->linffp);
 
223
 
 
224
    /*
 
225
     *   if we have data left in the buffer after the end of this line,
 
226
     *   move it to the start of the buffer
 
227
     */
 
228
    if (linf->linfnxtlen != 0)
 
229
    {
 
230
        /* move the data down */
 
231
        memmove(linf->linfbuf, linf->linfbuf + linf->linfbufnxt,
 
232
                linf->linfnxtlen);
 
233
 
 
234
        /* 
 
235
         *   adjust the seek position to account for the fact that we've
 
236
         *   read ahead in the file 
 
237
         */
 
238
        linf->linfseek -= linf->linfnxtlen;
 
239
 
 
240
        /* 
 
241
         *   Fill up the rest of the buffer.  Leave one byte for a null
 
242
         *   terminator and one byte for a possible extra newline pair
 
243
         *   character (see below), hence fill to sizeof(buf)-2.  
 
244
         */
 
245
        rdlen = osfrbc(linf->linffp, linf->linfbuf + linf->linfnxtlen,
 
246
                       sizeof(linf->linfbuf) - linf->linfnxtlen - 2);
 
247
 
 
248
        /* 
 
249
         *   the total space is the amount we had left over plus the
 
250
         *   amount we just read 
 
251
         */
 
252
        rdlen += linf->linfnxtlen;
 
253
    }
 
254
    else
 
255
    {
 
256
        /* 
 
257
         *   We have nothing in the buffer - fill it up.  Fill to
 
258
         *   sizeof(buf)-2 to leave room for a null terminator plus a
 
259
         *   possible extra newline pair character (see below). 
 
260
         */
 
261
        rdlen = osfrbc(linf->linffp, linf->linfbuf,
 
262
                       sizeof(linf->linfbuf) - 2);
 
263
    }
 
264
 
 
265
    /* 
 
266
     *   if there's nothing in the buffer at this point, we've reached the
 
267
     *   end of the file 
 
268
     */
 
269
    if (rdlen == 0)
 
270
        return TRUE;
 
271
 
 
272
    /* 
 
273
     *   if the last line was not a continuation line, increment the line
 
274
     *   counter for the start of a new line 
 
275
     */
 
276
    if (!(lin->linflg & LINFMORE))
 
277
        ++(linf->linfnum);
 
278
 
 
279
    /* null-terminate the buffer contents */
 
280
    linf->linfbuf[rdlen] = '\0';
 
281
 
 
282
    /* perform character mapping on th new part only */
 
283
    for (p = linf->linfbuf + linf->linfnxtlen ; *p != '\0' ; ++p)
 
284
        *p = cmap_n2i(*p);
 
285
 
 
286
    /* 
 
287
     *   scan the for the first newline in the buffer, allowing newline
 
288
     *   conventions that involve either CR or LF 
 
289
     */
 
290
    for (p = linf->linfbuf ; *p != '\n' && *p != '\r' && *p != '\0' ; ++p) ;
 
291
 
 
292
    /*
 
293
     *   Check to see if this character is followed by its newline pair
 
294
     *   complement, to allow for either CR-LF or LF-CR sequences, as well
 
295
     *   as plain single-byte newline (CR or LF) sequences.
 
296
     *   
 
297
     *   First, though, one weird special case: if this character is at
 
298
     *   the read limit in the buffer, the complementary character might
 
299
     *   be lurking in the next byte that we haven't read.  In this case,
 
300
     *   use that one-byte reserve we have left (we filled the buffer only
 
301
     *   to length-2 so far) and read the next byte.  
 
302
     */
 
303
    if (*p != '\0' && p + 1 == linf->linfbuf + sizeof(linf->linfbuf) - 2)
 
304
    {
 
305
        /* 
 
306
         *   we've filled the buffer to but not including the reserve for
 
307
         *   just this case - fetch the extra character 
 
308
         */
 
309
        if (osfrbc(linf->linffp, p + 1, 1) == 1)
 
310
        {
 
311
            /* increase the total read length for the extra byte */
 
312
            ++rdlen;
 
313
            *(p+2) = '\0';
 
314
        }
 
315
    }
 
316
 
 
317
    /* 
 
318
     *   now we can check for the newline type, since we have definitely
 
319
     *   read the full paired sequence 
 
320
     */
 
321
    if (*p == '\0')
 
322
    {
 
323
        /* there's no newline in the buffer - we'll return a partial line */
 
324
        nl_len = 0;
 
325
 
 
326
        /* set the partial line flag */
 
327
        lin->linflg |= LINFMORE;
 
328
 
 
329
        /* return the entire buffer */
 
330
        lin->linlen = rdlen;
 
331
 
 
332
        /* there's nothing left for the next time through */
 
333
        linf->linfnxtlen = 0;
 
334
    }
 
335
    else
 
336
    {
 
337
        /* check for a complementary pair */
 
338
        if ((*p == '\n' && *(p+1) == '\r') || (*p == '\r' && *(p+1) == '\n'))
 
339
        {
 
340
            /* we have a paired newline */
 
341
            nl_len = 2;
 
342
        }
 
343
        else
 
344
        {
 
345
            /* we have but a single-character newline sequence */
 
346
            nl_len = 1;
 
347
        }
 
348
 
 
349
        /* this is the end of a line */
 
350
        lin->linflg &= ~LINFMORE;
 
351
 
 
352
        /* 
 
353
         *   return only the part of the buffer up to, but not including,
 
354
         *   the newline 
 
355
         */
 
356
        lin->linlen = (p - linf->linfbuf);
 
357
 
 
358
        /* null-terminate the buffer at the newline */
 
359
        *p = '\0';
 
360
 
 
361
        /* 
 
362
         *   anything remaining after the newline sequence is available
 
363
         *   for reading the next time through 
 
364
         */
 
365
        linf->linfbufnxt = ((p + nl_len) - linf->linfbuf);
 
366
        linf->linfnxtlen = rdlen - linf->linfbufnxt;
 
367
    }
 
368
 
 
369
    /* make sure buffer pointer is correct */
 
370
    lin->linbuf = linf->linfbuf;
 
371
 
 
372
    LINFDEBUG(printf("%s\n", linf->linfbuf));
 
373
 
 
374
    /* success */
 
375
    return FALSE;
 
376
 
 
377
#   undef  linf
 
378
}
 
379
 
 
380
/* make printable string from position in file (for error reporting) */
 
381
void linfppos(lindef *lin, char *buf, uint buflen)
 
382
{
 
383
    VARUSED(buflen);
 
384
    
 
385
    sprintf(buf, "%s(%lu): ", ((linfdef *)lin)->linfnam,
 
386
            ((linfdef *)lin)->linfnum);
 
387
}
 
388
 
 
389
/* close line source */
 
390
void linfcls(lindef *lin)
 
391
{
 
392
    osfcls(((linfdef *)lin)->linffp);
 
393
}
 
394
 
 
395
/* generate operand of OPCLINE (source-line debug) instruction */
 
396
void linfglop(lindef *lin, uchar *buf)
 
397
{
 
398
    oswp4(buf, ((linfdef *)lin)->linfseek);   /* save seek position of line */
 
399
}
 
400
 
 
401
/* generate new-style operand of OPCLINE instruction */
 
402
void linfglop2(lindef *lin, uchar *buf)
 
403
{
 
404
    oswp4(buf, ((linfdef *)lin)->linfnum);    /* save seek position of line */
 
405
}
 
406
 
 
407
/* save line source information to binary (.gam) file; TRUE ==> error */
 
408
int linfwrt(lindef *lin, osfildef *fp)
 
409
{
 
410
#   define  linf ((linfdef *)lin)
 
411
    uchar   buf[UCHAR_MAX + 6];
 
412
    size_t  len;
 
413
    uint    pgcnt;
 
414
    uchar  *objp;
 
415
    mcmon  *objn;
 
416
 
 
417
    buf[0] = lin->linid;
 
418
    len = strlen(linf->linfnam);
 
419
    if (len > UCHAR_MAX)
 
420
        return FALSE;
 
421
    buf[1] = (uchar)len;
 
422
    oswp4(buf + 2, linf->linfcrec);
 
423
    memcpy(buf + 6, linf->linfnam, (size_t)buf[1]);
 
424
    if (osfwb(fp, buf, (int)(buf[1] + 6))) return(TRUE);
 
425
    
 
426
    /* write the debug source pages */
 
427
    if (!linf->linfcrec) return(FALSE);          /* no debug records at all */
 
428
    pgcnt = 1 + ((linf->linfcrec - 1) >> 10);     /* figure number of pages */
 
429
    
 
430
    for (objn = linf->linfpg ; pgcnt ; ++objn, --pgcnt)
 
431
    {
 
432
        objp = mcmlck(linf->linfmem, *objn);
 
433
        if (osfwb(fp, objp, (1024 * DBGLINFSIZ))) return(TRUE);
 
434
        mcmunlck(linf->linfmem, *objn);
 
435
    }
 
436
    
 
437
    return(FALSE);
 
438
 
 
439
#   undef  linf
 
440
}
 
441
 
 
442
/* load a file-line-source from binary (.gam) file */
 
443
int linfload(osfildef *fp, dbgcxdef *dbgctx, errcxdef *ec, tokpdef *path)
 
444
{
 
445
    linfdef *linf;
 
446
    uchar    buf[UCHAR_MAX + 6];
 
447
    uint     pgcnt;
 
448
    uchar   *objp;
 
449
    mcmon   *objn;
 
450
    
 
451
    /* read the source's description from the file */
 
452
    if (osfrb(fp, buf, 6)
 
453
        || osfrb(fp, buf + 6, (int)buf[1]))
 
454
        return TRUE;
 
455
    
 
456
    /* initialize the linfdef */
 
457
    if (!(linf = linfini(dbgctx->dbgcxmem, ec, (char *)buf + 6,
 
458
                         (int)buf[1], path, FALSE, FALSE)))
 
459
    {
 
460
        errlog1(ec, ERR_NOSOURC, ERRTSTR,
 
461
                errstr(ec, (char *)buf+6, (int)buf[1]));
 
462
        return TRUE;
 
463
    }
 
464
    
 
465
    /* if we opened the file, close it - don't hold all files open */
 
466
    if (linf->linffp != 0)
 
467
    {
 
468
        osfcls(linf->linffp);
 
469
        linf->linffp = 0;
 
470
    }
 
471
    
 
472
    /* link into debug line source chain */
 
473
    linf->linflin.linnxt = dbgctx->dbgcxlin;
 
474
    dbgctx->dbgcxlin = &linf->linflin;
 
475
    linf->linflin.linid = buf[0];
 
476
    linf->linfcrec = osrp4(buf + 2);
 
477
    
 
478
    /* make sure the max line id is set above current line */
 
479
    if (buf[0] >= dbgctx->dbgcxfid)
 
480
        dbgctx->dbgcxfid = buf[0] + 1;
 
481
    
 
482
    /* make sure we have some debug records */
 
483
    if (!linf->linfcrec)
 
484
        return FALSE;
 
485
 
 
486
    /* figure number of pages */
 
487
    pgcnt = 1 + ((linf->linfcrec - 1) >> 10);
 
488
    
 
489
    /* allocate and read the debug source pages */
 
490
    for (objn = linf->linfpg ; pgcnt ; ++objn, --pgcnt)
 
491
    {
 
492
        objp = mcmalo(linf->linfmem, (ushort)(1024 * DBGLINFSIZ), objn);
 
493
        if (osfrb(fp, objp, (1024 * DBGLINFSIZ))) return(TRUE);
 
494
        mcmunlck(linf->linfmem, *objn);
 
495
    }
 
496
 
 
497
    /* success */
 
498
    return FALSE;
 
499
}
 
500
 
 
501
/* add a debugger line record for the current line being compiled */
 
502
void linfcmp(lindef *lin, uchar *buf)
 
503
{
 
504
    uint    pg;
 
505
    uchar  *objptr;
 
506
#   define  linf ((linfdef *)lin)
 
507
 
 
508
    /* figure out which page to use, and lock it */
 
509
    pg = linf->linfcrec >> 10;                     /* 2^10 records per page */
 
510
    if (pg >= LINFPGMAX)
 
511
        errsig(linf->linfmem->mcmcxgl->mcmcxerr, ERR_MANYDBG);
 
512
    if (linf->linfpg[pg] == MCMONINV)
 
513
        objptr = mcmalo(linf->linfmem, (ushort)(1024 * DBGLINFSIZ),
 
514
                        &linf->linfpg[pg]);
 
515
    else
 
516
        objptr = mcmlck(linf->linfmem, linf->linfpg[pg]);
 
517
    
 
518
    /* write the record to the appropriate offset within the page */
 
519
    memcpy(objptr + (linf->linfcrec & 1023) * DBGLINFSIZ, buf,
 
520
           (size_t)DBGLINFSIZ);
 
521
    
 
522
    /* increment counter of line records so far */
 
523
    ++(linf->linfcrec);
 
524
    
 
525
    /* done with page - touch it and unlock it */
 
526
    mcmtch(linf->linfmem, linf->linfpg[pg]);
 
527
    mcmunlck(linf->linfmem, linf->linfpg[pg]);
 
528
    
 
529
#   undef linf
 
530
}
 
531
 
 
532
/*
 
533
 *   Renumber an existing object.  Searches through all line records for
 
534
 *   any with the given object number, and changes the number to the new
 
535
 *   number if found.  
 
536
 */
 
537
void linfren(lindef *lin, objnum oldnum, objnum newnum)
 
538
{
 
539
#   define  linf ((linfdef *)lin)
 
540
    uint    pgcnt;
 
541
    uchar  *objp;
 
542
    mcmon  *pgobjn;
 
543
    int     i;
 
544
    int     pgtot;
 
545
    int     tot;
 
546
 
 
547
    /* figure the number of pages - if no lines, stop now */
 
548
    tot = linf->linfcrec;
 
549
    if (tot == 0)
 
550
        return;
 
551
 
 
552
    /* calculate the number of pages to check */
 
553
    pgcnt = 1 + ((tot - 1) >> 10);
 
554
 
 
555
    /* scan each page */
 
556
    for (pgobjn = linf->linfpg ; pgcnt ; ++pgobjn, --pgcnt, tot -= 1024)
 
557
    {
 
558
        /* lock the page */
 
559
        objp = mcmlck(linf->linfmem, *pgobjn);
 
560
 
 
561
        /* figure the number on this page */
 
562
        pgtot = (tot > 1024 ? 1024 : tot);
 
563
 
 
564
        /* scan each record on this page */
 
565
        for (i = 0 ; i < pgtot ; ++i, objp += DBGLINFSIZ)
 
566
        {
 
567
            /* check this one */
 
568
            if (osrp2(objp) == oldnum)
 
569
            {
 
570
                /* it matches - renumber it */
 
571
                oswp2(objp, newnum);
 
572
            }
 
573
        }
 
574
 
 
575
        /* done with the page - touch it and unlock it */
 
576
        mcmtch(linf->linfmem, *pgobjn);
 
577
        mcmunlck(linf->linfmem, *pgobjn);
 
578
    }
 
579
 
 
580
#   undef  linf
 
581
}
 
582
 
 
583
/*
 
584
 *   Delete an existing object.  Searches through all line records for any
 
585
 *   with the given object number, and removes line records for the object
 
586
 *   number if found.  
 
587
 */
 
588
void linfdelnum(lindef *lin, objnum objn)
 
589
{
 
590
#   define  linf ((linfdef *)lin)
 
591
    uint    pgcnt;
 
592
    uchar  *objp;
 
593
    uchar  *objp_orig;
 
594
    mcmon  *pgobjn;
 
595
    int     i;
 
596
    int     pgtot;
 
597
    int     tot;
 
598
 
 
599
    /* figure the number of pages - if no lines, stop now */
 
600
    tot = linf->linfcrec;
 
601
    if (tot == 0)
 
602
        return;
 
603
 
 
604
    /* calculate the number of pages to check */
 
605
    pgcnt = 1 + ((tot - 1) >> 10);
 
606
 
 
607
    /* scan each page */
 
608
    for (pgobjn = linf->linfpg ; pgcnt ; ++pgobjn, --pgcnt, tot -= 1024)
 
609
    {
 
610
        /* lock the page */
 
611
        objp = objp_orig = mcmlck(linf->linfmem, *pgobjn);
 
612
 
 
613
        /* figure the number on this page */
 
614
        pgtot = (tot > 1024 ? 1024 : tot);
 
615
 
 
616
        /* scan each record on this page */
 
617
        for (i = 0 ; i < pgtot ; ++i, objp += DBGLINFSIZ)
 
618
        {
 
619
            int j;
 
620
            
 
621
            /* check this one */
 
622
            if (osrp2(objp) == objn)
 
623
            {
 
624
                uchar *nxtp;
 
625
                uint pg;
 
626
                int delcnt;
 
627
                int totrem;
 
628
                
 
629
                /* 
 
630
                 *   it matches - delete it, along with any subsequent
 
631
                 *   contiguous entries that also match it 
 
632
                 */
 
633
                for (delcnt = 1, j = i + 1 ; j < pgtot ; ++j, ++delcnt)
 
634
                {
 
635
                    /* 
 
636
                     *   if this one doesn't match, we've found the end of
 
637
                     *   the contiguous records for this object 
 
638
                     */
 
639
                    if (osrp2(objp + (j - i)*DBGLINFSIZ) != objn)
 
640
                        break;
 
641
                }
 
642
 
 
643
                /* close up the gap on this page */
 
644
                if (j < pgtot)
 
645
                    memmove(objp, objp + delcnt*DBGLINFSIZ,
 
646
                            (pgtot - j)*DBGLINFSIZ);
 
647
 
 
648
                /* 
 
649
                 *   if this isn't the last page, copy the bottom of the
 
650
                 *   next page to the gap at the top of this page 
 
651
                 */
 
652
                if (pgcnt > 1)
 
653
                {
 
654
                    /* lock the next page */
 
655
                    nxtp = mcmlck(linf->linfmem, *(pgobjn + 1));
 
656
 
 
657
                    /* 
 
658
                     *   copy from the beginning of the next page to the
 
659
                     *   end of this page 
 
660
                     */
 
661
                    memcpy(objp_orig + (pgtot - delcnt)*DBGLINFSIZ,
 
662
                           nxtp, delcnt*DBGLINFSIZ);
 
663
 
 
664
                    /* done with the page */
 
665
                    mcmunlck(linf->linfmem, *(pgobjn + 1));
 
666
                }
 
667
                else
 
668
                {
 
669
                    /* 
 
670
                     *   this is the last page, so there's no next page to
 
671
                     *   copy items from - reduce the count of items on
 
672
                     *   this page accordingly 
 
673
                     */
 
674
                    pgtot -= delcnt;
 
675
                }
 
676
 
 
677
                /*
 
678
                 *   Now rearrange all subsequent pages to accommodate the
 
679
                 *   gap we just created 
 
680
                 */
 
681
                for (totrem = tot, pg = 1 ; pg < pgcnt ;
 
682
                     totrem -= 1024, ++pg)
 
683
                {
 
684
                    uchar *curp;
 
685
                    int curtot;
 
686
 
 
687
                    /* figure how many we have on this page */
 
688
                    curtot = (totrem > 1024 ? 1024 : totrem);
 
689
                    
 
690
                    /* lock this page */
 
691
                    curp = mcmlck(linf->linfmem, *(pgobjn + pg));
 
692
 
 
693
                    /* delete from the start of this page */
 
694
                    memmove(curp, curp + delcnt*DBGLINFSIZ,
 
695
                            (curtot - delcnt)*DBGLINFSIZ);
 
696
 
 
697
                    /* if there's another page, copy from it */
 
698
                    if (pg + 1 < pgcnt)
 
699
                    {
 
700
                        /* lock the next page */
 
701
                        nxtp = mcmlck(linf->linfmem, *(pgobjn + pg + 1));
 
702
 
 
703
                        /* 
 
704
                         *   copy from the start of the next page to the
 
705
                         *   end of this page 
 
706
                         */
 
707
                        memcpy(curp + (curtot - delcnt)*DBGLINFSIZ,
 
708
                               nxtp, delcnt*DBGLINFSIZ);
 
709
 
 
710
                        /* unlock it */
 
711
                        mcmunlck(linf->linfmem, *(pgobjn + pg + 1));
 
712
                    }
 
713
 
 
714
                    /* done with the page - touch it and unlock it */
 
715
                    mcmtch(linf->linfmem, *(pgobjn + pg));
 
716
                    mcmunlck(linf->linfmem, *(pgobjn + pg));
 
717
                }
 
718
 
 
719
                /* deduct the removed records from the total */
 
720
                linf->linfcrec -= delcnt;
 
721
            }
 
722
        }
 
723
 
 
724
        /* done with the page - touch it and unlock it */
 
725
        mcmtch(linf->linfmem, *pgobjn);
 
726
        mcmunlck(linf->linfmem, *pgobjn);
 
727
    }
 
728
 
 
729
#   undef  linf
 
730
}
 
731
 
 
732
 
 
733
/* find the nearest line record to a file seek location */
 
734
void linffind(lindef *lin, char *buf, objnum *objp, uint *ofsp)
 
735
{
 
736
#   define  linf ((linfdef *)lin)
 
737
    uint    pg;
 
738
    uchar  *objptr;
 
739
    uchar  *bufptr;
 
740
    long    first;
 
741
    long    last;
 
742
    long    cur;
 
743
    ulong   seekpos;
 
744
    ulong   curpos;
 
745
    objnum  objn;
 
746
    uint    ofs;
 
747
 
 
748
    /* get desired seek position out of buffer */
 
749
    seekpos = osrp4(buf);
 
750
 
 
751
    /* we haven't traversed any records yet */
 
752
    objn = MCMONINV;
 
753
    ofs = 0;
 
754
    
 
755
    /* run a binary search for the indicated line record */
 
756
    first = 0;
 
757
    last = linf->linfcrec - 1;
 
758
    for (;;)
 
759
    {
 
760
        /* make sure we're not out of records entirely */
 
761
        if (first > last)
 
762
        {
 
763
            /* return the most recent record found - it's closest */
 
764
            *objp = objn;
 
765
            *ofsp = ofs;
 
766
 
 
767
            /* set the position to that of the line we actually found */
 
768
            oswp4(buf, curpos);
 
769
            return;
 
770
        }
 
771
 
 
772
        /* split the difference */
 
773
        cur = first + (last - first)/2;
 
774
 
 
775
        /* calculate the page containing this item */
 
776
        pg = cur >> 10;
 
777
        
 
778
        /* get object + offset corresponding to current source line */
 
779
        objptr = mcmlck(linf->linfmem, linf->linfpg[pg]);
 
780
        bufptr = objptr + ((cur & 1023) * DBGLINFSIZ);
 
781
        objn = osrp2(bufptr);
 
782
        ofs = osrp2(bufptr + 2);
 
783
        mcmunlck(linf->linfmem, linf->linfpg[pg]);
 
784
 
 
785
        /* read user data out of the object's OPCLINE record */
 
786
        objptr = mcmlck(linf->linfmem, (mcmon)objn);
 
787
        bufptr = objptr + ofs + 5;
 
788
        curpos = osrp4(bufptr);
 
789
        mcmunlck(linf->linfmem, (mcmon)objn);
 
790
 
 
791
        /* see what we have */
 
792
        if (curpos == seekpos)
 
793
        {
 
794
            *objp = objn;
 
795
            *ofsp = ofs;
 
796
            return;
 
797
        }
 
798
        else if (curpos < seekpos)
 
799
            first = (cur == first ? first + 1 : cur);
 
800
        else
 
801
            last = (cur == last ? last - 1 : cur);
 
802
    }
 
803
    
 
804
#   undef linf
 
805
}
 
806
 
 
807
/* 
 
808
 *   copy line records to an array of linfinfo structures 
 
809
 */
 
810
void linf_copy_linerecs(linfdef *linf, struct linfinfo *info)
 
811
{
 
812
    uint    pg;
 
813
    uint    prvpg;
 
814
    uchar  *objptr;
 
815
    uchar  *bufptr;
 
816
    long    last;
 
817
    long    cur;
 
818
 
 
819
    /* note the last element */
 
820
    last = linf->linfcrec;
 
821
 
 
822
    /* if there are no records, there's nothing to do */
 
823
    if (last == 0)
 
824
        return;
 
825
 
 
826
    /* load the first page of records */
 
827
    prvpg = 0;
 
828
    pg = 0;
 
829
    objptr = mcmlck(linf->linfmem, linf->linfpg[0]);
 
830
 
 
831
    /* scan the records */
 
832
    for (cur = 0 ; cur < last ; ++cur, ++info)
 
833
    {
 
834
        uchar *codeptr;
 
835
        
 
836
        /* calculate the page containing this item */
 
837
        pg = cur >> 10;
 
838
 
 
839
        /* if it's different than the last page, load the next page */
 
840
        if (pg != prvpg)
 
841
        {
 
842
            /* unlock the previous page */
 
843
            mcmunlck(linf->linfmem, linf->linfpg[prvpg]);
 
844
 
 
845
            /* load the next page */
 
846
            objptr = mcmlck(linf->linfmem, linf->linfpg[pg]);
 
847
 
 
848
            /* this is now the previous page */
 
849
            prvpg = pg;
 
850
        }
 
851
            
 
852
        /* get object + offset corresponding to current source line */
 
853
        bufptr = objptr + ((cur & 1023) * DBGLINFSIZ);
 
854
        info->objn = osrp2(bufptr);
 
855
        info->ofs = osrp2(bufptr + 2);
 
856
 
 
857
        /* read source location data out of the object's OPCLINE record */
 
858
        codeptr = mcmlck(linf->linfmem, (mcmon)info->objn);
 
859
        bufptr = codeptr + info->ofs + 5;
 
860
        info->fpos = osrp4(bufptr);
 
861
        mcmunlck(linf->linfmem, (mcmon)info->objn);
 
862
    }
 
863
 
 
864
    /* unlock the last page */
 
865
    mcmunlck(linf->linfmem, linf->linfpg[prvpg]);
 
866
}
 
867
 
 
868
/* disactivate line source under debugger - close file */
 
869
void linfdis(lindef *lin)
 
870
{
 
871
#   define linf ((linfdef *)lin)
 
872
 
 
873
    if (linf->linffp)
 
874
    {
 
875
        osfcls(linf->linffp);
 
876
        linf->linffp = (osfildef *)0;
 
877
    }
 
878
    
 
879
#   undef linf
 
880
}
 
881
 
 
882
/* activate line source under debugger - open file */
 
883
void linfact(lindef *lin)
 
884
{
 
885
    char   *fname;
 
886
#   define  linf ((linfdef *)lin)
 
887
 
 
888
    /* get the name buffer, and advance to the full path name portion */
 
889
    fname = linf->linfnam;
 
890
    fname += strlen(fname) + 1;
 
891
 
 
892
    /*
 
893
     *   If the full path name is empty, it means that the UI told us to
 
894
     *   defer searching for the file until we actually need the file.  At
 
895
     *   this point, we actually need the file.  Ask the UI again to find
 
896
     *   the file. 
 
897
     */
 
898
    if (fname[0] != '\0'
 
899
        || dbgu_find_src(linf->linfnam, strlen(linf->linfnam),
 
900
                         fname, OSFNMAX, TRUE))
 
901
    {
 
902
        /* open the file */
 
903
        linf->linffp = osfoprs(fname, OSFTTEXT);
 
904
    }
 
905
    else
 
906
    {
 
907
        /* there's no file to open */
 
908
        linf->linffp = 0;
 
909
    }
 
910
 
 
911
#   undef linf
 
912
}
 
913
 
 
914
/* get current seek position */
 
915
void linftell(lindef *lin, uchar *pos)
 
916
{
 
917
#   define  linf ((linfdef *)lin)
 
918
    long    seekpos;
 
919
 
 
920
    seekpos = osfpos(linf->linffp);
 
921
    oswp4(pos, seekpos);
 
922
 
 
923
#   undef linf
 
924
}
 
925
 
 
926
/* seek to a new position */
 
927
void linfseek(lindef *lin, uchar *pos)
 
928
{
 
929
#   define  linf ((linfdef *)lin)
 
930
    long    seekpos;
 
931
    
 
932
    seekpos = osrp4(pos);
 
933
    osfseek(linf->linffp, seekpos, OSFSK_SET);
 
934
 
 
935
#   undef linf
 
936
}
 
937
 
 
938
/* read bytes - fread-style interface */
 
939
int linfread(lindef *lin, uchar *buf, uint siz)
 
940
{
 
941
#   define  linf ((linfdef *)lin)
 
942
 
 
943
    return osfrbc(linf->linffp, buf, siz);
 
944
 
 
945
#   undef linf
 
946
}
 
947
 
 
948
/* add a signed delta to a seek position */
 
949
void linfpadd(lindef *lin, uchar *pos, long delta)
 
950
{
 
951
#   define  linf ((linfdef *)lin)
 
952
    long    seekpos;
 
953
 
 
954
    seekpos = osrp4(pos);
 
955
    seekpos += delta;
 
956
    if (seekpos < 0) seekpos = 0;
 
957
    oswp4(pos, seekpos);
 
958
 
 
959
#   undef linf
 
960
}
 
961
 
 
962
/* query whether we're at top of file */
 
963
int linfqtop(lindef *lin, uchar *pos)
 
964
{
 
965
#   define  linf ((linfdef *)lin)
 
966
 
 
967
    return(osrp4(pos) == 0);
 
968
 
 
969
#   undef linf
 
970
}
 
971
 
 
972
/* read one line at current position - fgets-style interface */
 
973
int linfgets(lindef *lin, uchar *buf, uint siz)
 
974
{
 
975
    int    ret;
 
976
    long   startpos;
 
977
    uchar *p;
 
978
#   define  linf ((linfdef *)lin)
 
979
 
 
980
    /* note the seek offset at the start of the line */
 
981
    startpos = osfpos(linf->linffp);
 
982
 
 
983
    /* read the next line */
 
984
    ret = (osfgets((char *)buf, siz, linf->linffp) != 0);
 
985
    if (!ret)
 
986
        return ret;
 
987
 
 
988
    /* scan for non-standard line endings */
 
989
    for (p = buf ; *p != '\0' && *p != '\r' && *p != '\n' ; ++p) ;
 
990
    if (*p != '\0')
 
991
    {
 
992
        uchar *nxt;
 
993
        
 
994
        /* 
 
995
         *   Scan for non-line-ending characters after this line-ending
 
996
         *   character.  If we find any, we must have non-standard newline
 
997
         *   conventions in this file.  To be tolerant of these, seek back
 
998
         *   to the start of the next line in these cases and read the
 
999
         *   next line from the new location. 
 
1000
         */
 
1001
        for (nxt = p + 1 ; *nxt == '\r' || *nxt == '\n' ; ++nxt) ;
 
1002
        if (*nxt == '\0')
 
1003
        {
 
1004
            /* 
 
1005
             *   we had only line-ending characters after the first
 
1006
             *   line-ending character -- simply end the line after the
 
1007
             *   first line-ending character 
 
1008
             */
 
1009
            *(p+1) = '\0';
 
1010
        }
 
1011
        else
 
1012
        {
 
1013
            /*
 
1014
             *   We had a line-ending character in the middle of other
 
1015
             *   text, so we must have a file that doesn't conform to
 
1016
             *   local newline conventions.  Seek back to the next
 
1017
             *   character following the last line-ending character so
 
1018
             *   that we start the next line here, and end the current
 
1019
             *   line after the first line-ending character. 
 
1020
             */
 
1021
            *(p+1) = '\0';
 
1022
            osfseek(linf->linffp, startpos + (nxt - buf), OSFSK_SET);
 
1023
        }
 
1024
    }
 
1025
 
 
1026
    /* return the result */
 
1027
    return ret;
 
1028
 
 
1029
#   undef linf
 
1030
}
 
1031
 
 
1032
/* get name of line source */
 
1033
void linfnam(lindef *lin, char *buf)
 
1034
{
 
1035
#   define  linf ((linfdef *)lin)
 
1036
 
 
1037
    strcpy(buf, linf->linfnam);
 
1038
 
 
1039
#   undef linf
 
1040
}
 
1041
 
 
1042
/* get the current line number */
 
1043
ulong linflnum(lindef *lin)
 
1044
{
 
1045
#   define  linf ((linfdef *)lin)
 
1046
 
 
1047
    return linf->linfnum;
 
1048
 
 
1049
#   undef linf
 
1050
}
 
1051
 
 
1052
/* go to top/bottom of line source */
 
1053
void linfgoto(lindef *lin, int where)
 
1054
{
 
1055
#   define  linf ((linfdef *)lin)
 
1056
 
 
1057
    osfseek(linf->linffp, 0L, where);
 
1058
 
 
1059
#   undef linf
 
1060
}
 
1061
 
 
1062
/* return current seek offset within source */
 
1063
long linfofs(lindef *lin)
 
1064
{
 
1065
#   define linf ((linfdef *)lin)
 
1066
 
 
1067
    return(osfpos(linf->linffp));
 
1068
    
 
1069
#   undef  linf
 
1070
}