cfad47cfa3/t2compiler/tads2/linf.c

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
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
}