'
' Microsoft RemLine - Line Number Removal Utility
' Copyright (C) Microsoft Corporation 1985-1990
'
' REMLINE.BAS is a program to remove line numbers from Microsoft Basic
' Programs. It removes only those line numbers that are not the object
' of one of the following statements: GOSUB, RETURN, GOTO, THEN, ELSE,
' RESUME, RESTORE, or RUN.
'
' When REMLINE is run, it will ask for the name of the file to be
' processed and the name of the file or device to receive the
' reformatted output. If no extension is given, .BAS is assumed (except
' for output devices). If filenames are not given, REMLINE prompts for
' file names. If both filenames are the same, REMLINE saves the original
' file with the extension .BAK.
'
' REMLINE makes several assumptions about the program:
'
' 1. It must be correct syntactically, and must run in BASICA or
' GW-BASIC interpreter.
' 2. There is a 400 line limit. To process larger files, change
' MaxLines constant.
' 3. The first number encountered on a line is considered a line
' number; thus some continuation lines (in a compiler-specific
' construction) may not be handled correctly.
' 4. REMLINE can handle simple statements that test the ERL function
' using relational operators such as =, <, and >. For example,
' the following statement is handled correctly:
'
' IF ERL = 100 THEN END
'
' Line 100 is not removed from the source code. However, more
' complex expressions that contain the +, -, AND, OR, XOR, EQV,
' MOD, or IMP operators may not be handled correctly. For example,
' in the following statement REMLINE does not recognize line 105
' as a referenced line number and removes it from the source code:
'
' IF ERL + 5 = 105 THEN END
'
' If you do not like the way REMLINE formats its output, you can modify
' the output lines in SUB GenOutFile. An example is shown in comments.
REM *** NOTE: I like Veranda
, but you can remove it
or replace it with your favorite font.
fontpath$ = "Veranda.tff"
' Function and Subprocedure declarations
' Global and constant data
DIM SHARED Seps$
, InputFile$
, OutputFile$
, TmpFile$
' Keyword search data
KeyData:
' Start of module-level program code
Seps$
= " ,:=<>()" + CHR$(9)InitKeyTable
GetFileNames
BuildTable
GenOutFile
FileErr1:
INPUT " New input file name (ENTER to terminate): ", InputFile$
FileErr2:
INPUT " Output file name (ENTER to print to screen) :", OutputFile$
IF (OutputFile$
= "") THEN OutputFile$
= "CON" TmpFile$ = ""
'
' BuildTable:
' Examines the entire text file looking for line numbers that are
' the object of GOTO, GOSUB, etc. As each is found, it is entered
' into a table of line numbers. The table is used during a second
' pass (see GenOutFile), when all line numbers not in the list
' are removed.
' Input:
' Uses globals KeyWordTable$, KeyWordCount, and Seps$
' Output:
' Modifies LineTable! and LineCount
'
' Get line and first token
Token$ = GetToken$(InLin$, Seps$)
FOR KeyIndex
= 1 TO KeyWordCount
' See if token is keyword
' Get possible line number after keyword
Token$ = GetToken$("", Seps$)
' Check each token to see if it is a line number
' (the LOOP is necessary for the multiple numbers
' of ON GOSUB or ON GOTO). A non-numeric token will
' terminate search.
LineCount = LineCount + 1
LineTable!
(LineCount
) = VAL(Token$
) Token$ = GetToken$("", Seps$)
IF Token$
<> "" THEN KeyIndex
= 0 ' Get next token
Token$ = GetToken$("", Seps$)
'
' GenOutFile:
' Generates an output file with unreferenced line numbers removed.
' Input:
' Uses globals LineTable!, LineCount, and Seps$
' Output:
' Processed file
'
' Speed up by eliminating comma and colon (can't separate first token)
' Get first token and process if it is a line number
Token$ = GetToken$(InLin$, Sep$)
LineNumber!
= VAL(Token$
) FoundNumber = false
' See if line number is in table of referenced line numbers
FOR index
= 1 TO LineCount
IF (LineNumber!
= LineTable!
(index
)) THEN FoundNumber = TRUE
' Modify line strings
MID$(InLin$
, StrSpn
(InLin$
, Sep$
), LEN(Token$
)) = Token$
' You can replace the previous lines with your own
' code to reformat output. For example, try these lines:
'TmpPos1 = StrSpn(InLin$, Sep$) + LEN(Token$)
'TmpPos2 = TmpPos1 + StrSpn(MID$(InLin$, TmpPos1), Sep$)
'
'IF FoundNumber THEN
' InLin$ = LEFT$(InLin$, TmpPos1 - 1) + CHR$(9) + MID$(InLin$, TmpPos2)
'ELSE
' InLin$ = CHR$(9) + MID$(InLin$, TmpPos2)
'END IF
' Print line to file or console (PRINT is faster than console device)
'
' GetFileNames:
' Gets a file name by prompting the user.
' Input:
' User input
' Output:
' Defines InputFiles$ and OutputFiles$
'
PRINT " Microsoft RemLine: Line Number Removal Utility" PRINT " (.BAS assumed if no extension given)" INPUT " Input file name (ENTER to terminate): ", InputFile$
INPUT " Output file name (ENTER to print to screen): ", OutputFile$
IF (OutputFile$
= "") THEN OutputFile$
= "CON"
InputFile$ = InputFile$ + ".BAS"
CASE "CON", "SCRN", "PRN", "COM1", "COM2", "LPT1", "LPT2", "LPT3" OutputFile$ = OutputFile$ + ".BAS"
TmpFile$
= LEFT$(InputFile$
, INSTR(InputFile$
, ".")) + "BAK" IF TmpFile$
<> "" THEN InputFile$
= TmpFile$
'
' GetToken$:
' Extracts tokens from a string. A token is a word that is surrounded
' by separators, such as spaces or commas. Tokens are extracted and
' analyzed when parsing sentences or commands. To use the GetToken$
' function, pass the string to be parsed on the first call, then pass
' a null string on subsequent calls until the function returns a null
' to indicate that the entire string has been parsed.
' Input:
' Search$ = string to search
' Delim$ = String of separators
' Output:
' GetToken$ = next token
'
' Note that SaveStr$ and BegPos must be static from call to call
' (other variables are only static for efficiency).
' If first call, make a copy of the string
BegPos = 1
SaveStr$ = Search$
' Find the start of the next token
NewPos
= StrSpn
(MID$(SaveStr$
, BegPos
, LEN(SaveStr$
)), Delim$
) ' Set position to start of token
BegPos = NewPos + BegPos - 1
' If no new token, quit and return null
GetToken$ = ""
' Find end of token
NewPos
= StrBrk
(MID$(SaveStr$
, BegPos
, LEN(SaveStr$
)), Delim$
) ' Set position to end of token
NewPos = BegPos + NewPos - 1
' If no end of token, return set to end a value
NewPos
= LEN(SaveStr$
) + 1 ' Cut token out of search string
GetToken$
= MID$(SaveStr$
, BegPos
, NewPos
- BegPos
) ' Set new starting position
BegPos = NewPos
'
' InitKeyTable:
' Initializes a keyword table. Keywords must be recognized so that
' line numbers can be distinguished from numeric constants.
' Input:
' Uses KeyData
' Output:
' Modifies global array KeyWordTable$
'
FOR Count
= 1 TO KeyWordCount
KeyWordTable$(Count) = KeyWord$
'
' IsDigit:
' Returns true if character passed is a decimal digit. Since any
' Basic token starting with a digit is a number, the function only
' needs to check the first digit. Doesn't check for negative numbers,
' but that's not needed here.
' Input:
' Char$ - initial character of string to check
' Output:
' IsDigit - true if within 0 - 9
'
IsDigit = false
IsDigit
= (CharAsc
>= ASC("0")) AND (CharAsc
<= ASC("9"))
'
' StrBrk:
' Searches InString$ to find the first character from among those in
' Separator$. Returns the index of that character. This function can
' be used to find the end of a token.
' Input:
' InString$ = string to search
' Separator$ = characters to search for
' Output:
' StrBrk = index to first match in InString$ or 0 if none match
'
BegPos = 1
' Look for end of token (first character that is a delimiter).
StrBrk = 0
BegPos = BegPos + 1
StrBrk = BegPos
'
' StrSpn:
' Searches InString$ to find the first character that is not one of
' those in Separator$. Returns the index of that character. This
' function can be used to find the start of a token.
' Input:
' InString$ = string to search
' Separator$ = characters to search for
' Output:
' StrSpn = index to first nonmatch in InString$ or 0 if all match
'
BegPos = 1
' Look for start of a token (character that isn't a delimiter).
StrSpn = 0
BegPos = BegPos + 1
StrSpn = BegPos