!MOD.BAS
       ! EXPERIMENTAL VERSION USING INVUE.SBR
       MAP1 KEYLIN(20),S,80            ! STRING TO SEARCH FOR STORAGE
       MAP1 DATLIN,S,200                       ! STRING FROM DISK FILE
       MAP1 SUBLIN(20),S,200           ! SUBSTITUTE STRING FOR KEYLIN(X)
       MAP1 MESAG,S,80                 ! ERROR MESSAGE VARIABLE
       MAP1 FILNUM,F,6,1                       ! NUMBER OF LAST FILE MODDED
       MAP1 MATCH(20),F,6                      ! MATCH FLAG ARRAY FOR
       ! KEYLIN(X)
       MAP1 FSPEC$,S,30                        ! DISK FILE SPECIFICATION
       MAP1 TEMP$,S,200                        ! TEMPORARY STORAGE
       MAP1 TEMP2$,S,200                       ! DITTO
       MAP1 TEMP3$,S,200
       MAP1 OLDFSPEC$,S,30             ! OLD FILE NAME STORAGE
       MAP1 LINNUM,S,5
       MAP1 OPENR                      ! FILE OPEN FLAGS
               MAP2 OPEN1,F,6
               MAP2 OPEN2,F,6
               MAP2 OPEN3,F,6
               MAP2 OPEN4,F,6
               MAP2 OPEN'FLAG(20),F,6
       MAP1 FLAG,F,6                   ! FLAGS RNAME ERROR
       MAP1 PRTDEV,S,30                        ! PRINT-OUT DEVICE NAME
       MAP1 DEVNUM,F,6,0                       ! PRINT OUT DEVICE NUMBER
       MAP1 TRUE,F,6,-1                        ! LOGICAL TRUE
       MAP1 FALSE,F,6                  ! LOGICAL FALSE
       MAP1 STARTLIN,F,6                       ! STARTING INSERT LINE NUMBER
       MAP1 LASTLIN,F,6                        ! ENDING INSERT LINE NUMBER
       MAP1 LINENO$,S,6                        ! NEW LINE NUMBER IN STRING FORM
       MAP1 MASK,S,6,"######"          ! LINE # FORMATTER
       MAP1 MODE(2),S,6
       MAP1 MD,F,6,1                           ! MODE INDEX 1=STRING,2=BLOCK
420     MODE(1)="STRING"
430     MODE(2)="BLOCK"

       MAP1 INVUE'PARMS
               MAP2 LOCAL'EDIT,F,6,0   ! INVUE FLAG
               MAP2 LENGTH,B,2
               MAP2 FLAGS,B,2,15391
               MAP2 EMODE,B,2,0
               MAP2 CHAR,S,2,"_"
       MAP1 WORK'STRING,S,200
       MAP1 SAVE'STRING,S,200


530 MOD:
540     ONLYONE=FALSE
550        FOR I=1 TO 20
560        MATCH(I)=FALSE
570        NEXT I
580     OPEN1=FALSE
590     OPEN2=FALSE
600     OPEN3=FALSE
610     OPEN4=FALSE
620     ? TAB(-1,0);"FILE MODIFIER PROGRAM";
630     ? TAB(12,20);
640     INPUT LINE "ALL USER PROMPTS GO TO (CR for screen) filename=",PRTDEV
650     IF PRTDEV="" THEN DEVNUM=0 : GOTO LINUM
660     DEVNUM=14
670     OPEN #DEVNUM,PRTDEV,OUTPUT
680 LINUM:
690 MENU:
700     ?TAB(2,1);TAB(-1,10);"Global editor menu"
710     ?
720     ?TAB(6,30);"1. Find and substitute lines of text"
730     ?TAB(8,30);"2. Find and substitute MAP statements"
740     ?TAB(10,30);"3. Global string search"
!   750 ?TAB(12,30);"4. Global editor with key search"
760     ?TAB(12,30);"4. EXIT"
770     ?TAB(18,30);
780     INPUT "      Enter (1-5) ",MENU
790     ON MENU GOTO ONELINESUB,BLOCKSUB,LOOK,EXIT

810 BAD'NEWS:
820     PRINT TAB(23,1);MESAG+" -CR TO CONTINUE";
830     INPUT LINE "",TEMP$
840     GOTO MENU
850 GLOBEDIT:
860     LOCAL'EDIT=TRUE

   ONELINESUB:

880     ! SUSTITUTE ONLY SUBSETS OF SINGLE LINES
890     SUBFLAG = NOT(LOCAL'EDIT)
900     !GETFILES OPENS LIST OF FILES AND/OR GETS FIRST FILENAME
910     CALL GETFILES
920     IF FSPEC$="" THEN MESAG="FILE NOT FOUND" :GOTO BAD'NEWS
930     CALL GET'KEYS
940     IF KEYMAX=0 THEN MESAG="NO STRING" : GOTO BAD'NEWS
950 FILELOOP:
960     CALL SEARCH1 !READS FILE FOR KEYS IN KEYLIN FOR MATCH
970     IF FOUND GOTO MODIFY'FILE
980     CALL BUMP'LIST
990     GOTO FILELOOP !TRY NEXT FILE
1000
1010 MODIFY'FILE:
1020    ? #DEVNUM, "modifying ";FSPEC$
1030    OPEN #2,FSPEC$,INPUT
1040    OPEN2=TRUE
1050    OLDFSPEC$=FSPEC$
1060    DOTPOS=INSTR(1,FSPEC$,".")
1070    BRACK= INSTR(1,FSPEC$,"[")
1080    IF BRACK<>0 THEN PPN$=FSPEC[BRACK,-1] ELSE PPN$=""
1090    IF DOTPOS=0 ? #DEVNUM "SPECIFICATION ERROR- NO FILE EXTENSION" :STOP
1100    FSPEC$=FSPEC$[1,DOTPOS]+"TMP"+PPN$
1110    OPEN #3,FSPEC$,OUTPUT
1120    OPEN3=TRUE
1130 MODLOOP:
1140    INPUT LINE #2,DATLIN
1150    IF EOF(2) GOTO MODEXIT
       CHANGED = FALSE
1160       FOR J=1 TO KEYMAX
1170       CALL SCANIT
1190       NEXT J
1440    IF CHANGED THEN ? #DEVNUM, "new-";DATLIN
1450    IF CHANGED AND DEVNUM<>0 THEN ? "new-";DATLIN
1200    IF (LOCAL'EDIT) AND EMODE = 4 THEN CALL EDIT'LINE
1210    ?#3,DATLIN
1220    GOTO MODLOOP

1240 SCANIT:
1250    MODPOS = 1
1270 CHECK'AGAIN:
1280    POS3=INSTR(MODPOS,DATLIN,KEYLIN(J))
1290    IF POS3=0 GOTO END'SCANIT
1300    ! FORCE EDIT OF LINE IF KEY MATCH OCCURS
1310    IF (LOCAL'EDIT) THEN EMODE=4 : RETURN
1320    IF CHANGED GOTO SKIP'OLD
1330    ? #DEVNUM, "old-";DATLIN
1340    IF DEVNUM<>0 THEN ? "old-";DATLIN
1350    CHANGED = TRUE
1360 SKIP'OLD:
1370    OLDLEN=LEN(KEYLIN(J))
1380    TEMP$=DATLIN[POS3+OLDLEN,-1]
1390    TEMP3$=DATLIN[1,POS3-1] : IF POS3=1 THEN TEMP3$=""
1400    DATLIN=TEMP3$+SUBLIN(J)+TEMP$
1410    MODPOS = (POS3-1+LEN(SUBLIN(J)) MAX 1)
1420    GOTO CHECK'AGAIN
1430 END'SCANIT:
1460    RETURN

1470 EDIT'LINE:
1480    LENGTH = LEN(DATLIN)
1490    WORK'STRING = DATLIN
1500    ! IF LINE < 79 CHARS, SIMPLE-JUST INVUE AND RETURN
1510    IF LENGTH < 79 THEN CALL DOIT : GOTO END'EDIT
1520    ! SPLIT LINE INTO TWO SMALLER ONES, ALLOW EDITING,
1530    ! AND THEN CONCATENATE THEM AND RETURN
1540    ? "Splitting line into two smaller lines...."
1550    POS5 = 70
1560 SEARCH'BREAK:
1570    POS5 = POS5 -1
1580    IF POS5 < 1 THEN POS5 = 70 : GOTO DO'FIRST
1590    IF ASC(DATLIN[POS5,POS5]) <> 32 GOTO SEARCH'BREAK
1600 DO'FIRST:
1610    WORK'STRING = DATLIN[1,POS5]
1620    CALL DOIT       ! EDIT FIRST PART
1630    SAVE'STRING = WORK'STRING
1640    WORK'STRING = DATLIN[POS5+1,-1]
1650    CALL DOIT       ! EDIT LAST PART
1660    IF EMODE=3 GOTO DO'FIRST
1670    WORK'STRING = SAVE'STRING + WORK'STRING
1680 END'EDIT:
1690    IF EMODE = 5 THEN EMODE = 1 : GOTO SKIP'UPDATE
1700    DATLIN = WORK'STRING
1710 SKIP'UPDATE:
1720    RETURN
1730 DOIT:
1740    CALL UNTAB
1750    PRINT : PRINT TAB(-1,9);
1760    LENGTH = 79
1770    XCALL INVUE,LENGTH,WORK'STRING,FLAGS,CHAR,EMODE
1780    CALL RETAB
1790    RETURN
1800
1810 UNTAB:
1820    POS4 = INSTR(1,WORK'STRING,CHR$(9))
1830    IF POS4 <> 0 THEN WORK'STRING[POS4,POS4] = "|" : GOTO UNTAB
1840    RETURN
1850 RETAB:
1860    POS4 = INSTR(1,WORK'STRING,"|")
1870    IF POS4 <> 0 THEN WORK'STRING[POS4,POS4] = CHR$(9) : GOTO RETAB
1880    RETURN
1890
1900 MODEXIT:
1910    IF OPEN2 THEN CLOSE #2 : OPEN2=FALSE
1920    IF OPEN3 THEN CLOSE #3 : OPEN3=FALSE
1930    ? #DEVNUM, FSPEC$;" to ";OLDFSPEC$
1940    KILL OLDFSPEC$
1950    XCALL RENAME,FSPEC$,OLDFSPEC$,FLAG
1960    IF FLAG#0 ? #DEVNUM, "ERROR IN RENAME",FLAG:STOP
1970    CALL BUMP'LIST
1980    GOTO FILELOOP

    BLOCKSUB:

2010    ? TAB(12,20)
2020    INPUT LINE "GENERATE LINE NUMBERS (N/Y) ? ",Q$
2030    SUPRESS= (Q$[1,1] <>"Y")
2040    MD=2
2050    SUBFLAG=TRUE
2060    !GET FILENAME OF NEW BLOCK AND COUNT THE NUMBER OF LINES IN IT
2070    CALL GETFILES
2080    IF FSPEC$="" THEN MESAG="NO BLOCK FILE?" :GOTO BAD'NEWS
2090    CALL GET'KEYS
2100    IF KEYMAX=0 THEN MESAG="NO SEARCH KEY?" : GOTO BAD'NEWS
2110    CALL OPEN'BLOCKS
2120
2130 BLOCK'LOOP:
2140
2150    CALL SEARCH1
2160    IF FOUND GOTO BLOCKMOD
2170    CALL BUMP'LIST
2180    IF EOF(1) GOTO FIN
2190    GOTO BLOCK'LOOP
2200
2210 BLOCKMOD:
2220
2230    ?#DEVNUM,"modifying block in ";FSPEC$
2240    OPEN #2,FSPEC$,INPUT
2250    OPEN2=TRUE
2260    DOTPOS=INSTR(1,FSPEC$,".")
2270    BRACK= INSTR(1,FSPEC$,"[")
2280    IF DOTPOS=0 ?#DEVNUM,"file specification error-no extension " :STOP
2290    OLDFSPEC$=FSPEC$
2300    IF BRACK<>0 THEN PPN$=FSPEC$[BRACK,-1]  ELSE PPN$=""
2310    FSPEC$=FSPEC$[1,DOTPOS]+"TMP"+PPN$
2320    OPEN #3,FSPEC$,OUTPUT
2330    OPEN3=TRUE
2340 BLOCKMODLOOP:
2350
2360    INPUT LINE #2,DATLIN
2370    IF EOF(2) GOTO BLOCKMODEXIT
2380       FOR J=1 TO KEYMAX
2390       CALL BLOCKSCANIT
2400       NEXT J
2410    ?#3,DATLIN
2420    GOTO BLOCKMODLOOP
2430
2440 BLOCKSCANIT:
2450
2460    POS3=INSTR(1,DATLIN,KEYLIN(J))
2470    IF POS3=0 THEN RETURN
2480    !FIND BLOCK LEVEL
2490    TEMP2$=DATLIN
2500    CALL MAPLEVEL
2510    MAPLEVEL'A=MAPLEVEL
2520    STARTLIN=LINNUM
2530    IF STARTLIN=0 THEN SUPRESS=TRUE !NO LINE NUMBERS IN FILE-SUPRESS
2540    MAPLINS=0
2550
2560 MAPSIZLOOP:
2570
2580    INPUT LINE #2,TEMP2$
2590    IF EOF(2) GOTO FOUND'SPACE
2600    CALL MAPLEVEL
2610    LASTLIN=LINNUM
2620    IF MAPLEVEL<=MAPLEVEL'A GOTO FOUND'SPACE
2630    MAPLINS=MAPLINS+1
2640    GOTO MAPSIZLOOP
2650
2660 FOUND'SPACE:
2670
2680    ! CALCULATE DIFFERENCE BETWEEN LINE NUMBERS AND INCREMENT
2690    ! IF WE ARE NUMBERING
2700    IF SUPRESS GOTO STINIT  !JUST STRIP LINE
2710    INCREMENT=INT((LASTLIN-STARTLIN)/LINCOUNT(J))-1
2720    ? "INCREMENT=";INCREMENT,"LASTLIN=";LASTLIN
2730    ? "STARTLIN=";STARTLIN;"COUNT=";LINCOUNT(J)
2740    SUPRESS = (INCREMENT=0)
2750    !OK-READY TO PUT NEW MAP ON DISK
2760 STINIT:
2770    OPEN #(10+J),SUBLIN(J),INPUT
2780    OPEN'FLAG(J)=TRUE
2790       FOR INSERT=1 TO LINCOUNT(J)
2800       INPUT LINE #(10+J),TEMP$
2810       STRIP=0
2820
2830    STLOOP: STRIP=STRIP+1
2840       NUMERIC=INSTR(1," 0123456789",TEMP$[STRIP,STRIP])
2850       IF NUMERIC <> 0 THEN GOTO STLOOP     !STRIP OFF NUMBERS
2860       TEMP$=TEMP$[STRIP,-1]
2870       IF SUPRESS THEN LINENO$="" :GOTO NOLINUM
2880       LINNUM=STR(+STARTLIN+(INCREMENT*INSERT))
2890       LINENO$=LINNUM+" "
2900    NOLINUM:
2910       ?#3,LINENO$;TEMP$
2920       NEXT INSERT
2930    CLOSE #(10+J) : OPEN'FLAG(J)=FALSE
2940    DATLIN=TEMP2$
2950    RETURN
2960
2970 BLOCKMODEXIT:
2980
2990    IF OPEN2 THEN CLOSE #2 :OPEN2=FALSE
3000    IF OPEN3 THEN CLOSE #3 :OPEN3=FALSE
3010    KILL OLDFSPEC$
3020    XCALL RENAME,FSPEC$,OLDFSPEC$,FLAG
3030    IF FLAG#0 ?#DEVNUM,"RENAME ERROR IN MOD" :STOP
3040    CALL BUMP'LIST
3050    IF EOF(1) THEN GOTO FIN
3060    GOTO BLOCK'LOOP

    LOOK:

3090    SUBFLAG=FALSE !NO SUSTITUTE STRINGS NEEDED
3100    CALL GETFILES
3110    IF FSPEC$="" THEN MESAG="NULL FILENAME " : GOTO BAD'NEWS
3120    CALL    SHOW'IT
3130    OPEN #2,FSPEC$,INPUT
3140    OPEN2=TRUE
3150    CALL GET'KEYS
3160    TYPEALL = (KEYMAX=0)
3170 LOOKLOOP:
3180    INPUT LINE #2,DATLIN
3190    IF EOF(2) THEN GOTO NEXT'ONE
3200    IF TYPEALL THEN ?# DEVNUM,DATLIN :GOTO LOOKLOOP
3210       FOR J=1 TO KEYMAX
3220       POS=INSTR(1,DATLIN,KEYLIN(J))
3230       IF POS<>0 THEN ?#DEVNUM,DATLIN
3240       NEXT J
3250    GOTO LOOKLOOP
3260
3270 NEXT'ONE:
3280    CALL BUMP'LIST
3290    IF EOF(1) GOTO FIN
3300    IF OPEN2 THEN CLOSE #2 :OPEN2=FALSE
3310    CALL    SHOW'IT
3320    OPEN #2,FSPEC$,INPUT
3330    OPEN2=TRUE
3340    GOTO LOOKLOOP
3350    RETURN
3360
3370 GETFILES:
3380    INPUT "DO YOU WANT TO WORK ON A LIST OF FILES ? ",QUERY$
3390    IF QUERY$[1,1]="Y" GOTO GETLIST
3400    ONLYONE=TRUE !FLAG FOR SINGLE FILE MODE
3410    INPUT LINE "FULL FILENAME > ",FSPEC$
3420    RETURN
3430
3440 GETLIST:
3450    INPUT LINE "FULL NAME OF LIST OF FILES (direct.lst)> ",FSPEC$
3460    IF FSPEC$="" THEN FSPEC$="DIRECT.LST":?"using direct.lst"
3470    OPEN #1,FSPEC$,INPUT
3480    OPEN1=TRUE
3490    INPUT LINE #1,FSPEC$
3500    IF (EOF(1) AND OPEN1) THEN CLOSE #1  &
       : OPEN1=FALSE : MESAG="LIST FILE IS EMPTY" :GOTO BAD'NEWS
3510    RETURN
3520
3530    GET'KEYS: !INPUT STRINGS TO SEARCH FOR
3540    KEYMAX=0
3550 KEYLOOP:
3560    ?"ENTER ";MODE(MD);" TO SEARCH FOR OR <CR> TO START SEARCH "
3570    INPUT LINE "",TEMP$
3580    IF TEMP$ ="" GOTO KEYEXIT
3590    KEYMAX=KEYMAX+1
3600    KEYLIN(KEYMAX)=TEMP$
3610    IF NOT SUBFLAG GOTO KEYLOOP
3620    ?"ENTER SUBSTITUTE ";MODE(MD)
3630    INPUT LINE "",SUBLIN(KEYMAX)
3640    GOTO KEYLOOP
3650 KEYEXIT:
3660    RETURN
3670
3680 SEARCH1:
3690    ? #DEVNUM,FSPEC$
3700    FOUND=FALSE
3710    OPEN #2,FSPEC$,INPUT
3720    OPEN2=TRUE
3730 INLOOP:
3740    INPUT LINE #2,DATLIN
3750    IF EOF(2) GOTO NOTFOUND
3760       FOR I=1 TO KEYMAX
3770       POS=INSTR(1,DATLIN,KEYLIN(I))
3780       IF POS<>0 THEN FOUND=TRUE : I=KEYMAX
3790       NEXT I
3800    IF NOT(FOUND) GOTO INLOOP
3810 NOTFOUND:
3820    IF OPEN2 THEN CLOSE #2 :OPEN2=FALSE
3830    RETURN
3840
3850 BUMP'LIST:
3860    IF ONLYONE ? #DEVNUM, "THATS ALL FOLKS":GOTO FIN
3870    FILNUM=FILNUM+1
3880    OPEN #4,"INDEX.MOD",OUTPUT
3890    ?#4 FILNUM,FSPEC$
3900    CLOSE #4
3910    INPUT LINE #1,FSPEC$
3920    IF (EOF(1) AND OPEN1) THEN CLOSE #1: OPEN1=FALSE : ?"DONE":GOTO FIN
3930    RETURN
3940
3950 OPEN'BLOCKS:
3960       FOR I=1 TO KEYMAX
3970       OPEN #(10+I),SUBLIN(I),INPUT
3980       OPEN'FLAG(I)=TRUE
3990       COUNT=0
4000    COUNTLINS:
4010       INPUT LINE #(10+I),TEMP$
4020       ! JUST COUNTING # OF LINES
4030       IF EOF((10+I)) THEN GOTO STORECOUNT
4040       COUNT=COUNT+1
4050       GOTO COUNTLINS
4060
4070    STORECOUNT:
4080       LINCOUNT(I)=COUNT
4090       CLOSE #(10+I)
4100       OPEN'FLAG(I)=FALSE
4110       NEXT I
4120    RETURN
4130
4140 MAPLEVEL:
4150    Z=0
4160 NUMLOOP:
4170    Z=Z+1
4180    POS3=INSTR(1,"0123456789",TEMP2$[Z,Z])
4190    IF POS3<>0 GOTO NUMLOOP
4200    LINNUM=TEMP2$[1,Z-1]
4210    POS3=INSTR(1,TEMP2$,"MAP")
4220    MAPLEVEL=VAL(TEMP2$[POS3+3;2])
4230    IF POS3=0 THEN MAPLEVEL=OLDLEVEL  ! to prevent problems with !lines
4240    OLDLEVEL=MAPLEVEL
4250    RETURN
4260 SHOW'IT:
4270    ?#DEVNUM,FSPEC$
4280    ?#DEVNUM
4290    RETURN
4300
4310 FIN:IF DEVNUM<>0 THEN CLOSE #DEVNUM
4320    IF OPEN1 THEN CLOSE #1
4330    IF OPEN2 THEN CLOSE #2
4340    IF OPEN3 THEN CLOSE #3
4350 EXIT:      END