MFP language Help: Input/Output and File Operations
Input/Output is the communication between user and MFP program. MFP programming language provides user a set of C-like input/output functions. Using these functions, user can easily read information from/write information to console (i.e. Command Line or Scientific Calculator Plus for JAVA), string and file. However, please note that Smart Calculator does not support reading / writing console functions.
To create, copy, move and delete files, MFP also provides a group of Dos (Unix) command-like functions. With authorization, user is able to create, read, modify, copy, move or delete any file or folder, just like working in a Dos or Unix command line window.
Section 1 Input and Output in Command Line
MFP provides the following functions to input/output in Command Line or Scientific Calculator Plus for JAVA:
Function Name |
Function Info |
input |
input(2) : input(prompt,input_type) prints string prompt in the console and waiting for user to input. The second parameter, input_type, is optional. At this stage only if the second parameter exists and it is string "s" or "S", user's input is looked on as a string and this function returns the string. Otherwise, input is treated as an expression and this function returns the value of the expression. If input is not a valid expression, this function will reprint the prompt and wait for user to input again. An input is finished by pressing ENTER key. If multiple lines are input, only the first line is read. For example, user runs input("$", "S"), then types 4 + 3 after prompt, presses ENTER, this function returns a string "4 + 3". If user runs input("%"), then types 4 + 3 after prompt, presses ENTER, this function returns 7. |
pause |
pause(1) : pause(message) suspends current running program waiting for an ENTER input by user. Message, which is a string and is optional, will be printed on screen as a prompt if provided. |
|
print(1) : print(x) prints the value of x to output, x can be any value type. |
printf |
printf(1...) : printf(format_string, ...), sprintf(format_string, ...) and fprintf(fd, format_string, ...) work like corresponding C/C++ functions. Function printf prints formatted string constructed from format_string and other parameter values to output console, sprintf constructs a new string from format_string and other parameters, and returns the new string, fprintf prints the formated string from format_string and other parameter values to the text file whose id is fd. The format_string parameter supports integer (%d, %i, %x, etc), float (%e, %f, etc), character (%c), string (%s) etc. User can find detailed information for construction of a format string by reading C language manual for these functions. For example, printf("Hello world!%f", 3.14) will output "Hello world!3.140000" on the screen, sprintf("%c%d", "A", 9) returns "A9" (MFP does not support single character type, so single character is stored as a one-char string). |
scanf |
scanf(1) : scanf(format_string), sscanf(input_from, format_string) and fscanf(fd, format_string) work like corresponding C/C++ functions. Function scanf reads one line input from user, sscanf reads string based parameter input_from, and fscanf reads content from a file whose id is fd. The format_string parameter supports integer (%d, %i, %x, etc), float (%e, %f, etc), character (%c), string (%s) etc. User can find detailed information for construction of a format string by reading C language manual for these functions. Different from C language, these functions do not accept additional parameters to store read values. These functions simply return all the read values in an array. For example, sscanf("3Hello world!", "%d%c%c%s") returns [3, "H", "e", "llo"] (MFP does not support single character type, so single character is stored as a one-char string). |
As shown in the above table, functions input, pause and print are easy to use. The only thing to note is function print only accepts a string based parameter. Since a string plus any value is a string, user may use an empty string plus a data value as the parameter to print. For example, to print value of array [1,2,3+4i], user may call print(""+[1,2,3+4i]) so that [1,2,3+4i] is converted to string [1, 2, 3 + 4i] and then is printed on the screen. Also note that, some special characters, e.g. double-quote " and backward slash \, need to escape (i.e. add a \ before the character) in string. For example,
print("\"\\")
will print "\ on the screen. This escaping requirement is applied to all the functions using string based parameters, including functions print, input, pause and printf and scanf which will be introduced later.
The following example is for the above functions. It can be found in the examples.mfps file in io and file libs sub-folder in the manual’s sample code folder:
Help
@language:
test input, pause and print functions
@end
@language:simplified_chinese
测试input,pause和print函数
@end
endh
function io2console1()
variable a = input("Please input a number") //input a number
variable b = input("Please input a string:", "S") //input a string
pause("Press ENTER to continue!") //press ENTER to continue
//print what has been input
print("You have input " + a + b)
//print special character.
print("\n\"\\")
endf
When running the above example, user inputs sind(30)*2+3i after the first prompt, and inputs a string “Is a complex value”, then press ENTER and sees the output is:
You have input 1 + 3iIs a complex value
"\
Functions printf and scanf are used in formatted input/output. Their usage is similar to the corresponding C language functions. The way to call printf() function is:
Printf("<format string>", <argument list>)
. The format string includes two parts. The first part includes normal characters. These characters will be output as they are shown in the format string. The second part includes special characters. They immediately follow a “%”. Character(s) following a “%”generally determine output format of a value. The only exception is character “%” which needs another “%” before it to escape. And instead of controlling the output format of a value, it simply means printing a “%” on the screen.
Argument list is a list of to-be-output values. The number and order of values must match the definition of format string. Otherwise error will be reported.
Below is a list of supported output formats of printf:
%d: means a value is output as a decimal integer;
%f: means a value is output as a floating value;
%s: means a value is output as a string;
%e: means a value is output using scientific notation;
%x and %X: means a value is output as a hexadecimal integer. Note that there is no 0x initial in the output. For example, in MFP, hexadecimal integer FF (i.e. 255) should be written as 0xFF. However, if user calls printf to output decimal integer 255 using %x or %X format, FF instead of 0xFF will be printed;
%o: means a value is output as an octal integer. Note that there is no 0 initial in the output. For example, in MFP octal integer 77 (i.e. 63) should be written as 077. However, if user calls printf to output decimal integer 63 using %o format, 77 instead of 077 will be printed;
%g: select a suitable format for a real value. Note that string is not supported.
For example, if user wants to output 8.776 followed by a comma and then followed by a string "Hello", and then followed by a blank character, and then output 1234 using hexadecimal format, then output three letters which are abc, then output 255 as a normal decimal integer, finally output a string "finish", function printf can be called as below:
printf("%f,%s %Xabc%dfinish",8.776,"Hello",1234,255)
The output of the above statement is:
8.776000,Hello 4D2abc255finish
Note that in the output result, hexadecimal integer does not start with 0x (i.e. 1234 is output as 4D2 not 0x4D2).
Basically, values in the argument list will be formatted and then output by the format string. If a value cannot be directly output using the desired format, printf will try to convert the value to another data type and try again. If any value cannot be formatted even after data type conversion, an error will be triggered. For example,
printf("%d", 123)
and
printf("%f", 123.1)
are both right because 123 is an integer and %d is the format indicator. And 123.1 is a floating value and %f is exactly the format indicator to output floating value.
For another example,
printf("%f", 123)
and
printf("%d", 123.1)
are also both right because 123 can be automatically converted to a floating value, and 123.1 can be rounded to an integer. However,
printf("%d", 123 + 123i)
and
printf("%f", [1.2,2.3])
are wrong because 123 + 123i is a complex value which cannot be converted to integer . [1.2, 2.3] is an array which cannot be converted to a single value. So if user wants to output complex or array, real and image parts or each element in the array must be output separately, like follows:
printf("%d + %di", 123, 123) //output 123 + 123i
printf("[%f, %f]", 1.2, 2.3) //output [1.200000, 2.300000]
. Alternatively, a trick to output them as string (i.e. using %s) can be played:
printf("%s", 123 + 123i) //output 123 + 123i
printf("%s", [1.2,2.3]) //output [1.2, 2.3]
. Since any value in MFP can be converted to a string, this trick always works.
In order to accurately control the output format, user may insert some characters between "%" and following format definition character(s). For example, user may insert a positive integer value between "%" and following format definition character to tell printf function what’s the maximum output length. For example:
%3d means outputting 3 or more digit integer, and the output is right-aligned if the integer includes less than 3 digits;
%9.2f means outputting 9 or more digit floating value, 2 digits after decimal point and 6 digits before. Decimal point takes one digit. The output is right-aligned if the floating value has less than 9 characters;
%8s means outputting an 8 or more character string. Blank characters are padded in front of the string if it includes less than 8 characters.
In the above examples, if the length of an integer or a string is longer than the specified output length, the full integer or string will be printed regardless of the output length setting; if the length of the integer part of a floating value is longer than the specified integer part of output length, the full integer part will be printed regardless of the setting; if the length of the fractional part of a floating value is longer than the specified fractional part of output length, the fractional part will be rounded.
If user wants to pad 0 before the output, s\he can add a zero before the output length setting. For example, %04d means 0s are padded in front of an integer’s output to make the total output length is 4 if the integer’s length is less than 4.
If output length setting for string is a floating value, the integer part of the floating value means the minimum output length, and the fractional part means the maximum output length. If the string’s length is larger than the maximum output length, the output will be truncated. For example, %6.9s means outputting a string whose length is no less than 6 and no greater than 9. If a string includes less than 6 characters, blank will be padded in front of it; if a string includes more than 9 characters, the characters after character no. 9 will be discarded.
Function printf supports some special characters including \n (new line), \r (return) and \t (tabulator). These characters can be used in the format string parameter. For example:
printf("abc\ndef")
outputs two lines which are abc and def because \n means changing to a new line.
Opposite to printf, function scanf reads a line of user’s input from console. Reading terminates at the place where an ENTER key is pressed, i.e. the end of the line, and returns an array whose elements are the values user input. Scanf only has one parameter which is the input format string. This parameter tells scanf what type of data the input should be recognized. Basically function scanf supports the following input formats:
%d: input a decimal integer;
%f and %e: input a floating value;
%s: input a string;
%x: input a hexadecimal integer. Note that there should be no 0x initial, e.g. 0x10AB should be input as 10AB. Otherwise, scanf cannot recognize it. This is different from the format of hexadecimal values in MFP, but matches the requirement of printf function. Also note that x in %x must be a small letter and %X is not supported.
%o: input an octal integer. Note that there should be no 0 initial, e.g. 017 should be input as 17. Otherwise, scanf may not recognize it. This is different from the format of octal values in MFP, but matches the requirement of printf function.
%g: input a decimal value.
Scanf’s format string may include some characters between the format indicators, i.e. %d, %f, etc. When scanf reads the input line, it ignores these characters and read input after them. The delimiters can include both special characters like space, \t, \n, and \r and normal characters like a, b, c, etc. Note that same as printf, some characters need escaping, i.e. % must be written as %% in the format string, \ must be written as \\ and " must be written as \". A blank char (i.e. space, \t, \n and \r) delimiter results in ignoring one or several consecutive blank characters. Otherwise, scanf just ignores the same character(s) as in the delimiter. If no delimiter between two format indicators, scanf will skip 0, 1 or several adjacent blank characters in the format string after reading the first input value and before reading the second input value.
The strategy of scanf is reading until cannot read. For example, if the format string is "%d%s" and user’s input is 123abd, scanf first reads the digits, i.e. 123, because the first format indicator is %d. Then scanf sees character a but clearly a cannot be a part of decimal integer. Therefore, scanf tries to use %s, which is immediately after %d, to match it. %s means a string. As such scanf will read all the characters from a to the end of the line or until a blank character is found. Thus abd is formatted as a string input.
If during reading, scanf finds nothing that can be input for a format indicator, it will return an array including all the read data values. For example, the format string of scanf is "%f %d%s" and user’s input is 1.23 xabd. The first format indicator is %f which corresponds to 1.23. Then there are blanks which will be looked on as a delimiter. Then scanf tries to read a decimal integer corresponding to %d. However, no decimal integer can be read after the blanks in the input (i.e. 1.23 xabd) so that scanf returns an array which is [1.23].
The following example shows how scanf works. The statement is
Scanf("%f\n%x%dABC%s%d%s %e")
. Assume user inputs
8.67 6E8d 232ABC hello 12
. The returned value of scanf is [8.67, 28301, 232, "hello", 12, ""]. Note that in the format string after ABC scanf expects a string. However, in the input after ABC is blank which can only be looked on as a (part of) delimiter. Thus scanf skips the blank so that string "hello" not " hello" is input. In the end of the format string there is a format indicator which is %e. However, no corresponding input can be found so that scanf returns.
Format indicator can also tell scanf at most how many characters should be read. In the following example
scanf("%3f %2s")
, %3f means at most 3 characters should be read to input a floating value. Similarly, %2s means at most 2 characters should be read for the string. If user inputs
1235.324 aerf
, the output would be [123, "5."] because %3f only reads 3 characters from user’s input so that 123 is read. Then scanf finds a blank in the format string. As explained above, a blank character delimiter may mean 0 or 1 or several consecutive blank character(s) in the input. Since no blank character after 3, this delimiter means zero blank character so that scanf tries to read two characters to match %2s then. The string input therefore is "5." and it is returned by function scanf with 123.
Also note that, different from printf, scanf does not automatically convert data types. Only if user’s input exactly matches the format indicator scanf can read. Otherwise it stops reading input for this format indicator. For example,
Scanf("%d,%f")
tries to read an integer and a floating value from input. If user’s input is
12.34,5
, scanf can only return [12] because 12.34 is a floating value which cannot be automatically rounded to an integer. Thus when scanf reads an integer for %d, it stops at decimal point, i.e. “.”. However, scanf finds that after %d a “,” exists in the format string as a delimiter. However, decimal point is not a comma so that reading fails. So the final return is only [12].
The following example is for the above functions. It can be found in the examples.mfps file in io and file libs sub-folder in the manual’s sample code folder:
Help
@language:
test printf and scanf functions
@end
@language:simplified_chinese
测试printf和scanf函数
@end
endh
function printfscanf()
printf("Now test printf function\n")
printf("%f,%s %Xabc%dfinish",8.776,"Hello",1234,255)
printf("\n")
printf("%d", 123)
printf("\n")
printf("%f", 123.1)
printf("\n")
printf("%f", 123)
printf("\n")
printf("%d", 123.1)
printf("\n")
printf("%d + %di", 123, 123) //print 123 + 123i
printf("\n")
printf("[%f, %f]", 1.2, 2.3) //print [1.200000, 2.300000]
printf("\n")
printf("%s", 123 + 123i) //print 123 + 123i
printf("\n")
printf("%s", [1.2,2.3]) //print [1.2, 2.3]
printf("\n")
printf("%3s", "abcdefg")
printf("\n")
printf("%019.6f", 12.2342154577) // print 000000000012.234215
printf("\n")
printf("abc\ndef")
printf("\n")
printf("Now test scanf function\n")
variable result_of_scanf
printf("Please input:\n123abd\n")
result_of_scanf = scanf("%d%s")
// remember, to simply print % using printf, we need to use %%
printf("scanf(\"%%d%%s\") returns " + result_of_scanf)
printf("\n")
printf("Please input:\n1.23 xabd\n")
result_of_scanf = scanf("%f %d%s")
print("scanf(\"%f %d%s\") returns " + result_of_scanf)
printf("\n")
printf("Please input:\n8.67 6E8d 232ABC hello 12\n")
result_of_scanf = scanf("%f\n%x%dABC%s%d%s %e")
print("scanf(\"%f\n%x%dABC%s%d%s %e\") returns " + result_of_scanf)
printf("\n")
printf("Please input:\n1235.324 aerf\n")
result_of_scanf = scanf("%3f %2s")
print("scanf(\"%3f %2s\") returns " + result_of_scanf)
printf("\n")
printf("Please input:\n12.34,5\n")
result_of_scanf = scanf("%d,%f")
print("scanf(\"%d,%f\") returns " + result_of_scanf)
printf("\n")
endf
Running function printfscanf() in Command Line and the result is shown below. Note that the result includes both user’s input and scanf’s output.
Now test printf function
8.776000,Hello 4D2abc255finish
123
123.100000
123.000000
123
123 + 123i
[1.200000, 2.300000]
123 + 123i
[1.2, 2.3]
abcdefg
000000000012.234215
abc
def
Now test scanf function
Please input:
123abd
123abd
scanf("%d%s") returns [123, "abd"]
Please input:
1.23 xabd
1.23 xabd
scanf("%f %d%s") returns [1.23]
Please input:
8.67 6E8d 232ABC hello 12
8.67 6E8d 232ABC hello 12
scanf("%f
%x%dABC%s%d%s %e") returns [8.67, 28301, 232, "hello", 12, ""]
Please input:
1235.324 aerf
1235.324 aerf
scanf("%3f %2s") returns [123, "5."]
Please input:
12.34,5
12.34,5
scanf("%d,%f") returns [12]
Section 2 Input from and Output to String
Similar to printf and scanf, MFP programming language provides sprintf and sscanf to output to and input from string. Sprintf has very similar usage to printf except that printf does not have any returned value because all the output is printed on the screen while sprint returns the output string.
Sscanf is also similar to scanf. Their difference is, first, sscanf needs two parameters, first is input string and second is the format string; and second, input string of sscanf may have multiple lines while scanf can only read one line from console.
The following example is for the above functions. It can be found in the examples.mfps file in io and file libs sub-folder in the manual’s sample code folder:
Help
@language:
test sprintf and sscanf functions
@end
@language:simplified_chinese
测试sprintf和sscanf函数
@end
endh
function sprintfsscanf()
variable result_str
printf("Now test sprintf function\n")
result_str = sprintf("%f,%s %Xabc%dfinish",8.776,"Hello",1234,255)
printf(result_str + "\n")
result_str = sprintf("%d", 123)
printf(result_str + "\n")
result_str = sprintf("%f", 123.1)
printf(result_str + "\n")
result_str = sprintf("%f", 123)
printf(result_str + "\n")
result_str = sprintf("%d", 123.1)
printf(result_str + "\n")
result_str = sprintf("%d + %di", 123, 123) //return 123 + 123i
printf(result_str + "\n")
result_str = sprintf("[%f, %f]", 1.2, 2.3) //return [1.200000, 2.300000]
printf(result_str + "\n")
result_str = sprintf("%s", 123 + 123i) //return 123 + 123i
printf(result_str + "\n")
result_str = sprintf("%s", [1.2,2.3]) //return [1.2, 2.3]
printf(result_str + "\n")
result_str = sprintf("%3s", "abcdefg")
printf(result_str + "\n")
result_str = sprintf("%019.6f", 12.2342154577) // return 000000000012.234215
printf(result_str + "\n")
result_str = sprintf("abc\ndef")
printf(result_str + "\n")
printf("Now test sscanf function\n")
variable result_of_sscanf
result_of_sscanf = sscanf("123abd","%d%s")
// remember, to simply print % using printf, we need to use %%
printf("scanf(\"123abd\",\"%%d%%s\") returns " + result_of_sscanf)
printf("\n")
result_of_sscanf = sscanf("1.23 xabd","%f %d%s")
print("scanf(\"1.23 xabd\",\"%f %d%s\") returns " + result_of_sscanf)
printf("\n")
// read string including multiple lines
result_of_sscanf = sscanf("8.67 6E8d 232ABC\nhello 12", _
"%f\n%x%dABC%s%d%s %e")
print("scanf(\"8.67 6E8d 232ABC\\nhello 12\",\"%f\n%x%dABC%s%d%s %e\") returns " + result_of_sscanf)
printf("\n")
result_of_sscanf = sscanf("1235.324 aerf","%3f %2s")
print("scanf(\"1235.324 aerf\",\"%3f %2s\") returns " + result_of_sscanf)
printf("\n")
result_of_sscanf = sscanf("12.34,5","%d,%f")
print("scanf(\"12.34,5\",\"%d,%f\") returns " + result_of_sscanf)
printf("\n")
endf
Run function sprintfsscanf() in Command Line and the output is shown below. Note that different from the example for scanf, no user input is required here.
Now test sprintf function
8.776000,Hello 4D2abc255finish
123
123.100000
123.000000
123
123 + 123i
[1.200000, 2.300000]
123 + 123i
[1.2, 2.3]
abcdefg
000000000012.234215
abc
def
Now test sscanf function
scanf("123abd","%d%s") returns [123, "abd"]
scanf("1.23 xabd","%f %d%s") returns [1.23]
scanf("8.67 6E8d 232ABC\nhello 12","%f
%x%dABC%s%d%s %e") returns [8.67, 28301, 232, "hello", 12, ""]
scanf("1235.324 aerf","%3f %2s") returns [123, "5."]
scanf("12.34,5","%d,%f") returns [12]
Section 3 Functions to Read and Write File
MFP programming language provides user a set of C-like file reading and writing functions. They include text file reading/writing functions, i.e. fprintf and fscanf (similar usage to printf and scanf), line by line text file reader freadline, binary file reading/writing functions, i.e. fread and fwrite, and fopen and fclose to open and close file respectively. The functions are listed in the following table:
Function Name |
Function Info |
fclose |
fclose(1) : fclose(fd) closes the file whose id is fd. If fd is invalid, returns -1. Otherwise, returns 0. |
feof |
feof(1) : feof(fd) identifies if it has been the end of a read mode file whose id is fd. If so, returns true. Otherwise, returns false. If fd is invalid, throws an exception. |
fopen |
fopen(2) : fopen(path, mode) opens file at path to read or write and returns the file’s id number. It is similar to C and Matlab's same name function. However, only "r", "a", "w", "rb", "ab" and "wb" modes are supported. Examples are fopen("C:\\Temp\\Hello.dat", "ab") (Windows) and fopen("./hello.txt", "r") (Android). fopen(3) : fopen(path, mode, encoding) opens a text file at path using character set encoding to read or write and returns the file id number. Because only text file supports encoding, parameter mode can only be "r", "a" and "w". Examples are fopen("C:\\Temp\\Hello.txt", "a", "LATIN-1") (Windows) and fopen("./hello.txt", "r", "UTF-8") (Android). |
fprintf |
fprintf(2...) : printf(format_string, ...), sprintf(format_string, ...) and fprintf(fd, format_string, ...) work like corresponding C/C++ functions. Function printf prints formatted string constructed from format_string and other parameter values to output console, sprintf constructs a new string from format_string and other parameters, and returns the new string, fprintf prints the formatted string from format_string and other parameter values to the text file whose id is fd. The format_string parameter supports integer (%d, %i, %x, etc), float (%e, %f, etc), character (%c), string (%s) etc. User can find detailed information for construction of a format string by reading C language manual for these functions. For example, printf("Hello world!%f", 3.14) will output "Hello world!3.140000" on the screen, sprintf("%c%d", "A", 9) returns "A9" (MFP does not support single character type, so single character is stored as a one-char string). |
fread |
fread(4) : fread(fd, buffer, from, length) reads length number of bytes from file whose id is fd and stores the bytes in buffer starting from parameter from. Note that from and length must be non-negative and from + length should be no greater than buffer size. From and length are optional. If they do not exist, fread reads buffer size of bytes and fills the buffer. Buffer is also optional. If Buffer does not exist, fread returns a single byte. If fread finds that it is at the end of the file before reading, it returns -1. Otherwise, if using buffer, it returns the number of bytes that are read (if buffer is provided). If file does not exist, or is invalid or inaccessible, exception will be thrown. Examples are fread(1), fread(2, byte_buffer) and fread(2, byte_buffer, 3, 7). |
freadline |
freadline(1) : freadline(fd) reads one line from text file whose id is fd. If before reading, freadline finds it is at the end of the file, it returns NULL. Otherwise, it returns the string based line excluding the change-line character(s) at the end. |
fscanf |
fscanf(2) : scanf(format_string), sscanf(input_from, format_string) and fscanf(fd, format_string) work like corresponding C/C++ functions. Function scanf reads one line input from user, sscanf reads string based parameter input_from, and fscanf reads content from a file whose id is fd. The format_string parameter supports integer (%d, %i, %x, etc), float (%e, %f, etc), character (%c), string (%s) etc. User can find detailed information for construction of a format string by reading C language manual for these functions. Different from C language, these functions do not accept additional parameters to store read values. These functions simply return all the read values in an array. For example, sscanf("3Hello world!", "%d%c%c%s") returns [3, "H", "e", "llo"] (MFP does not support single character type, so single character is stored as a one-char string). |
fwrite |
fwrite(4) : fwrite(fd, buffer, from, length) writes length number of bytes to file whose id is fd. The data to write store in parameter buffer starting from parameter from. Note that from and length must be non-negative and from + length should be no greater than buffer size. From and length are optional. If they do not exist, fwrite writes whole buffer to file. Buffer can also be a single byte which means fwrite writes only 1 byte to file. If file does not exist, or is invalid or inaccessible, exception will be thrown. Examples are fwrite(1, 108), fwrite(2, byte_buffer) and fwrite(2, byte_buffer, 3, 7). |
1. Open and Close File
Similar to C language, the first step in MFP’s file operating routine is to open file. The function to open a file is fopen. This function has three parameters. The first one is string based file name (path). Here path can be either an absolute path (e.g. "/mnt/sdcard/a.txt" or "C:\\temp\\b.exe") or a relative path (e.g. "a.txt" or "temp\\b.exe"). Note that relative path is relative to the current working folder. In Android, the working folder when Scientific Calculator Plus starts is the AnMath folder in SD card. In PC, the working folder when Scientific Calculator Plus starts is where the JCmdLine.jar file is located. After Scientific Calculator Plus starts, user is able to change working folder using cd function.
The second parameter of fopen function is the mode to open the file. This parameter is also a string and has six choices which are:
"r": open a text file to read. Generally a text file’s extension is .txt, but can also be .c, .cpp, .mfps, .xml etc. These files can be opened and edited by notepad;
"w": open a text file to write. The original content will be wiped off;
"a": open a text file to append. The input will be appended to the tail of the text file;
"rb": open a binary file to read. Generally binary files cannot be opened and edited by notepad;
"wb": open a binary file to write. The original content will be wiped off;
"ab": open a binary file to append. The input will be appended to the tail of the binary file;
Note that functions for text files are different from functions for binary files. Reading/writing text files should call function fprintf, fscanf and freadline, while reading/writing binary files should call fread and fwrite. If user uses text file function to read/write a binary file or vice versa, an error will be reported.
Besides the above two parameters, fopen has another optional parameter which is the encoding mode of the file. This parameter is only useful to text files. It is quite important to open a text file using correct encoding mode. Otherwise, user may see it just includes bad codes.
The default encoding mode of fopen function is OS’s encoding mode. For example, if user is using simplified Chinese Windows, encoding is GB2312. This encoding mode fully supports simplified Chinese characters so that if user calls fopen to open a text file to write some Chinese words into it without an encoding mode parameter, and then opens it again in Nodepad, the Chinese words are still there. However, English Windows’s character set is IBM437 which does not support Chinese characters. If user calls fopen to write some Chinese words in an English Windows system, and then reopens it again in Nodepad, nothing but bad codes or question marks are found.
This problem is not that severe in Android because Android’s system adopts UTF-8 as encoding mode. UTF-8 supports Chinese as well as many other character sets. As such text files created by fopen in an Android device generally have no problem to open by a text editor on Windows.
So if user of MFP programming language wants to develop a script to create or modify some text files and share the script with other people using different languages, encoding mode parameter of fopen function cannot be neglected and encoding mode "UTF-8" is strongly recommended.
If fopen opens a file successfully, it returns a non-negative integer which is the file id. Every time fopen is called, whether operating the same file or not, a different file id is returned. The returned file id will be a parameter for the following file reading/writing/closing functions. Without this parameter, file reading/writing/closing functions are not able to know which file to operate.
After file is opened and read or written, user needs to close it to release the resource. The function to close an open file is fclose(fd) where fd is the returned file id from fopen.
Fclose function is not negligible. If a file is opened but not closed, first memory is leaked; second future writing operations on this file may fail.
Here examples are provided for fopen/fclose functions:
variable fd1 = fopen("test.exe","wb") // open binary file test.exe to write.
fclose(fd1)
variable fd2 = fopen("/mnt/sdcard/AnMath/test.txt","r","UTF-8") // open text file test.txt using UTF-8 encoding mode to read.
fclose(fd2)
2. Read and Write Text File
So far, MFP only provides sequentially reading / writing functions for text files. This means after a text file is opened, user can only read or write the file towards the end of the file. User cannot jump to an arbitrary point and start reading or writing. When reading arrives at the end of the file, it stops. MFP provides feof function to identify if it is at the end of the file. Feof has one parameter which is file id. It returns true if it is at the end of the file, or false otherwise.
Text file reading functions provided by MFP are fscanf and freadline. The usage of fscanf is similar to functions scanf and sscanf which have been introduced before. Fscanf needs two parameters, the first one is file id, i.e. fopen’s return value; the second one is format string. Fscanf returns an array whose elements are input values from the file. Note that the file may include multiple lines and the changing line characters are treated as a type of blanks.
Function freadline reads a text file line by line. Its usage is much simpler than fscanf. It only needs one parameter which is file id. Every time it is called, it returns a line of the file and sets file reading pointer to the beginning of the next line. If it arrives at the end of the file, next time it is called it returns an empty string.
The following example demonstrates user how to read text file using the above two functions. It can be found in the examples.mfps file in io and file libs sub-folder in the manual’s sample code folder.
Before running this example, user needs to create a text file named test_read.txt in the io and file libs folder (i.e. the same folder of the source file). The content of the file is:
123 456
Good,2*9=18
Hello!
abc
. The MFP code to read the file is shown below:
Help
@language:
test reading text file
@end
@language:simplified_chinese
测试读取文本文件
@end
endh
function readTextFile()
// here assume current directory is AnMath and test_read.txt
// is saved in scripts/manual/io and file libs/ folder.
// Content of the file :
//123 456
//Good,2*9=18
//Hello!
//abc
variable fd = fopen("scripts/manual/io and file libs/test_read.txt", "r")
// read two integers
variable int_array = fscanf(fd, "%d%d")
// print what has been read
printf("read " + int_array + "\n")
variable read_str = ""
// if we are not at the end of the file and we haven't read string Hello!
while and(feof(fd) == false, read_str != "Hello!")
read_str = freadline(fd)
// print what has been read
printf("read " + read_str + "\n")
loop
variable str_array = fscanf(fd, "%s")
// print what has been read
printf("read " + str_array + "\n")
if (feof(fd))
// it is right if we are at the end of the file
print("End of the file found!\n")
else
// it is wrong if we are still not at the end of file
print("Something wrong!\n")
endif
fclose(fd) //don’t forget to close the file
endf
The output of the above example is:
read [123, 456]
read
read Good,2*9=18
read Hello!
read ["abc"]
End of the file found!
In the above code, after reading 123 and 456, freadline is called in the while loop to read the file line by line. However, the first line freadline returns is not Good,2*9=18, but an empty string. The reason is, before freadline is called, fscanf only moves reading pointer to the end of 456 and returns. This means the changing line character hasn’t been read. As such freadline starts reading the character after 6 until it sees a changing line character. However, no character is between 6 and changing line so that it returns an empty string.
The text file writing function that MFP provides is fprintf. This function is very similar to printf and sprintf. The only difference is, fprintf has an extra parameter, i.e. its first parameter, which is the file id returned from fopen. The second parameter is format string and the following parameters (if there are) are the values which will be written into the file.
The following example demonstrates user how to write text file. It can be found in the examples.mfps file in io and file libs sub-folder in the manual’s sample code folder.
Help
@language:
test writing text file
@end
@language:simplified_chinese
测试写入文本文件
@end
endh
function writeTextFile()
// first test write to replace mode. If file does not exist, it will be
// created. If file does exist, its content will be wiped off.
variable fd = fopen("scripts/manual/io and file libs/test_write.txt", _
"w", "UTF-8")
// first inputs some numbers and string with prompt information
fprintf(fd, "The first line includes %d, %f, %s\n", 123.71, 56.48, "hi")
// then input 4 Chinese characters with prompt information
fprintf(fd, "Now input some Chinese characters: " + "汉字中文\n")
fclose(fd) // close the file
// Then test append mode. If file does not exist, it will be
// created. If file does exist, fprintf will append some text to its
// current content.
fd = fopen("scripts/manual/io and file libs/test_write.txt", _
"a", "UTF-8")
// inputs some numbers and string with prompt information
fprintf(fd, "Now add a new line %d, %f, %s\n", -999, -48.73, "why?")
fclose(fd) // close the file
endf
After running the above code, user will find a test_write.txt file is generated in the io and file libs folder. The content of the file is below:
The first line includes 123, 56.480000, hi
Now input some Chinese characters: 汉字中文
Now add a new line -999, -48.730000, why?
Because the code uses UTF-8 encoding mode to open the text file, these Chinese characters can be properly shown in any text editor, e.g. notepad++.
MFP doesn’t support global variables. However, user is able to write and read the same text file in different functions. The text file works as if a global variable. The content of the file is the value of the global variable.
3. Read and Write Binary File
In MFP, the function to read binary file is fread. Fread has four parameters. The first one is file id (fd) which is the returned value from fopen. The second one is the buffer where the read bytes are stored. This parameter must be an array. The third one is the starting place in the buffer from where the read bytes are stored. The last parameter is the number of bytes to read. Note that the starting point in the buffer plus the number of bytes to read should not be larger than the buffer length.
The third and fourth parameters are optional. If they don’t exist, the default starting point is 0 and number of bytes to read is the length of buffer. The second parameter is also optional. If it doesn’t exist, fread simply reads one byte and returns the read byte. If it exists, fread stores all the read bytes in the buffer and returns the number of bytes it has read. If before reading fread finds it has arrived at the end of the file, fread returns -1. To avoid unnecessary reading when arriving at the end of the file, user can use feof function before calling fread. If the file to read does not exist, an exception is thrown.
MFP’s binary file writing function is fwrite. Fwrite(fd, buffer, from, length) writes length bytes to the file whose id is fd. These bytes are stored in string buffer from index from. Note that from and length must be non-negative and from + length shouldn’t be larger than buffer’s capacity. Parameters from and length can be neglected together. If they don’t exist, fwrite writes the whole buffer into the file. Buffer can also be a single byte instead of an array. In this case, fwrite simply writes the byte into the file. If the file doesn’t exist or cannot be accessed, an exception will be thrown.
The following code is an example for the above functions. It can be found in the examples.mfps file in io and file libs sub-folder in the manual’s sample code folder.
Help
@language:
test reading & writing binary file
@end
@language:simplified_chinese
测试读写二进制文件
@end
endh
function readWriteBinaryFile()
// remember write binary file should use "wb" not "w"
variable fd = fopen("scripts/manual/io and file libs/test_rw.bin", "wb")
fwrite(fd, 108) // write one byte whose value is 108
// note that buffer should be an array of bytes (i.e. integer whose
// value is no less than -127 and no greater than 128). Here 1000
// is larger than 128 so that it will be casted to a byte whose
// value is -24 when write to a binary file. Its upper bits will lose
variable buffer = [-18,79,126,-55,48,-23,-75,7,98,6,0,-34,1000]
fwrite(fd,buffer) //write everything in the buffer into the file
fclose(fd)
// remember append binary file should use "ab" not "a"
fd = fopen("scripts/manual/io and file libs/test_rw.bin", "ab")
// write 7 bytes from index 3 of buffer
fwrite(fd,buffer, 3, 7)
fclose(fd)
//print original buffer content
print("Originally buffer includes " + buffer + "\n")
// remember read binary file should use "rb" not "r"
fd = fopen("scripts/manual/io and file libs/test_rw.bin", "rb")
// read 5 bytes from file, and store the read bytes in buffer from
// index 2
fread(fd, buffer, 2, 5)
print("Now buffer is " + buffer + "\n") //print the buffer’s content
variable byte_value = fread(fd) // read 1 byte
print("Read one byte which is " + byte_value + "\n")
variable read_byte_cnt = fread(fd, buffer) // try to read buffer length
// bytes
print("Read " + read_byte_cnt + " bytes" + "\n") // print how many
// bytes read
print("Now buffer is " + buffer + "\n") //print the buffer’s content
read_byte_cnt = fread(fd, buffer) // try to read buffer length bytes
// again
print("Read " + read_byte_cnt + " bytes" + "\n") // print how many
// bytes read
// check if we have arrived at the end of file
if (feof(fd))
// check how many bytes we can read if we have arrived at the
// end of file
print("We have arrived at the end of file.\n")
print("Now check how many bytes can be read.\n")
read_byte_cnt = fread(fd, buffer) // try to read buffer length
// bytes again
print("Read " + read_byte_cnt + " bytes" + "\n") // print how
// many bytes
// read
endif
fclose(fd)
endf
The output of the example is:
Originally buffer includes [-18, 79, 126, -55, 48, -23, -75, 7, 98, 6, 0, -34, 1000]
Now buffer is [-18, 79, 108, -18, 79, 126, -55, 7, 98, 6, 0, -34, 1000]
Read one byte which is 48
Read 13 bytes
Now buffer is [-23, -75, 7, 98, 6, 0, -34, -24, -55, 48, -23, -75, 7]
Read 2 bytes
We have arrived at the end of file.
Now check how many bytes can be read.
Read -1 bytes
Section 4 Functions to Read and Modify File Properties
MFP programming language provides functions to help user read or even modify file properties including file name, path, type, size and last-modified time. The details of these functions are listed in the table below:
Function Name |
Function Info |
get_absolute_path |
get_absolute_path(1) : get_absolute_path(fd_or_path) returns a string value which is the absolute path of the file either whose id number is fd_or_path (here fd_or_path is an integer) or whose relative path is fd_or_path (here fd_or_path is a string). |
get_canonical_path |
get_canonical_path(1) : get_canonical_path(fd_or_path) returns a string value which is the canonical path (path which is absolute and does not rely on symbol link) of file either whose id number is fd_or_path (here fd_or_path is an integer) or whose relative path is fd_or_path (here fd_or_path is a string). |
get_file_last_modified_time |
get_file_last_modified_time(1) : get_file_last_modified_time(path) returns the last-modified time of the file or folder corresponding to a string based path. The time is measured by the number of milliseconds since midnight on January 1st, 1970. If path does not exist or the file is not accessible, returns -1. |
get_file_path |
get_file_path(1) : get_file_path(fd) returns a string value which is the path of file whose id number is fd. |
get_file_separator |
get_file_separator(0) : get_file_separator() returns the separator used in path. In Windows it returns string "\\". In Linux or Android it returns string "/". |
get_file_size |
get_file_size(1) : get_file_size(path) returns the size of the file corresponding to a string based path. If path does not correspond to a file, or the file does not exist or the file is not accessible, it returns -1. |
is_directory |
is_directory(1) : is_directory(path) identifies if the file (or folder) at string based parameter path is a directory or not. If it exists and is a directory the function returns true, otherwise false. Examples are is_directory("E:\\") (Windows) and is_directory("/home/tony/Documents/cv.pdf") (Android). |
is_file_executable |
is_file_executable(1) : is_file_executable(path) identifies if the file (or folder) at string based parameter path is executable or not. If it exists and is executable the function returns true, otherwise false. Examples are is_file_executable("E:\\") (Windows) and is_file_executable("/home/tony/Documents/cv.pdf") (Android). |
is_file_existing |
is_file_existing(1) : is_file_existing(path) identifies if the file (or folder) at string based parameter path exists or not. If exists it returns true, otherwise false. Examples are is_file_existing("E:\\") (Windows) and is_file_existing("/home/tony/Documents/cv.pdf") (Android). |
is_file_hidden |
is_file_hidden(1) : is_file_hidden(path) identifies if the file (or folder) at string based parameter path is hidden or not. If it exists and is hidden the function returns true, otherwise false. Examples are is_file_hidden("E:\\") (Windows) and is_file_hidden("/home/tony/Documents/cv.pdf") (Android). |
is_file_normal |
is_file_normal(1) : is_file_normal(path) identifies if the file (or folder) at string based parameter path is a normal file (not a folder) or not. If it exists and is a normal file the function returns true, otherwise false. Examples are is_file_normal("E:\\") (Windows) and is_file_normal("/home/tony/Documents/cv.pdf") (Android). |
is_file_readable |
is_file_readable(1) : is_file_readable(path) identifies if the file (or folder) at string based parameter path is readable or not. If it exists and is readable the function returns true, otherwise false. Examples are is_file_readable("E:\\") (Windows) and is_file_readable("/home/tony/Documents/cv.pdf") (Android). |
is_file_writable |
is_file_writable(1) : is_file_writable(path) identifies if the file (or folder) at string based parameter path is writable or not. If it exists and is writable the function returns true, otherwise false. Examples are is_file_writable("E:\\") (Windows) and is_file_writable("/home/tony/Documents/cv.pdf") (Android). |
is_path_absolute |
is_path_absolute(1) : is_path_absolute(path) identifies if the string based path is an absolute path (i.e. not relative to current folder). If it is an absolute path the function returns true, otherwise false. Examples are is_path_absolute("E:\\temp") (Windows) and is_path_absolute("Documents/cv.pdf") (Android). |
is_path_parent |
is_path_parent(2) : is_path_parent(path1, path2) identifies if the string based path1 is the parent of string based path2. If it is returns true, otherwise false. Examples are is_path_parent("E:\\temp", "E:\\temp\\..\\temp\\test") (Windows) and is_path_parent(".", "Documents/cv.pdf") (Android). |
is_path_same |
is_path_same(2) : is_path_same(path1, path2) identifies if the string based path1 is actually the same as string based path2. If it is returns true, otherwise false. Examples are is_path_same("E:\\temp", "E:\\temp\\..\\temp\\") (Windows) and is_path_parent("/home/tony/Documents", "Documents/") (Android). |
is_symbol_link |
is_symbol_link(1) : is_symbol_link(path) identifies if the file (or folder) at string based parameter path is a symbol link or not. If it exists and is a symbol link the function returns true, otherwise false. Examples are is_symbol_link("E:\\") (Windows) and is_symbol_link("/home/tony/Documents/cv.pdf") (Android). |
set_file_last_modified_time |
set_file_last_modified_time(2) : set_file_last_modified_time(path, time) sets the last-modified time of the file or folder corresponding to a string based path to be time. Here time is measured by the number of milliseconds since midnight on January 1st, 1970. If path does not exist or the file is not accessible, it returns false. Otherwise, it returns true. Examples are set_file_last_modified_time("C:\\Temp\\Hello\\", 99999999) (Windows) and set_file_last_modified_time("./hello.txt", 1111111111) (Android). |
The usage of the above functions is very simple. The functions starting with get_ only need one parameter. The parameter is either file id returned by fopen function, or string based file path. The return value of the functions is either a string based file path, or an integer which is last-modified time or file size.
The functions starting with is_ confirm a property of a file. They only have one parameter which is either file id or string based file path. The return value is either True or False.
The function starting with set_ is set_file_last_modified_time. This is the only function that can modify file’s property. This function sets a file’s last-modified time. It needs two parameters. The first one is file path, and the second one is the new modification time.
The following code is the example of the above functions. This example can be found in the examples.mfps file in io and file libs sub-folder in the manual’s sample code folder.
Help
@language:
test file properties operators
@end
@language:simplified_chinese
测试读写文件属性的函数
@end
endh
function fileProperties()
// Assume current working directory is AnMath in Android
// or the folder where JCmdline.jar is located (for
// Scientific Calculator for JAVA)
print("Current working directory is "+get_working_dir()+"\n")
variable retval
// open current function's source code file
variable strPath = "scripts/manual/io and file libs/examples.mfps"
variable fd = fopen(strPath, "r")
// get source code file's absolute path
retval = get_absolute_path(fd)
print("Current source file's absolute path is " + retval + "\n")
fclose(fd)
// get source code file's canonical path
retval = get_canonical_path(strPath)
print("Current source file's canonical path is " + retval + "\n")
// get source code file's last-modified time
retval = get_file_last_modified_time(strPath)
print("Current source file's last modify time is " + retval + "\n")
// set source code file's last-modified time to be 1970/01/01
set_file_last_modified_time(strPath, 0)
retval = get_file_last_modified_time(strPath)
print("After set last modify time to be 0, " _
+ "current source file's last modify time is " + retval + "\n")
// get source code file's size
retval = get_file_size(strPath)
print("Current source file's size is " + retval + "\n")
// is source code file a directory?
retval = is_directory(strPath)
print("Is current source file a directory: " + retval + "\n")
// is source code file executable?
retval = is_file_executable(strPath)
print("Is current source file executable: " + retval + "\n")
// is source code file existing?
retval = is_file_existing(strPath)
print("Is current source file existing: " + retval + "\n")
// is source code file hidden?
retval = is_file_hidden(strPath)
print("Is current source file hidden: " + retval + "\n")
// is source code file normal?
retval = is_file_normal(strPath)
print("Is current source file normal: " + retval + "\n")
// is source code file readable?
retval = is_file_readable(strPath)
print("Is current source file readable: " + retval + "\n")
// is source code file writable?
retval = is_file_writable(strPath)
print("Is current source file writable: " + retval + "\n")
// is source code file path absolute?
retval = is_path_absolute(strPath)
print("Is current source file path absolute: " _
+ retval + "\n")
// is source code file path a symbol link?
retval = is_symbol_link(strPath)
print("Is current source file path symbol link: " _
+ retval + "\n")
// is path1 the parent of source code file path?
Variable strPath1 = "scripts/manual/io and file libs"
retval = is_path_parent(strPath1, strPath)
print("Is " + strPath1 + " parent of " + strPath + " : " _
+ retval + "\n")
// is path2 the same as source code file path?
Variable strPath2 = "scripts/./../scripts/manual/../manual/io and file libs/examples.mfps"
retval = is_path_same(strPath2, strPath)
print("Is " + strPath2 + " same as " + strPath + " : " _
+ retval + "\n")
endf
Output of the above example is shown below. Please note that if the working directory is not AnMath (on Android) or the folder where JCmdLine.jar is located (in PC), running the above example user may see a very different result, or even some errors.
Current working directory is E:\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime
Current source file's absolute path is E:\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime\scripts\manual\io and file libs\examples.mfps
Current source file's canonical path is E:\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime\scripts\manual\io and file libs\examples.mfps
Current source file's last modify time is 1439531707807
After set last modify time to be 0, current source file's last modify time is 0
Current source file's size is 16761
Is current source file a directory: FALSE
Is current source file executable: TRUE
Is current source file existing: TRUE
Is current source file hidden: FALSE
Is current source file normal: TRUE
Is current source file readable: TRUE
Is current source file writable: TRUE
Is current source file path absolute: FALSE
Is current source file path symbol link: FALSE
Is scripts/manual/io and file libs parent of scripts/manual/io and file libs/examples.mfps : TRUE
Is scripts/./../scripts/manual/../manual/io and file libs/examples.mfps same as scripts/manual/io and file libs/examples.mfps : TRUE
Section 5 Functions Similar to Dos and Unix Commands
The above functions only operate on a single file and none of them can delete a file. If user wants to read the file name list in a folder, or wants to move a folder, the above functions cannot be used.
User can use Dos or Unix command to do this work. For example, pwd returns current folder, cd changes current working folder, xcopy or cp copies file, etc. MFP also provides below functions to mimic the OS commands so that user can work in the Command Line as if in a Unix terminal.
Function Name |
Function Info |
cd |
cd(1) : change_dir(path) (with alias cd(path)) changes current directory to string based value path. If successful, it returns true. Otherwise, it returns falses. Examples are change_dir("D:\\Windows") (Windows) and cd("/") (Android). |
change_dir |
change_dir(1) : change_dir(path) (with alias cd(path)) changes current directory to string based value path. If successful, it returns true. Otherwise, it returns falses. Examples are change_dir("D:\\Windows") (Windows) and cd("/") (Android). |
copy_file |
copy_file(3) : copy_file(source, destination, replace_exist) copies file or folder whose path is string source to file or folder whose path is string destination. If the 3rd parameter, replace_exist, is true, then source file (or any file in source folder) will replace destination file (or corresponding file in destination folder) if destination exists. Note that the 3rd parameter is optional. By default it is false. Examples are copy_file("c:\\temp\\try1", "D:\\", true) (Windows) and copy_file("/mnt/sdcard/testfile.txt", "./testfile_copy.txt") (Android). |
create_file |
create_file(2) : create_file(path, is_folder) creates a file (if is_folder is false or does not exist) or folder (if is_folder is true). If the parent of string based parameter path does not exist, the parent will be created. If the file can be created, this function returns true, otherwise, returns false. Examples are create_file("c:\\temp\\try1", true) (Windows) and create_file("testfile_copy.txt") (Android). |
delete_file |
delete_file(2) : delete_file(path, delete_children_in_folder) deletes a file or folder at string based parameter path. If it is a folder and the second parameter is true, all the files in the folder will be recursively deleted. The second parameter is optional. By default, it is false. If the file or folder can be deleted, this function returns true, otherwise, it returns false. Examples are delete_file("c:\\temp\\try1", true) (Windows) and delete_file("testfile_copy.txt") (Android). |
dir |
dir(1) : print_file_list(path) (alias ls(path) or dir(path)) works like ls command in Linux or dir command in Windows. It prints the information for the file or all the files in folder at string based path. It returns the number of entries printed. If the path does not correspond to an existing file or folder, it returns -1. Note that path is optional. By default it is current folder ("."). Examples are dir() (Windows) and ls("../testfile_copy.txt") (Android). |
get_working_dir |
get_working_dir(0) : get_working_dir() (with alias pwd()) returns string based current directory. |
list_files |
list_files(1) : list_files(path) returns all the file names in the folder whose path is the string based parameter path, or it returns the file at path if path corresponds to a file. If the path does not correspond to a file or folder, it returns NULL. Note that parameter path is optional. By default it is current folder ("."). Examples are list_files("c:\\temp\\try1") (Windows) and list_files("../testfile_copy.txt") (Android). |
ls |
ls(1) : print_file_list(path) (alias ls(path) or dir(path)) works like ls command in Linux or dir command in Windows. It prints the information for the file or all the files in folder at string based path. It returns the number of entries printed. If the path does not correspond to an existing file or folder, it returns -1. Note that path is optional. By default it is current folder ("."). Examples are dir() (Windows) and ls("../testfile_copy.txt") (Android). |
move_file |
move_file(3) : move_file(source, destination, replace_exist) moves file or folder whose path is string source to file or INTO (not to) folder whose path is string destination. If the 3rd parameter, replace_exist, is true, then source file (or any file in source folder) will replace destination file (or corresponding file in destination folder) if corresponding file exists. Note that the 3rd parameter is optional. By default it is false. Examples are move_file("c:\\temp\\try1", "D:\\", true) (Windows) and move_file("/mnt/sdcard/testfile.txt", "./testfile_copy.txt") (Android). |
print_file_list |
print_file_list(1) : print_file_list(path) (alias ls(path) or dir(path)) works like ls command in Linux or dir command in Windows. It prints the information for the file or all the files in folder at string based path. It returns the number of entries that printed. If the path does not correspond to an existing file or folder, it returns -1. Note that path is optional. By default it is current folder ("."). Examples are dir() (Windows) and ls("../testfile_copy.txt") (Android). |
pwd |
pwd(0) : get_working_dir() (with alias pwd()) returns string based current directory. |
In the function list, functions cd and change_dir, functions pwd and get_working_dir, and functions ls, dir and print_file_list are three groups of functions. In each group, the functions are exactly the same except the different names. Moreover, the above functions correspond to Dos and Unix commands, as shown below:
1. cd and change_dir: correspond to the cd command in Dos and Unix;
2. pwd and get_working_dir: correspond to the pwd command in Dos and Unix;
3. ls, dir and print_file_list: correspond to the dir command in Dos and the ls command in Unix;
4. copy_file: corresponds to the xcopy command in Dos and cp command in Unix;
5. move_file: corresponds to the move command in Dos and the mv command in Unix;
6. delete_file: corresponds to the del command in Dos and the rm command in Unix;
And there is a list_files function. This function returns all the file names in a folder. Its difference from function dir (or ls or print_file_list) is that list_files returns an array and each element in the array is a string based file name, while dir prints all the files’ names, modified time and other properties on the screen. Function dir is very useful when user works in Command Line while list_files should be chosen when programming.
The following example is for the above functions. This example can be found in the examples.mfps file in io and file libs sub-folder in the manual’s sample code folder.
Help
@language:
test file operation commands
@end
@language:simplified_chinese
测试文件整体操作函数
@end
endh
function fileOpr()
// Assume current working directory is AnMath in Android
// or the folder where JCmdline.jar is located (for
// Scientific Calculator for JAVA)
Variable strOriginalPWD = pwd()
printf("Current directory is " + strOriginalPWD + "\n")
// now move to scripts/manual/io and file libs/
cd("scripts/manual/io and file libs/")
printf("After cd, current directory is " + pwd() + "\n")
// now print content in the folder
dir(pwd())
// now create a file in a sub-folder
create_file("test_folder/test_file.txt")
// print content in the folder after create_file
print("After create test_folder/test_file.txt, run dir:\n")
dir(pwd())
print("After create test_folder/test_file.txt, run dir for test_folder:\n")
dir("test_folder")
move_file("test_folder","test_folder1")
// print content in the folder after move_file
print("After move folder test_folder to test_folder1, run dir:\n")
dir(pwd())
if delete_file("test_folder1") == false
print("Cannot delete a folder with file inside " _
+ "if delete_children_in_folder flag is not set\n")
if delete_file("test_folder1", true)
print("Can delete a folder with file inside " _
+ "if delete_children_in_folder flag is set to true\n")
endif
endif
// print content in the folder after delete_file
print("After delete folder test_folder1, run dir:\n")
dir(pwd())
// return to the original working directory
cd(strOriginalPWD)
endf
Output of the above example is shown below. Please note that if the working directory is not AnMath (on Android) or the folder where JCmdLine.jar is located (in PC), running the above example user may see a very different result, or even some errors.
Current directory is E:\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime
After cd, current directory is E:\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime\scripts\manual\io and file libs
-rwx examples.mfps 18897 2015-08-14 18:17:29
-rwx test_read.txt 33 2015-08-13 14:58:55
-rwx test_rw.bin 21 2015-08-14 13:04:55
-rwx test_write.txt 135 2015-08-13 15:37:46
After create file test_folder/test_file.txt, run dir:
-rwx examples.mfps 18897 2015-08-14 18:17:29
drwx test_folder\ 0 2015-08-14 18:17:42
-rwx test_read.txt 33 2015-08-13 14:58:55
-rwx test_rw.bin 21 2015-08-14 13:04:55
-rwx test_write.txt 135 2015-08-13 15:37:46
After create file test_folder/test_file.txt, run dir for test_folder:
-rwx test_file.txt 0 2015-08-14 18:17:42
After move folder test_folder to test_folder1, run dir:
-rwx examples.mfps 18897 2015-08-14 18:17:29
drwx test_folder1\ 0 2015-08-14 18:17:42
-rwx test_read.txt 33 2015-08-13 14:58:55
-rwx test_rw.bin 21 2015-08-14 13:04:55
-rwx test_write.txt 135 2015-08-13 15:37:46
Cannot delete a folder with file inside if delete_children_in_folder flag is not set
Can delete a folder with file inside if delete_children_in_folder flag is set to true
After delete folder test_folder1, run dir:
-rwx examples.mfps 18897 2015-08-14 18:17:29
-rwx test_read.txt 33 2015-08-13 14:58:55
-rwx test_rw.bin 21 2015-08-14 13:04:55
-rwx test_write.txt 135 2015-08-13 15:37:46
Section 6 An Example of Comprehensive File Operations
This chapter has introduced all of the file operation functions provided by MFP. With them, user is able to do anything on any file if s\he has the authorization. In this section, a comprehensive file operation example is provided to demonstrate the power of MFP.
In Scientific Calculator Plus, function set_array_elem (refer to part 3 in Section 3 of Chapter 3 for details) may assign value to an element in an array and returns the new array. The original array, which is the parameter, may or may not be changed. Even if it is changed, changed value may not be the same as the returned value. In other words, user has to use the returned value as the updated array. This means the right way to call set_array_elem is:
array_to_change = set_array_elem(array_to_change, index, value)
. However, in revision 1.6.6 or earlier, set_array_elem will change the parameter to the new value. In other words, user needs not to retrieve the return value of set_array_elem. Thus many user calls this function in the following way:
set_array_elem(array_to_change, index, value)
, and simply continue to use array_to_change after the function call. However, this will not guarantee correctness after revision 1.7. It is strongly recommended to change code now.
The code change can be performed manually. In this way user has to search all the set_array_elem calls and modify it line by line. This is time-expensive and mistake-prone.
Alternatively user can develop an MFP script to search and change set_array_elem calls. This is much faster and unlikely it will make mistakes.
A question is, will change of source code affect running functions? Fortunately the answer is no because Scientific Calculator Plus automatically loads in all the codes at start. The code will not be reloaded until user restarts Scientific Calculator Plus, or in PC the GUI based Scientific Calculator Plus for JAVA gets the focus back. However, please note that this does not mean Scientific Calculator Plus will never dynamically load code in the future. Thus user still has to be cautious to run script to change code.
To change source code, a script needs to:
1. find all the .mfps files in the scripts folder;
2. search every line of each file and locate the old-style set_array_elem calls;
3. modify some lines in each file and save.
In order to find all the .mfps files in a folder and its sub-folders, functions list_files, is_directory and is_file_normal must be used. List_files lists all the sub-folders and files in the scripts folder, and then script goes through these sub-folders and files. Is_directory is able to tell sub-folders from files. If a file is found, script needs to verify that it is a .mfps file. Then is_file_normal is called to identify if it is a normal file. If a sub-folder is found, script calls list_files again and repeats the above steps.
To achieve the above routine, one solution is to use iteration function, i.e. each time a new sub-folder is found, the iteration function is called. The other way is to use an array to store all the folder and sub-folders. Every time a new sub-folder is found, it is appended to the array until the size of the array no longer increases and all the folders in the array have been searched. The following code chooses the second approach:
// all_mfps_files is a 1D array.
// Each element is the path of a source file.
Variable all_mfps_files = []
// all_folders is a 1D array.
//Each element is a folder or sub-folder.
Variable all_folders = [strScriptsPath]
Variable folder_idx = 0
// go through all_folders. Note that during the procedure
// all_folders is still increasing its size.
While(folder_idx < size(all_folders)[0])
// list all the files in a folder
Variable these_files = list_files(all_folders[folder_idx])
// go through all the files. Note that these_files is a
// 1D array so that size(these_files)[0] must be the size
// of the array. Also note that the array’s index starts
// from 0 to array size – 1.
For variable idx = 0 to size(these_files)[0] - 1 step 1
Variable this_file_name = these_files[idx]
this_file_name = all_folders[folder_idx] _
+ get_file_separator() _
+ this_file_name
If(is_directory(this_file_name))
//If this_file_name is a folder, add it to all_folders.
All_folders = set_array_elem(all_folders, _
size(all_folders), _
this_file_name)
Elseif and(stricmp(strsub(this_file_name, _
strlen(this_file_name)-5), ".mfps")==0, _
is_file_normal(this_file_name))
// if this_file_name is a .mfps source file, add it to
// all_mfp_files.
all_mfps_files = set_array_elem(all_mfps_files, _
size(all_mfps_files), _
this_file_name)
Endif
Next
folder_idx = folder_idx + 1
Loop
After every mfps source file is found, the script starts to read each line of the source file to see if it is an old-style set_array_elem call. Note that old-style set_array_elem call means that, after trimming the blanks from the head and tail, set_array_elem is the beginning of the line, and then round bracket (note that blanks may exist between set_array_elem and bracket), then comma (note that blanks may exist between comma and to-be-changed array name). Because of a clear pattern exists, split function can be used to separate code line into pieces and then identify if the first piece is set_array_elem. The code is shown below:
// Assume file has been opened, now read:
Variable strLine = freadline(fd)
// Note that the regex string for "(" is not "(" but "\\(" because
// split function uses "(" as a regex control character so that
// to escape.
Variable strarray1 = split(strline, "\\(")
// If at least 2 sub-strings after stpliting and the first one is
// set_array_elem after trimming the white spaces.
If and(size(strarray1)[0] >= 2, _
Stricmp(trim(strarray1[0]), "set_array_elem") == 0)
// No need to escape comma which is not a regex
// control character.
Variable strarray2 = split(strarray1[1], ",")
If size(strarray2)[0] >= 2
// Should have at least two sub-strings, otherwise may mean
// no comma.
// Now we can confirm that this line needs change.
……
Endif
EndIf
Change the old-style set_array_elem call to the new-style is fairly simple. Adding the array name and assignment is enough. The code to do this work is shown below:
StrLine = strarray2[0] + " = " + trim(strLine)
, where strarray2[0] is the to-be-changed array name (see the above code snip for details).
Then write the line into a new file:
Fprintf(fd1, "%s\n", strLine)
. After the new file is created, call function move_file to replace old MFP code by the new one. The whole example is shown below. This example can be found in the examples.mfps file in io and file libs sub-folder in the manual’s sample code folder.
Help
@language:
a complicated file operation example
@end
@language:simplified_chinese
一个复杂的文件操作的例子
@end
endh
function fileOpr2()
Variable strConfirm
// first get current working directory, should be AnMath
// in Android or the folder where JCmdline.jar is located
// (for Scientific Calculator for JAVA)
Variable strOriginalPWD = pwd()
printf("Current directory is " + strOriginalPWD + "\n")
// confirm it is the right working folder
printf("Is this AnMath folder in Android " _
+ "or if you are working on Scientific Calculator for JAVA, " _
+ "is the folder where JCmdline.jar is located?\n")
strConfirm = input("Y for yes and other for no:", "S")
if and(stricmp(strConfirm, "Y") != 0, stricmp(strConfirm, "Yes") !=0)
//exit if not in the right working directory
print("You are not in the right working directory, exit!\n")
return
endif
// the scripts folder
Variable strScriptsPath = strOriginalPWD + get_file_separator() _
+ "scripts"
// Please back up your source code first
Print("Please back up your source codes before run the program!!!\n")
// have you backed up your source codes, if no I cannot continue.
Print("Have you backed up your source codes?\n")
strConfirm = input("Y for yes and other for no:", "S")
if and(stricmp(strConfirm, "Y") != 0, stricmp(strConfirm, "Yes") !=0)
// If you haven't backed up your codes, I will do it for you.
print("If haven't been backed up, I will do it for you!\n")
pause("Press ENTER to start back up.")
copy_file(strScriptsPath, strScriptsPath + ".bakup", true)
endif
// ok, now it is the right working directory and source code has been
// backed up. Preparation work has finished, press enter to continue.
pause("Now preparation work has finished, press Enter to continue")
// all_mfps_files is a 1D array with each element path of a .mfps src
Variable all_mfps_files = []
// all_folders is also a 1D array, each element is path of a folder
// including source codes
Variable all_folders = [strScriptsPath]
Variable folder_idx = 0
// Go through all_folders, note that in the procedure all_folders is
// increasing
While(folder_idx < size(all_folders)[0])
// list all the files in a folder
Variable these_files = list_files(all_folders[folder_idx])
// Go through the files. Note that these_files is a 1D array so
// size(these_files)[0] must be equal to the length of the array
// Also note that index is from 0 to array length - 1.
For variable idx = 0 to size(these_files)[0] - 1 step 1
Variable this_file_name = these_files[idx]
this_file_name = all_folders[folder_idx] + get_file_separator() _
+ this_file_name
If(is_directory(this_file_name))
// If this file is actually a folder, append it to all_folders
All_folders = set_array_elem(all_folders, _
size(all_folders), _
this_file_name)
Elseif and(stricmp(strsub(this_file_name, _
strlen(this_file_name)-5), ".mfps") == 0, _
is_file_normal(this_file_name))
// If this file is a .mfps source file, append it to
// all_mfps_files
all_mfps_files = set_array_elem(all_mfps_files, _
size(all_mfps_files), _
this_file_name)
Endif
Next
folder_idx = folder_idx + 1
Loop
// Now all_mfps_files includes all the .mfps files
For variable idx = 0 to size(all_mfps_files)[0] - 1 step 1
// create a temporary source file to write the modified code in
// set encode UTF-8 to ensure that unicode (e.g. Chinese and
// Japanese characters) is supported
Variable fd1 = fopen("temporary_src_file","w", "UTF-8")
print("Now analyse " + all_mfps_files[idx] + "\n")
Variable fd = fopen(all_mfps_files[idx], "r", "UTF-8")
Variable idxLine = 0
while (!feof(fd))
idxLine = idxLine + 1
Variable strLine = freadline(fd)
// Note that the regex string for "(" is "\\(" not "(" because
// split function uses "(" as a regex control character so that
// have to escape.
Variable strarray1 = split(strline, "\\(")
// If at least 2 sub strings after splitting and the first one
// is set_array_elem after trimming the white spaces
If and(size(strarray1)[0] >= 2, _
Stricmp(trim(strarray1[0]), "set_array_elem") == 0)
// need not to escape "," for regex, different from "("
Variable strarray2 = split(strarray1[1], ",")
If size(strarray2)[0] >= 2
// Should have at least two sub strings, otherwise may mean
// no comma.
// Now we can confirm that this line needs change.
print("\tset_elem_array calling statement to change at" _
+ " Line " + idxLine + "\n")
print("\tBefore change is : " + strLine + "\n")
StrLine = strarray2[0] + " = " + trim(strLine)
print("\tAfter change is : " + strLine + "\n")
Endif
EndIf
// write strLine into temporary source file
fprintf(fd1, "%s\n", strLine)
Loop
fclose(fd1)
fclose(fd)
//move temporary file to replace all_mfps_files[idx]
move_file("temporary_src_file", all_mfps_files[idx], true)
Next
//Done!
printf("Done!\n")
endf
The procedure of the above code is:
1. identify if current working folder is AnMath in Android or the folder where JCmdLine.jar is placed (in PC). If the working folder is wrong, no source code file can be found;
2. remind user to back up. If user hasn’t done it, the script will do this for user by copying scripts folder to scripts.bakup;
3. find all the .mfps source files;
4. find all old-style set_array_elem calls;
5. modify and source code files and save the modified files to a new place;
6. copy the modified files to replace the old ones.
The outcome of the program is below. Note that the output varies with user source libs, i.e. different user sees different output. But after the program finishes, user should see all the set_array_elem functions are called in the new way.
Current directory is C:\Users\tonyc\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime
Is this AnMath folder in Android or if you are working on Scientific Calculator for JAVA, is the folder where JCmdline.jar is located?
Y for yes and other for no:Y
Please back up your source codes before run the program!!!
Have you backed up your source codes?
Y for yes and other for no:n
If haven't been backed up, I will do it for you!
Press ENTER to start back up.
Now preparation work has finished, press Enter to continue
Now analyse C:\Users\tonyc\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime\scripts\examples\math.mfps
Now analyse C:\Users\tonyc\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime\scripts\examples\misc.mfps
Now analyse C:\Users\tonyc\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime\scripts\userdef_lib\506.mfps
Now analyse C:\Users\tonyc\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime\scripts\userdef_lib\biao.mfps
……
Now analyse C:\Users\tonyc\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime\scripts\userdef_lib\cha_ru.mfps
Now analyse C:\Users\tonyc\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime\scripts\userdef_lib\cv100plus测试.mfps
Now analyse C:\Users\tonyc\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime\scripts\userdef_lib\捻系数.mfps
Now analyse C:\Users\tonyc\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime\scripts\userdef_lib\支偏计算.mfps
Now analyse C:\Users\tonyc\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime\scripts\userdef_lib\断强计算.mfps
Now analyse C:\Users\tonyc\Development\workspace\AnMath\misc\marketing\JCmdLine_runtime\scripts\userdef_lib\落棉率.mfps
set_elem_array calling statement to change at Line 35
Before change is : set_array_elem(luo_mian_lv_s,idx2,luo_mian_lv)
After change is : luo_mian_lv_s = set_array_elem(luo_mian_lv_s,idx2,luo_mian_lv)
……
Summary
Input / output and file operation is an important part of MFP advanced programming. MFP programming language provides a set of C-like I/O functions to read/write console, string and file. Furthermore, MFP programming language includes functions to change directory, list files in a folder and copy, move and delete files. With these functions, as long as user has authorization, any file in OS can be operated.
Please note that file operation in Android sometimes is dangerous. Because files are hidden from users, after program finishes user is not able to easily confirm right files are changed or check result. In this way, it is strongly recommended to create a working folder in AnMath directory and confine all the file operations inside it.