Ml functions: Difference between revisions

From Color 64 BBS Wiki
m Protected "Ml functions" ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite))
No edit summary
 
(6 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{DISPLAYTITLE:ML Functions}}
[[programming features|Programming Features]] - <strong>ML Functions</strong>
[[programming features|Programming Features]] - <strong>ML Functions</strong>


The ML functions are used where the ML commands and ML variables will not be able to perform more complex operations. Simply put, a function is like a variable that can perform a subroutine before returning a computed value. Some functions also have parameters which are used to perform the function's specific operation.  Since the ML variables cannot return string values, the functions also take care of this need as well.
The ML functions provide operations that are more flexible than ML commands or ML variables. In practice, they behave like built-in BASIC functions: some execute an ML routine and then return a computed value. Functions can return either numeric or string results (including string values that cannot be returned through ML variables).


All functions begin with an "@" at sign, followed by one or two digits (the function number). Functions are either string or numeric functions, as will be indicated. Some functions have parameters that are required and/or optional; parameters are included in parenthesis after the function number.  
All ML functions begin with an "@" followed by one or two digits (the function number). Functions are either STRING or NUMERIC, as indicated in the table. Some functions accept required and/or optional parameters, which are placed in parentheses after the function number.


Example:
Example:
  1000 a$=@5:sr=st:a=val(a$):ifa<>0thenprint@1(a)  
  1000 a$=@5:sr=st:a=val(a$):ifa<>0thenprint@1(a)
  1010 ifsr=.then1000    
  1010 ifsr=.then1000


The above example would perform the following:  
In this example:
* Use the function @5, which reads in a line of disk data like the .01 command and then returns the line of data as its value.  
* @5 reads a line from disk (like .01) and returns it as a string.
* Then the routine tests to see if what was read in was numeric characters.  If it was then it will use the @1 function to print the value of the input without a leading space.  
* VAL() is used to test whether the returned line is numeric; if so, @1 prints the number without the leading space added by STR$ for positive values.
* The routine continues reading in data until the end of the file.  
* The loop continues until end-of-file (as indicated by ST).


The table below lists the ML Functions and descriptions.  
All ML functions (@##) invoke address $4E21 for ML processing.


{| class="wikitable
The table below lists the ML Functions and descriptions.
 
{| class="wikitable"
|-
|-
|+ML Function Descriptions  
|+ ML Function Descriptions
! Function
! Function
! Format and Description
! Format and Description
|-
|-
| @0  
| @0
| <strong>Format: @0 : STRING </strong>
| <strong>Input Buffer Slice (TX$/!40)</strong><br>
This is the equivalent of LEFT$(TX$,!40). This is used for when lines are returned from disk input (.01) or from key input (.02).  
<strong>Format: @0 : STRING</strong><br>
 
Equivalent to <code>LEFT$(TX$,!40)</code>. Commonly used after disk input (.01) or keyed input (.02) when the input buffer is TX$ and the character count is in !40.<br>
Example: <strong>.01:A$=@0 </strong>
Example: <strong>.01:A$=@0</strong>
|-
| @1
| <strong>STR$ Without Leading Space</strong><br>
<strong>Format: @1( <number> ) : STRING</strong><br>
Returns the equivalent of <code>STR$(<number>)</code> without the leading blank for positive numbers. Negative values retain the minus sign.<br>
Examples:<br>
<strong>@1(500)</strong> returns "500"<br>
<strong>@1(-10)</strong> returns "-10"
|-
| @2
| <strong>Find Substring (Forward)</strong><br>
<strong>Format: @2( <string1> , <string2> [ , <number> ] ) : NUMERIC</strong><br>
Searches for <string1> within <string2> from left to right and returns the 1-based position. Returns 0 if not found.<br>
Optional <number> behavior:<br>
* If omitted: return position of first occurrence<br>
* If <number> > 0: return position of the <number>th occurrence<br>
* If <number> = 0: return the count of occurrences of <string1> in <string2><br>
Examples:<br>
<ul style="list-style: none; margin-left: 0;">
<li><strong>@2("b","abc")</strong> returns 2</li>
<li><strong>@2("b","def")</strong> returns 0</li>
<li><strong>@2("b","abcdabc",2)</strong> returns 6</li>
<li><strong>@2("b","bobby",0)</strong> returns 3</li>
</ul>
The !52 variable stores the most recent find position (0 if the count form was used).
|-
| @3
| <strong>Repeat First Character</strong><br>
<strong>Format: @3( <string> , <number> ) : STRING</strong><br>
Returns a string made of the first character of <string> repeated <number> times.<br>
Example: <strong>@3("A",5)</strong> returns "AAAAA"<br>
<number> range: 0–255. If <string> is null, returns null.
|-
|-
| @1
| @4
| <strong>Format: @1( <number> ) : STRING </strong>
| <strong>Modem GET Character</strong><br>
 
<strong>Format: @4 : STRING</strong><br>
This returns the equivalent of STR$(<number>), but it will not include the leading blank that accompanies positive numbers. 
Modem input character (GET-style). Returns one character if available; otherwise returns a null string.<br>
 
Example: <strong>A$=@4</strong>
Examples: 
 
<strong>@1(500)</strong> will return the string "500"
 
<strong>@1(-10)</strong> will return the string "-10"
 
This is better than MID$(STR$(<number>),2) because it will not strip a negative sign.
|-
|-
| @2
| @5
| <strong>Format: @2( <string1> , <string2> [ , <number> ] ) : NUMERIC </strong>
| <strong>Read Disk Line (Returns String)</strong><br>
 
<strong>Format: @5 : STRING</strong><br>
This will search for and return the position of <string1> inside <string2>, searching from the first character to the end of <string2>.  If <string1> cannot be found in <string2>, then 0 is returned.  If you include <number>, then the @2 function will return the position of the <number> occurrence of <string1> in <string2>.  If <number> is 0, then the @2 function will return the number of occurrencess of <string1> in <string2>
Performs a disk line read (.01) and returns the resulting line as a string. Similar to @0, but executes the read first.<br>
 
Example: <strong>A$=@5:SR=ST:PRINT#9,A$;</strong>
Examples: 
<ul style="list-style: none;">
<li><strong>@2("b","abc”)</strong> would return 2, the position of b in abc </li>
<li><strong>@2("b","def")</strong> would return 0, because b is not in def </li>
<li><strong>@2("b","abcdabc",2)</strong> would return 6, the position of the second b </li>
<li><strong>@2("b","bobby",0)</strong> would return 3, the number of b's in bobby </li></ul>
 
The !52 variable will contain the value of the most recent find but will be 0 if the find command was used to find the number of occurances of <string1>.
|-
|-
| @3
| @6
| <strong>Format: @3( <string> , <number> ) : STRING </strong>
| <strong>Extended ASC / 16-bit Extract</strong><br>
 
<strong>Format: @6( <string1> [ , <string2> ] ) : NUMERIC</strong><br>
This function returns a string with <number> characters of the first character of <string>Example: @3("A",5) would return the string "AAAAA".   
Extended ASC for 8-bit and 16-bit extraction. Behavior depends on argument form:<br>
 
* One string, length 0–1: returns PETSCII of first character; returns 0 if null string (no error).<br>
<number> can range from 0 to 255.  If the string is a null string, then a null will be returned.
  Example: <strong>GET#8,A$:I=@6(A$)</strong><br>
* One string, length 2: returns 16-bit value from the first two characters (low byte = 1st char, high byte = 2nd char).<br>
   Example: <strong>IF LEN(I$)=2 THEN L=@6(I$)</strong><br>
* Two strings: treats first character of each as low/high bytes and returns a 16-bit value. Null strings are treated as 0.<br>
  Example: <strong>GET#8,A$,B$:L=@6(A$,B$)</strong>
|-
|-
| @4
| @7
| <strong>Format: @4 : STRING </strong>
| <strong>Extended CHR$ (16-bit to 2 Bytes)</strong><br>
 
<strong>Format: @7( <number> ) : STRING</strong><br>
This function is for input from the modem and returns a character as if you had used a GET statement.  
Extended CHR$. Returns a 2-character string containing the low byte then high byte of <number>. Useful for relative file positioning.<br>
 
Example: <strong>PRINT#15,"p"CHR$(104)@7(RN)CHR$(1)</strong>
Example: <strong>A$=@4</strong>.  If there are no characters in the modem input buffer, then a null (nu$) will be returned.
|-
|-
| @5
| @8
| <strong>Format: @5 : STRING </strong>
| <strong>Read Keyed Line (Returns String)</strong><br>
 
<strong>Format: @8 : STRING</strong><br>
This is the same as the @0 function, except it executes a .01 (get line from disk) command before returning the string.  
Performs keyed line input (.02) and returns the resulting line as a string.<br>
 
Example: <strong>I$=@8:P=!01:IF P=0 THEN RETURN</strong>
Example: <strong>A$=@5:SR=ST:PRINT#9,A$; </strong>
|-
|-
| @6
| @9
| <strong>Format: @6( <string1> [ , <string2> ] ) : NUMERIC </strong>
| <strong>Enhanced FRE()</strong><br>
 
<strong>Format: @9 : NUMERIC</strong><br>
This is an extended ASC function.  Its operation varies depending on the number characters you use in each string (regardless of if you use two strings or not). 
Enhanced FRE(). Returns free memory as a positive value and does not force garbage collection; uses an internal calculation routine.<br>
 
Example: <strong>I=@9:IF I>3000 THEN RETURN</strong>
Here is a table of the possible outcomes:
 
* One string, length of 0 or 1: 
::This will return the PET ASCII value of  <string1>, and will return 0 if it is a null string (not an error like ASC). 
::Example: <strong>GET#8,A$:I=@6(A$) </strong>
* One string, length of 2: 
::This will return the 16-bit value of the string.  The formula is 256*<2nd char> + <first char> using the characters' appropriate PET ASCII values. 
::Example:  <strong>IFLEN(I$)=2THENL=@6(I$)  </strong>
 
::This version is not as useful as the next one:
* Two strings, any lengths: 
:: This is useful for when a GET# command reads from disk two characters which represent the low and high byte of a 16-bit value. <string1> represents the low-byte character, and <string2> represents the high-byte character. 
::Example: <strong>GET#8,A$,B$:L=@6(A$,B$) </strong>
 
::L would contain the 16-bit value of the 2-byte input.  Only the first character of each of these strings will be used in the calculation.  If a string is a null string, then its value is considered zero.
|-
|-
| @7
| @10
| <strong>Format: @7( <number> ) : STRING </strong>
| <strong>Strip Control/Graphics Codes</strong><br>
 
<strong>Format: @10( <string> [ , <number> ] ) : STRING</strong><br>
This is an extended CHR$ function. It will return a two-character string representing the low and high bytes of <number>, respectively. This is useful for the relative file positioning command.  
Returns <string> with graphics/control characters removed. Optional <number> returns only the first <number> characters (LEFT$-style).<br>
 
<number> range: 0–255.<br>
Example: <strong>PRINT#15,"p"CHR$(104)@7(RN)CHR$(1) </strong>
Example: <strong>A$=@10(@0,15)</strong>
|-
|-
| @8
| @11
| <strong>Format: @8 : STRING </strong>
| <strong>Get Time String</strong><br>
 
<strong>Format: @11 : STRING</strong><br>
This is the same as @0, except it executes an .02 (Get keyed line of input) command before returning the string. 
Returns current time as "HH:MM am" or "HH:MM pm". Updates !45 (hour) and !44 (AM/PM flag: 0=AM, non-zero=PM).
 
Example: <strong>I$=@8:P=!01:IFP=0THENRETURN </strong>
|-
|-
| @9
| @12
| <strong>Format: @9 : NUMERIC </strong>
| <strong>Overlay String / Replace at Position</strong><br>
 
<strong>Format: @12( <string1> , <string2> , <number> ) : STRING</strong><br>
An enhanced FRE function. This returns the amount of free memory as a positive number (unlike how FRE sometimes returns a negative number). This routine does not perform a garbage collection (the slow delay often accompanying using the FRE function), but instead uses a routine that calculates free memory accurately.  
Overlays <string1> onto <string2> starting at position <number> (1–255), replacing existing characters. Pads with spaces if needed.<br>
 
Examples:<br>
Example: <strong>I=@9:IFI>3000THENRETURN </strong>
<ul style="list-style: none; margin-left: 0;">
<li><strong>@12("there","Hello",7)</strong> returns "Hello there"</li>
<li><strong>@12("*","++++++++",4)</strong> returns "+++*++++"</li>
</ul>
Special replace mode: if <number>=0, uses the most recent find position from @2 or @25. If that value is 0 (or if @2/@25 was used in count mode), an ILLEGAL QUANTITY error will occur.<br>
Example (replace all "." with "/"):<br>
<strong>1000 IF @2(".",I$)>0 THEN I$=@12("/",I$,0):GOTO 1000</strong>
|-
|-
| @10
| @13
| <strong>Format: @10( <string> [ , <number> ] ) : STRING </strong>
| <strong>Capture Crash Error</strong><br>
 
<strong>Format: @13 : STRING</strong><br>
This function returns <string>, but with all graphics control characters stripped from it.  This is useful for determining the exact width of the set of normal characters in the string (for centering, etc.).  If you include <number>, then only the first <number> characters will be returned, just like the LEFT$ function.  <number> can range from 0 to 255.
Crash routine helper: returns the BASIC error message text associated with the crash.
Example: <strong>A$=@10(@0,15) </strong>
|-
|-
| @11
| @14
| <strong>Format: @11 : STRING </strong>
| <strong>Capture Crash Line Number</strong><br>
 
<strong>Format: @14 : STRING</strong><br>
This function returns the current time in the format "HH:MM am" or "HH:MM pm", where HH is the current hour and MM is the current minute.  The !45 and !44 variables are also changed. !45 will contain the hour, and !44 will be 0 if the time is AM, or non-zero if the time is PM.  
Crash routine helper: returns the BASIC error line number as a string.
|-
|-
| @12
| @15
| <strong>Format: @12( <string1> , <string2> , <number> ) : STRING </strong>
| <strong>Convert Date to ADN</strong><br>
 
<strong>Format: @15( <year> , <month> , <day> ) : NUMERIC</strong><br>
This function returns a string that is <string2> with <string1> overlayed (replacing existing characters) at position <number>.  <number> can range from 1 to 255. If the strings do not overlap, then the space in between them will be padded with spaces. 
Returns an ADN (absolute day number) from year/month/day. Returns -1 if any parameter is invalid.
 
Examples: 
<ul style="list-style: none;"><li>
<strong>@12("there","Hello",7)</strong> will return the string "Hello there" </li>
<li><strong>@12("*","++++++++",4)</strong> will return "+++*++++" </li></ul>
 
The @12 function can also be used in conjunction with the @2 and @25 search-string functions as a "search and replace" function.  If 0 is used for <number> in the @12 function, then the value of the MOST RECENT @2 or @25 function will be used.  If that value is 0, then an ILLEGAL QUANTITY error will occur.  Also, if the @2 or @25 function was used to find the number of occurrences of a string rather than the position, then an error will occur. 
 
Example of the replace function: 
 
<strong>1000 IF @2(".",I$)>0 THEN I$=@12("/",I$,0):GOTO 1000 </strong>
 
The above routine will keep replacing all the "." characters in I$ with a “/" character until no more are found. See lines 2400-2403 in √bbs.msgs  (the routine that sifts merged messages for unauthorized MCI usage) for an example of the use of the @12 function.  
|-
|-
| @13
| @16
| <strong>Format: @13 : STRING </strong>
| <strong>Convert ADN to Year (Sets Month/Day)</strong><br>
 
<strong>Format: @16( <number> ) : NUMERIC</strong><br>
This function is used in the crash routine to determine what the BASIC error message was at the crash.  
Converts ADN in <number> to a date and returns the year. Updates !43 (month) and !42 (day). Invalid ADN yields undefined results.
|-
|-
| @14
| @17
| <strong>Format: @14 : STRING </strong>
| <strong>Convert ADN to Day of Week</strong><br>
 
<strong>Format: @17( <number> ) : NUMERIC</strong><br>
This function is also used in the crash routine. It returns the error line number as a string.  
Returns day-of-week from ADN in <number>: 0–6 for Sunday–Saturday.
|-
|-
| @15
| @18
| <strong>Format: @15( <year> , <month> , <day> ) : NUMERIC </strong>
| <strong>Convert ADN to Date String</strong><br>
 
<strong>Format: @18( <number> ) : STRING</strong><br>
This function returns an ADN (absolute day number) using the year, month, and day parameters. If either the year, month, or day is invalid, then negative one is returned.  
Returns date string "MM/DD/YYYY" from ADN in <number>. If ADN is invalid, returns "--/--/----".
|-
|-
| @16
| @19
| <strong>Format: @16( <number> ) : NUMERIC </strong>
| <strong>Convert Date String to ADN</strong><br>
 
<strong>Format: @19( <string> ) : NUMERIC</strong><br>
This function converts the ADN in <number> to a date and returns the YEAR of the date. The month and day are returned in the !43 and !42 variables, respectively.  If the ADN is invalid, then the results will be unpredictable.  
Converts date string "MM/DD/YYYY" to ADN. Returns -1 if invalid.
|-
|-
| @17
| @20
| <strong>Format: @17( <number> ) : NUMERIC </strong>
| <strong>Current Overlay Filename</strong><br>
 
<strong>Format: @20 : STRING</strong><br>
This function returns the day of the week using the ADN in <number>.  The value will be 0 to 6 for Sunday through Saturday.  
Returns the filename of the BASIC overlay currently in memory (used by crash routines).
|-
|-
| @18
| @21
| <strong>Format: @18( <number> ) : STRING </strong>
| <strong>Alpha-Only, Lowercase Filter</strong><br>
 
<strong>Format: @21( <string> ) : STRING</strong><br>
This function will return a string in the format "MM/DD/YYYY" using the AND in <number>. If the ADN is invalid, then the string "--/--/----" will be returned.
Returns <string> with all non-alphabetic characters removed and converts letters to lowercase.<br>
Example: <strong>@21("This Is A Test")</strong> returns "thisisatest"
|-
|-
| @19
| @22
| <strong>Format: @19( <string> ) : NUMERIC </strong>
| <strong>Compress Number for Disk</strong><br>
 
<strong>Format: @22( <number> ) : STRING</strong><br>
<string> is a date in the format "MM/DD/YYYY". This function will return the ADN calculated from <string>. If the date is invalid, then the function will return negative 1.
Returns a compressed numeric string for disk storage by packing two digits per byte (approximately half-length of STR$ output). Uses a special encoding to avoid producing a carriage return character.<br>
Example: <strong>PRINT#8,@22(I)</strong>
|-
|-
| @20
| @23
| <strong>Format: @20 : STRING </strong>
| <strong>Uncompress Number from Disk</strong><br>
 
<strong>Format: @23( <string> ) : NUMERIC</strong><br>
This function returns the file name of the BASIC overlay currently in memory. It is used by the crash routine to get the name of the current overlay.  
Inverse of @22: uncompresses a number stored in <string>. Invalid strings yield undefined results.<br>
Example: <strong>INPUT#8,I$:I=@23(I$)</strong>
|-
|-
| @21
| @24
| <strong>Format: @21( <string> ) : STRING </strong>
| <strong>Pad/Terminate Relative Record</strong><br>
 
<strong>Format: @24( <string> , <number> ) : STRING</strong><br>
This function returns a string that is <string> stripped of all characters that are not alphabetic.  It will also convert any uppercase letters to lowercase.  
Pads/truncates a record to length <number> for relative file use.<br>
 
* If <string> is shorter than <number>, pads with carriage returns to reach <number>.<br>
Example: <strong>@21("This Is A Test")</strong> would return "thisisatest". 
* If <string> is >= <number>, truncates to <number>-1 and appends a carriage return.<br>
 
Null strings or <number><2 may yield undefined results.<br>
This function is used for the password file to enable a search for users who have uppercase characters and graphics in their username.
Example: <strong>F$=F$+@24("name",15)</strong>
|-
|-
| @22
| @25
| <strong>Format: @22( <number> ) : STRING </strong>
| <strong>Find Substring (Reverse)</strong><br>
 
<strong>Format: @25( <string1> , <string2> [ , <number> ] ) : NUMERIC</strong><br>
This function will return a special compressed version of <number> for writing to a disk file. It is like a STR$ function, but packs two digits into each byte, cutting the length of the string in half. 
Same as @2, but searches from right to left (end of <string2> toward the beginning).
 
Programmer's note: This does NOT convert the number to BCD (Binary Coded Decimal). Rather, it uses a special method to avoid ever creating a carriage return character in the string (because such a character would not enable the compressed number to be read in from disk).  
 
Example:  <strong>PRINT#8,@22(I) </strong>
|-
|-
| @23
| @26
| <strong>Format: @23( <string> ) : NUMERIC </strong>
| <strong>Get Delimited Field</strong><br>
 
<strong>Format: @26( <string1> , <string2> , <number> ) : STRING</strong><br>
This function performs the opposite of the @22 function and uncompresses the number stored in <string>. An invalid string will cause unpredictable results.
Returns the <number>th section of <string2> separated by the delimiter in <string1>.<br>
 
Example: <strong>@26("!","cp6!i6!cd//directory",2)</strong> returns "i6"<br>
Example: <strong>INPUT#8,I$:I=@23(I$) </strong>
<number> must be non-zero.
|-
|-
| @24
| @27
| <strong>Format: @24( <string> , <number> ) : STRING </strong>
| <strong>Calendar Age from ADNs</strong><br>
 
<strong>Format: @27( <number1> , <number2> ) : NUMERIC</strong><br>
This function is used to pad relative file records to get them ready to print to disk.
Returns calendar age in years between two ADNs: from <number2> to <number1>.<br>
 
Example: <strong>AGE=@27(DA,BD)</strong>
If <string> is less than <number> characters in length, then <string> will be returned with enough carriage returns padded on the end to make it <number> characters in length.
 
If <string> is the same as or more than <number> characters in length, then <string> will be truncated to <number> minus one character, and a carriage return will be added, so the resulting string will be <number> characters in length.
 
If <string> is a null, or <number> is less than 2 characters, then there will be unpredictable results: 
 
Example: <strong>F$=F$+@24("name",15) </strong>
|-
|-
| @25
| @28
| <strong>Format: @25( <string1> , <string2> [ , <number> ] ) : NUMERIC </strong>
| <strong>Find String in Array</strong><br>
 
<strong>Format: @28( <string> , <array> ) : NUMERIC</strong><br>
This works the same as the @2 function, except the search for the string proceeds from the END of <string2> to the beginning (backwards).  
Searches a one-dimensional string array for an exact match to <string> and returns the index. Returns -1 if not found.<br>
<Array> is the array name without "$" or parentheses (for example, pass <code>A</code> for <code>A$()</code>). Errors if array is missing or not 1-D.<br>
Example: <strong>I=@28(A$,A):IF I<0 THEN #"not found!"</strong>
|-
|-
| @26
| @29
| <strong>Format: @26( <string1> , <string2> , <number> ) : STRING </strong>
| <strong>Read N Characters</strong><br>
 
<strong>Format: @29( <number> ) : STRING</strong><br>
This function returns the <number> section of <string2> separated by the character in <string1>.
Reads <number> characters (GET#-style). Does not stop at EOF and does not stop at the end-of-line character in !04.
 
Example: <strong>@26("!","cp6!i6!cd//directory",2)</strong> would return "i6", because the "!" is the separator character, and "i6" is the second section divided off by the "!" character.
 
This function is used by the drive command routine for dividing up the drive command into its sections.  If <number> is 0, then an error will result.  
|-
|-
| @27
| @30
| <strong>Format: @27( <number1> , <number2> ) : NUMERIC </strong>
| <strong>Boot Drive Init Command</strong><br>
 
<strong>Format: @30( <number> ) : STRING</strong><br>
This function calculates the calendar age from two ADN's.  The age is the number of calendar years from the ADN in <number2> to the ADN in <number1> (like subtracting <number2> from <number1>).  
This function is used in conjunction with the variables !49, !50, and !51.  
 
It returns the drive init command for one of the three boot drives:
For example, to calculate someone's age on the BBS system, the formula would be: age=@27(DA,BD) where DA is the system date ADN, and BD is the birth date ADN.  
0=Boot drive, 1=Program drive, 2=External drive.
|-
|-
| @28
| @31
| <strong>Format: @28( <string> , <array> ) : NUMERIC </strong>
| <strong>Sequential Read (Enhanced)</strong><br>
 
<strong>Format: @31 : (Undocumented)</strong><br>
This function is a search function which will search through an array to find <string><array> is the name of a one-dimensional string array, but the name should not include either the $ character or the array parenthesis (e.g. the string array "a$()" would simply be "a").  The function will return the index of <array> where the string was found. If the string is not found, will return a negative one. The function will search through the entire array, and the string must match the array element exactly. If <array> is not found in memory or is more than one dimension, then an error will result.  
Newer function (not documented in the v8.0 manuscript). See [[Undocumented_8.1_commands#at31|Undocumented features: @31]].
 
Example: <strong>I=@28(A$,A):IFI<0THEN#"not found!"</strong>
|-
|-
| @29
| @32
| <strong>Format: @29( <number> ) : STRING </strong>
| <strong>Retrieve File Block Count</strong><br>
 
<strong>Format: @32 : (Undocumented)</strong><br>
This function is like @5, except that <number> is how many characters you want read in. It is a viable alternative to the GET# command in some cases. It does not check for End of File and it does not stop at the End of Line character stored in !04.  
Newer function (not documented in the v8.0 manuscript). See [[Undocumented_8.1_commands#at32|Undocumented features: @32]].
|-
|-
| @30
| @33
| <strong>Format: @30( <number> ) : STRING </strong>
| <strong>Return 1-Byte Null String</strong><br>
 
<strong>Format: @33 : (Undocumented)</strong><br>
This function is used in conjunction with the variables !49, !50, and !51. It returns the drive init command for one of the three boot drives: 0=Boot drive, 1=Program drive, 2=External drive.  
Newer function (not documented in the v8.0 manuscript). Returns a single-byte null string (CHR$(0)). See [[Undocumented_8.1_commands#at33|Undocumented features: @33]].
|}
|}



Latest revision as of 03:37, 1 March 2026

Programming Features - ML Functions

The ML functions provide operations that are more flexible than ML commands or ML variables. In practice, they behave like built-in BASIC functions: some execute an ML routine and then return a computed value. Functions can return either numeric or string results (including string values that cannot be returned through ML variables).

All ML functions begin with an "@" followed by one or two digits (the function number). Functions are either STRING or NUMERIC, as indicated in the table. Some functions accept required and/or optional parameters, which are placed in parentheses after the function number.

Example:

1000 a$=@5:sr=st:a=val(a$):ifa<>0thenprint@1(a)
1010 ifsr=.then1000

In this example:

  • @5 reads a line from disk (like .01) and returns it as a string.
  • VAL() is used to test whether the returned line is numeric; if so, @1 prints the number without the leading space added by STR$ for positive values.
  • The loop continues until end-of-file (as indicated by ST).

All ML functions (@##) invoke address $4E21 for ML processing.

The table below lists the ML Functions and descriptions.

ML Function Descriptions
Function Format and Description
@0 Input Buffer Slice (TX$/!40)

Format: @0 : STRING
Equivalent to LEFT$(TX$,!40). Commonly used after disk input (.01) or keyed input (.02) when the input buffer is TX$ and the character count is in !40.
Example: .01:A$=@0

@1 STR$ Without Leading Space

Format: @1( <number> ) : STRING
Returns the equivalent of STR$(<number>) without the leading blank for positive numbers. Negative values retain the minus sign.
Examples:
@1(500) returns "500"
@1(-10) returns "-10"

@2 Find Substring (Forward)

Format: @2( <string1> , <string2> [ , <number> ] ) : NUMERIC
Searches for <string1> within <string2> from left to right and returns the 1-based position. Returns 0 if not found.
Optional <number> behavior:

  • If omitted: return position of first occurrence
  • If <number> > 0: return position of the <number>th occurrence
  • If <number> = 0: return the count of occurrences of <string1> in <string2>

Examples:

  • @2("b","abc") returns 2
  • @2("b","def") returns 0
  • @2("b","abcdabc",2) returns 6
  • @2("b","bobby",0) returns 3

The !52 variable stores the most recent find position (0 if the count form was used).

@3 Repeat First Character

Format: @3( <string> , <number> ) : STRING
Returns a string made of the first character of <string> repeated <number> times.
Example: @3("A",5) returns "AAAAA"
<number> range: 0–255. If <string> is null, returns null.

@4 Modem GET Character

Format: @4 : STRING
Modem input character (GET-style). Returns one character if available; otherwise returns a null string.
Example: A$=@4

@5 Read Disk Line (Returns String)

Format: @5 : STRING
Performs a disk line read (.01) and returns the resulting line as a string. Similar to @0, but executes the read first.
Example: A$=@5:SR=ST:PRINT#9,A$;

@6 Extended ASC / 16-bit Extract

Format: @6( <string1> [ , <string2> ] ) : NUMERIC
Extended ASC for 8-bit and 16-bit extraction. Behavior depends on argument form:

  • One string, length 0–1: returns PETSCII of first character; returns 0 if null string (no error).
 Example: GET#8,A$:I=@6(A$)
  • One string, length 2: returns 16-bit value from the first two characters (low byte = 1st char, high byte = 2nd char).
 Example: IF LEN(I$)=2 THEN L=@6(I$)
  • Two strings: treats first character of each as low/high bytes and returns a 16-bit value. Null strings are treated as 0.
 Example: GET#8,A$,B$:L=@6(A$,B$)
@7 Extended CHR$ (16-bit to 2 Bytes)

Format: @7( <number> ) : STRING
Extended CHR$. Returns a 2-character string containing the low byte then high byte of <number>. Useful for relative file positioning.
Example: PRINT#15,"p"CHR$(104)@7(RN)CHR$(1)

@8 Read Keyed Line (Returns String)

Format: @8 : STRING
Performs keyed line input (.02) and returns the resulting line as a string.
Example: I$=@8:P=!01:IF P=0 THEN RETURN

@9 Enhanced FRE()

Format: @9 : NUMERIC
Enhanced FRE(). Returns free memory as a positive value and does not force garbage collection; uses an internal calculation routine.
Example: I=@9:IF I>3000 THEN RETURN

@10 Strip Control/Graphics Codes

Format: @10( <string> [ , <number> ] ) : STRING
Returns <string> with graphics/control characters removed. Optional <number> returns only the first <number> characters (LEFT$-style).
<number> range: 0–255.
Example: A$=@10(@0,15)

@11 Get Time String

Format: @11 : STRING
Returns current time as "HH:MM am" or "HH:MM pm". Updates !45 (hour) and !44 (AM/PM flag: 0=AM, non-zero=PM).

@12 Overlay String / Replace at Position

Format: @12( <string1> , <string2> , <number> ) : STRING
Overlays <string1> onto <string2> starting at position <number> (1–255), replacing existing characters. Pads with spaces if needed.
Examples:

  • @12("there","Hello",7) returns "Hello there"
  • @12("*","++++++++",4) returns "+++*++++"

Special replace mode: if <number>=0, uses the most recent find position from @2 or @25. If that value is 0 (or if @2/@25 was used in count mode), an ILLEGAL QUANTITY error will occur.
Example (replace all "." with "/"):
1000 IF @2(".",I$)>0 THEN I$=@12("/",I$,0):GOTO 1000

@13 Capture Crash Error

Format: @13 : STRING
Crash routine helper: returns the BASIC error message text associated with the crash.

@14 Capture Crash Line Number

Format: @14 : STRING
Crash routine helper: returns the BASIC error line number as a string.

@15 Convert Date to ADN

Format: @15( <year> , <month> , <day> ) : NUMERIC
Returns an ADN (absolute day number) from year/month/day. Returns -1 if any parameter is invalid.

@16 Convert ADN to Year (Sets Month/Day)

Format: @16( <number> ) : NUMERIC
Converts ADN in <number> to a date and returns the year. Updates !43 (month) and !42 (day). Invalid ADN yields undefined results.

@17 Convert ADN to Day of Week

Format: @17( <number> ) : NUMERIC
Returns day-of-week from ADN in <number>: 0–6 for Sunday–Saturday.

@18 Convert ADN to Date String

Format: @18( <number> ) : STRING
Returns date string "MM/DD/YYYY" from ADN in <number>. If ADN is invalid, returns "--/--/----".

@19 Convert Date String to ADN

Format: @19( <string> ) : NUMERIC
Converts date string "MM/DD/YYYY" to ADN. Returns -1 if invalid.

@20 Current Overlay Filename

Format: @20 : STRING
Returns the filename of the BASIC overlay currently in memory (used by crash routines).

@21 Alpha-Only, Lowercase Filter

Format: @21( <string> ) : STRING
Returns <string> with all non-alphabetic characters removed and converts letters to lowercase.
Example: @21("This Is A Test") returns "thisisatest"

@22 Compress Number for Disk

Format: @22( <number> ) : STRING
Returns a compressed numeric string for disk storage by packing two digits per byte (approximately half-length of STR$ output). Uses a special encoding to avoid producing a carriage return character.
Example: PRINT#8,@22(I)

@23 Uncompress Number from Disk

Format: @23( <string> ) : NUMERIC
Inverse of @22: uncompresses a number stored in <string>. Invalid strings yield undefined results.
Example: INPUT#8,I$:I=@23(I$)

@24 Pad/Terminate Relative Record

Format: @24( <string> , <number> ) : STRING
Pads/truncates a record to length <number> for relative file use.

  • If <string> is shorter than <number>, pads with carriage returns to reach <number>.
  • If <string> is >= <number>, truncates to <number>-1 and appends a carriage return.

Null strings or <number><2 may yield undefined results.
Example: F$=F$+@24("name",15)

@25 Find Substring (Reverse)

Format: @25( <string1> , <string2> [ , <number> ] ) : NUMERIC
Same as @2, but searches from right to left (end of <string2> toward the beginning).

@26 Get Delimited Field

Format: @26( <string1> , <string2> , <number> ) : STRING
Returns the <number>th section of <string2> separated by the delimiter in <string1>.
Example: @26("!","cp6!i6!cd//directory",2) returns "i6"
<number> must be non-zero.

@27 Calendar Age from ADNs

Format: @27( <number1> , <number2> ) : NUMERIC
Returns calendar age in years between two ADNs: from <number2> to <number1>.
Example: AGE=@27(DA,BD)

@28 Find String in Array

Format: @28( <string> , <array> ) : NUMERIC
Searches a one-dimensional string array for an exact match to <string> and returns the index. Returns -1 if not found.
<Array> is the array name without "$" or parentheses (for example, pass A for A$()). Errors if array is missing or not 1-D.
Example: I=@28(A$,A):IF I<0 THEN #"not found!"

@29 Read N Characters

Format: @29( <number> ) : STRING
Reads <number> characters (GET#-style). Does not stop at EOF and does not stop at the end-of-line character in !04.

@30 Boot Drive Init Command

Format: @30( <number> ) : STRING
This function is used in conjunction with the variables !49, !50, and !51. It returns the drive init command for one of the three boot drives: 0=Boot drive, 1=Program drive, 2=External drive.

@31 Sequential Read (Enhanced)

Format: @31 : (Undocumented)
Newer function (not documented in the v8.0 manuscript). See Undocumented features: @31.

@32 Retrieve File Block Count

Format: @32 : (Undocumented)
Newer function (not documented in the v8.0 manuscript). See Undocumented features: @32.

@33 Return 1-Byte Null String

Format: @33 : (Undocumented)
Newer function (not documented in the v8.0 manuscript). Returns a single-byte null string (CHR$(0)). See Undocumented features: @33.

Next section: Basic Variables Table

Programming Features