diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1997-06-26 17:39:10 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1997-06-26 17:39:10 -0300 |
commit | da585783e33f92f8dff6fd47a89671494adc11e0 (patch) | |
tree | aa1a0f59eea602c6622427b573e9b85e94f79b66 | |
parent | e81f1841644405845e7de6bd70a0f074cced3d81 (diff) | |
download | lua-da585783e33f92f8dff6fd47a89671494adc11e0.tar.gz lua-da585783e33f92f8dff6fd47a89671494adc11e0.tar.bz2 lua-da585783e33f92f8dff6fd47a89671494adc11e0.zip |
new method to handle current files, with global variables
_INPUT and _OUTPUT.
-rw-r--r-- | iolib.c | 89 | ||||
-rw-r--r-- | manual.tex | 91 |
2 files changed, 105 insertions, 75 deletions
@@ -10,8 +10,6 @@ | |||
10 | #include "lualib.h" | 10 | #include "lualib.h" |
11 | 11 | ||
12 | 12 | ||
13 | FILE *lua_infile, *lua_outfile; | ||
14 | |||
15 | int lua_tagio; | 13 | int lua_tagio; |
16 | 14 | ||
17 | 15 | ||
@@ -39,59 +37,80 @@ static void pushresult (int i) | |||
39 | } | 37 | } |
40 | 38 | ||
41 | 39 | ||
42 | static void closefile (FILE *f) | 40 | |
41 | static FILE *getfile (char *name) | ||
43 | { | 42 | { |
44 | if (f == stdin || f == stdout) | 43 | lua_Object f = lua_getglobal(name); |
45 | return; | 44 | if (lua_tag(f) != lua_tagio) |
46 | if (f == lua_infile) | 45 | luaL_verror("global variable %s is not a file handle", name); |
47 | lua_infile = stdin; | 46 | return lua_getuserdata(f); |
48 | if (f == lua_outfile) | 47 | } |
49 | lua_outfile = stdout; | 48 | |
49 | |||
50 | static void closefile (char *name) | ||
51 | { | ||
52 | FILE *f = getfile(name); | ||
53 | if (f == stdin || f == stdout) return; | ||
50 | if (pclose(f) == -1) | 54 | if (pclose(f) == -1) |
51 | fclose(f); | 55 | fclose(f); |
52 | } | 56 | } |
53 | 57 | ||
54 | 58 | ||
59 | static void setfile (FILE *f, char *name) | ||
60 | { | ||
61 | lua_pushusertag(f, lua_tagio); | ||
62 | lua_setglobal(name); | ||
63 | } | ||
64 | |||
65 | |||
66 | static void setreturn (FILE *f, char *name) | ||
67 | { | ||
68 | setfile(f, name); | ||
69 | lua_pushusertag(f, lua_tagio); | ||
70 | } | ||
71 | |||
55 | 72 | ||
56 | static void io_readfrom (void) | 73 | static void io_readfrom (void) |
57 | { | 74 | { |
75 | FILE *current; | ||
58 | lua_Object f = lua_getparam(1); | 76 | lua_Object f = lua_getparam(1); |
59 | if (f == LUA_NOOBJECT) | 77 | if (f == LUA_NOOBJECT) { |
60 | closefile(lua_infile); /* restore standart input */ | 78 | closefile("_INPUT"); |
79 | current = stdin; | ||
80 | } | ||
61 | else if (lua_tag(f) == lua_tagio) | 81 | else if (lua_tag(f) == lua_tagio) |
62 | lua_infile = lua_getuserdata(f); | 82 | current = lua_getuserdata(f); |
63 | else { | 83 | else { |
64 | char *s = luaL_check_string(1); | 84 | char *s = luaL_check_string(1); |
65 | FILE *fp = (*s == '|') ? popen(s+1, "r") : fopen(s, "r"); | 85 | current = (*s == '|') ? popen(s+1, "r") : fopen(s, "r"); |
66 | if (fp) | 86 | if (current == NULL) { |
67 | lua_infile = fp; | ||
68 | else { | ||
69 | pushresult(0); | 87 | pushresult(0); |
70 | return; | 88 | return; |
71 | } | 89 | } |
72 | } | 90 | } |
73 | lua_pushusertag(lua_infile, lua_tagio); | 91 | setreturn(current, "_INPUT"); |
74 | } | 92 | } |
75 | 93 | ||
76 | 94 | ||
77 | static void io_writeto (void) | 95 | static void io_writeto (void) |
78 | { | 96 | { |
97 | FILE *current; | ||
79 | lua_Object f = lua_getparam(1); | 98 | lua_Object f = lua_getparam(1); |
80 | if (f == LUA_NOOBJECT) | 99 | if (f == LUA_NOOBJECT) { |
81 | closefile(lua_outfile); /* restore standart output */ | 100 | closefile("_OUTPUT"); |
101 | current = stdout; | ||
102 | } | ||
82 | else if (lua_tag(f) == lua_tagio) | 103 | else if (lua_tag(f) == lua_tagio) |
83 | lua_outfile = lua_getuserdata(f); | 104 | current = lua_getuserdata(f); |
84 | else { | 105 | else { |
85 | char *s = luaL_check_string(1); | 106 | char *s = luaL_check_string(1); |
86 | FILE *fp = (*s == '|') ? popen(s+1,"w") : fopen(s,"w"); | 107 | current = (*s == '|') ? popen(s+1,"w") : fopen(s,"w"); |
87 | if (fp) | 108 | if (current == NULL) { |
88 | lua_outfile = fp; | ||
89 | else { | ||
90 | pushresult(0); | 109 | pushresult(0); |
91 | return; | 110 | return; |
92 | } | 111 | } |
93 | } | 112 | } |
94 | lua_pushusertag(lua_outfile, lua_tagio); | 113 | setreturn(current, "_OUTPUT"); |
95 | } | 114 | } |
96 | 115 | ||
97 | 116 | ||
@@ -99,10 +118,8 @@ static void io_appendto (void) | |||
99 | { | 118 | { |
100 | char *s = luaL_check_string(1); | 119 | char *s = luaL_check_string(1); |
101 | FILE *fp = fopen (s, "a"); | 120 | FILE *fp = fopen (s, "a"); |
102 | if (fp != NULL) { | 121 | if (fp != NULL) |
103 | lua_outfile = fp; | 122 | setreturn(fp, "_OUTPUT"); |
104 | lua_pushusertag(lua_outfile, lua_tagio); | ||
105 | } | ||
106 | else | 123 | else |
107 | pushresult(0); | 124 | pushresult(0); |
108 | } | 125 | } |
@@ -112,6 +129,7 @@ static void io_appendto (void) | |||
112 | 129 | ||
113 | static void io_read (void) | 130 | static void io_read (void) |
114 | { | 131 | { |
132 | FILE *f = getfile("_INPUT"); | ||
115 | char *buff; | 133 | char *buff; |
116 | char *p = luaL_opt_string(1, "[^\n]*{\n}"); | 134 | char *p = luaL_opt_string(1, "[^\n]*{\n}"); |
117 | int inskip = 0; /* to control {skips} */ | 135 | int inskip = 0; /* to control {skips} */ |
@@ -131,7 +149,7 @@ static void io_read (void) | |||
131 | else { | 149 | else { |
132 | char *ep = luaL_item_end(p); /* get what is next */ | 150 | char *ep = luaL_item_end(p); /* get what is next */ |
133 | int m; /* match result */ | 151 | int m; /* match result */ |
134 | if (c == NEED_OTHER) c = getc(lua_infile); | 152 | if (c == NEED_OTHER) c = getc(f); |
135 | m = (c == EOF) ? 0 : luaL_singlematch((char)c, p); | 153 | m = (c == EOF) ? 0 : luaL_singlematch((char)c, p); |
136 | if (m) { | 154 | if (m) { |
137 | if (inskip == 0) luaI_addchar(c); | 155 | if (inskip == 0) luaI_addchar(c); |
@@ -152,7 +170,7 @@ static void io_read (void) | |||
152 | } | 170 | } |
153 | } break_while: | 171 | } break_while: |
154 | if (c >= 0) /* not EOF nor NEED_OTHER? */ | 172 | if (c >= 0) /* not EOF nor NEED_OTHER? */ |
155 | ungetc(c, lua_infile); | 173 | ungetc(c, f); |
156 | buff = luaI_addchar(0); | 174 | buff = luaI_addchar(0); |
157 | if (*buff != 0 || *p == 0) /* read something or did not fail? */ | 175 | if (*buff != 0 || *p == 0) /* read something or did not fail? */ |
158 | lua_pushstring(buff); | 176 | lua_pushstring(buff); |
@@ -161,11 +179,12 @@ static void io_read (void) | |||
161 | 179 | ||
162 | static void io_write (void) | 180 | static void io_write (void) |
163 | { | 181 | { |
182 | FILE *f = getfile("_OUTPUT"); | ||
164 | int arg = 1; | 183 | int arg = 1; |
165 | int status = 1; | 184 | int status = 1; |
166 | char *s; | 185 | char *s; |
167 | while ((s = luaL_opt_string(arg++, NULL)) != NULL) | 186 | while ((s = luaL_opt_string(arg++, NULL)) != NULL) |
168 | status = status && (fputs(s, lua_outfile) != EOF); | 187 | status = status && (fputs(s, f) != EOF); |
169 | pushresult(status); | 188 | pushresult(status); |
170 | } | 189 | } |
171 | 190 | ||
@@ -300,7 +319,11 @@ static struct luaL_reg iolib[] = { | |||
300 | void iolib_open (void) | 319 | void iolib_open (void) |
301 | { | 320 | { |
302 | lua_tagio = lua_newtag(); | 321 | lua_tagio = lua_newtag(); |
303 | lua_infile=stdin; lua_outfile=stdout; | 322 | setfile(stdin, "_INPUT"); |
323 | setfile(stdout, "_OUTPUT"); | ||
324 | setfile(stdin, "_STDIN"); | ||
325 | setfile(stdout, "_STDOUT"); | ||
326 | setfile(stderr, "_STDERR"); | ||
304 | luaL_openlib(iolib, (sizeof(iolib)/sizeof(iolib[0]))); | 327 | luaL_openlib(iolib, (sizeof(iolib)/sizeof(iolib[0]))); |
305 | lua_pushcfunction(errorfb); | 328 | lua_pushcfunction(errorfb); |
306 | lua_seterrormethod(); | 329 | lua_seterrormethod(); |
@@ -1,4 +1,4 @@ | |||
1 | % $Id: manual.tex,v 2.4 1997/06/19 18:49:40 roberto Exp roberto $ | 1 | % $Id: manual.tex,v 2.5 1997/06/20 19:28:16 roberto Exp roberto $ |
2 | 2 | ||
3 | \documentstyle[fullpage,11pt,bnf]{article} | 3 | \documentstyle[fullpage,11pt,bnf]{article} |
4 | 4 | ||
@@ -38,7 +38,7 @@ Waldemar Celes | |||
38 | \tecgraf\ --- Computer Science Department --- PUC-Rio | 38 | \tecgraf\ --- Computer Science Department --- PUC-Rio |
39 | } | 39 | } |
40 | 40 | ||
41 | \date{\small \verb$Date: 1997/06/19 18:49:40 $} | 41 | \date{\small \verb$Date: 1997/06/20 19:28:16 $} |
42 | 42 | ||
43 | \maketitle | 43 | \maketitle |
44 | 44 | ||
@@ -1034,7 +1034,7 @@ This method cannot be set for tables with default tag. | |||
1034 | function settable_event (table, index, value) | 1034 | function settable_event (table, index, value) |
1035 | local tm = gettagmethod(tag(table), "settable") | 1035 | local tm = gettagmethod(tag(table), "settable") |
1036 | if tm then | 1036 | if tm then |
1037 | return tm(table, index, value) | 1037 | tm(table, index, value) |
1038 | elseif type(table) ~= "table" then | 1038 | elseif type(table) ~= "table" then |
1039 | error("indexed expression not a table") | 1039 | error("indexed expression not a table") |
1040 | else | 1040 | else |
@@ -1598,11 +1598,10 @@ If \verb|retmode| is absent, | |||
1598 | all results from \verb|func| are just returned by the call. | 1598 | all results from \verb|func| are just returned by the call. |
1599 | If \verb|retmode| is equal to \verb|"pack"|, | 1599 | If \verb|retmode| is equal to \verb|"pack"|, |
1600 | the results are {\em packed\/} in a single table.\index{packed results} | 1600 | the results are {\em packed\/} in a single table.\index{packed results} |
1601 | That is, \verb|call| returns just one table. | 1601 | That is, \verb|call| returns just one table; |
1602 | At index \verb|n|, the table has the total number of results | 1602 | at index \verb|n|, the table has the total number of results |
1603 | from the call; | 1603 | from the call; |
1604 | the first result is at index 1, etc. | 1604 | the first result is at index 1, etc. |
1605 | |||
1606 | For instance, the following calls produce the following results: | 1605 | For instance, the following calls produce the following results: |
1607 | \begin{verbatim} | 1606 | \begin{verbatim} |
1608 | a = call(sin, {5}) --> a = 0.0871557 = sin(5) | 1607 | a = call(sin, {5}) --> a = 0.0871557 = sin(5) |
@@ -1666,7 +1665,9 @@ semantically, there is no difference between a | |||
1666 | field not present in a table or a field with value \nil. | 1665 | field not present in a table or a field with value \nil. |
1667 | Therefore, the function only considers fields with non \nil\ values. | 1666 | Therefore, the function only considers fields with non \nil\ values. |
1668 | The order in which the indices are enumerated is not specified, | 1667 | The order in which the indices are enumerated is not specified, |
1669 | {\em not even for numeric indices}. | 1668 | {\em not even for numeric indices} |
1669 | (to traverse a table in numeric order, | ||
1670 | use a counter). | ||
1670 | If the table is modified in any way during a traversal, | 1671 | If the table is modified in any way during a traversal, |
1671 | the semantics of \verb|next| is undefined. | 1672 | the semantics of \verb|next| is undefined. |
1672 | 1673 | ||
@@ -1904,7 +1905,7 @@ stands for the value of the n-th captured substring. | |||
1904 | 1905 | ||
1905 | If \verb|repl| is a function, then this function is called every time a | 1906 | If \verb|repl| is a function, then this function is called every time a |
1906 | match occurs, with the following arguments: | 1907 | match occurs, with the following arguments: |
1907 | If \verb|table| is present, the the first argument is this table | 1908 | If \verb|table| is present, then the first argument is this table |
1908 | and the second one is a match counter (1 for the first call). | 1909 | and the second one is a match counter (1 for the first call). |
1909 | Independently of these two optional arguments, | 1910 | Independently of these two optional arguments, |
1910 | all captured substrings are passed as arguments, | 1911 | all captured substrings are passed as arguments, |
@@ -2072,10 +2073,21 @@ range \Math{[0,1)}. | |||
2072 | 2073 | ||
2073 | \subsection{I/O Facilities} \label{libio} | 2074 | \subsection{I/O Facilities} \label{libio} |
2074 | 2075 | ||
2075 | All input and output operations in Lua are done over two {\em current\/} files: | 2076 | All input and output operations in Lua are done over two |
2076 | one for reading and one for writing. | 2077 | \Def{file handles}, one for reading and one for writing. |
2077 | Initially, the current input file is \verb|stdin|, | 2078 | These handles are stored in two Lua global variables, |
2078 | and the current output file is \verb|stdout|. | 2079 | called \verb|_INPUT| and \verb|_OUTPUT|. |
2080 | The global variables | ||
2081 | \verb|_STDIN|, \verb|_STDOUT| and \verb|_STDERR| | ||
2082 | are initialized with file descriptors for | ||
2083 | \verb|stdin|, \verb|stdout| and \verb|stderr|. | ||
2084 | Initially, \verb|_INPUT=_STDIN| and \verb|_OUTPUT=_STDOUT|. | ||
2085 | \Deffunc{_INPUT}\Deffunc{_OUTPUT} | ||
2086 | \Deffunc{_STDIN}\Deffunc{_STDOUT}\Deffunc{_STDERR} | ||
2087 | |||
2088 | A file handle is a userdata containing the file stream \verb|FILE*|, | ||
2089 | and with a distinctive tag created by the I/O library. | ||
2090 | |||
2079 | 2091 | ||
2080 | Unless otherwise stated, | 2092 | Unless otherwise stated, |
2081 | all I/O functions return \nil\ on failure and | 2093 | all I/O functions return \nil\ on failure and |
@@ -2083,18 +2095,16 @@ some value different from \nil\ on success. | |||
2083 | 2095 | ||
2084 | \subsubsection*{\ff {\tt readfrom (filename)}}\Deffunc{readfrom} | 2096 | \subsubsection*{\ff {\tt readfrom (filename)}}\Deffunc{readfrom} |
2085 | 2097 | ||
2086 | This function may be called in three ways. | 2098 | This function may be called in two ways. |
2087 | When called with a file name, | 2099 | When called with a file name, it opens the named file, |
2088 | it opens the named file, | 2100 | sets its handle as the value of \verb|_INPUT|, |
2089 | sets it as the {\em current\/} input file, | 2101 | and returns this value. |
2090 | and returns a {\em handle\/} to the file | ||
2091 | (this handle is a userdata containing the file stream \verb|FILE*|). | ||
2092 | It does not close the current input file. | 2102 | It does not close the current input file. |
2093 | When called with a file handle returned by a previous call, | 2103 | %When called with a file handle returned by a previous call, |
2094 | it restores the file as the current input. | 2104 | %it simply assigns it to \verb|_INPUT|. |
2095 | When called without parameters, | 2105 | When called without parameters, |
2096 | it closes the current input file, | 2106 | it closes the \verb|_INPUT| file, |
2097 | and restores \verb|stdin| as the current input file. | 2107 | and restores \verb|stdin| as the value of \verb|_INPUT|. |
2098 | 2108 | ||
2099 | If this function fails, it returns \nil, | 2109 | If this function fails, it returns \nil, |
2100 | plus a string describing the error. | 2110 | plus a string describing the error. |
@@ -2105,28 +2115,26 @@ plus a string describing the error. | |||
2105 | then a \Index{piped input} is open, via function \IndexVerb{popen}. | 2115 | then a \Index{piped input} is open, via function \IndexVerb{popen}. |
2106 | Not all systems implement pipes. | 2116 | Not all systems implement pipes. |
2107 | Moreover, | 2117 | Moreover, |
2108 | the number of files that can be open at the same time is usually limited and | 2118 | the number of files that can be open at the same time is |
2109 | depends on the system. | 2119 | usually limited and depends on the system. |
2110 | \end{quotation} | 2120 | \end{quotation} |
2111 | 2121 | ||
2112 | \subsubsection*{\ff {\tt writeto (filename)}}\Deffunc{writeto} | 2122 | \subsubsection*{\ff {\tt writeto (filename)}}\Deffunc{writeto} |
2113 | 2123 | ||
2114 | This function may be called in three ways. | 2124 | This function may be called in two ways. |
2115 | When called with a file name, | 2125 | When called with a file name, |
2116 | it opens the named file, | 2126 | it opens the named file, |
2117 | sets it as the {\em current\/} output file, | 2127 | sets its handle as the value of \verb|_OUTPUT|, |
2118 | and returns a {\em handle\/} to the file | 2128 | and returns this value. |
2119 | (this handle is a user data containing the file stream \verb|FILE*|). | ||
2120 | It does not close the current output file. | 2129 | It does not close the current output file. |
2121 | Notice that, if the file already exists, | 2130 | Notice that, if the file already exists, |
2122 | then it will be {\em completely erased\/} with this operation. | 2131 | then it will be {\em completely erased\/} with this operation. |
2123 | When called with a file handle returned by a previous call, | 2132 | %When called with a file handle returned by a previous call, |
2124 | it restores the file as the current output. | 2133 | %it restores the file as the current output. |
2125 | When called without parameters, | 2134 | When called without parameters, |
2126 | this function closes the current output file, | 2135 | this function closes the \verb|_OUTPUT| file, |
2127 | and restores \verb|stdout| as the current output file. | 2136 | and restores \verb|stdout| as the value of \verb|_OUTPUT|. |
2128 | \index{closing a file} | 2137 | \index{closing a file} |
2129 | %%LHF: nao tem como escrever em stderr, tem? | ||
2130 | 2138 | ||
2131 | If this function fails, it returns \nil, | 2139 | If this function fails, it returns \nil, |
2132 | plus a string describing the error. | 2140 | plus a string describing the error. |
@@ -2137,16 +2145,14 @@ plus a string describing the error. | |||
2137 | then a \Index{piped output} is open, via function \IndexVerb{popen}. | 2145 | then a \Index{piped output} is open, via function \IndexVerb{popen}. |
2138 | Not all systems implement pipes. | 2146 | Not all systems implement pipes. |
2139 | Moreover, | 2147 | Moreover, |
2140 | the number of files that can be open at the same time is usually limited and | 2148 | the number of files that can be open at the same time is |
2141 | depends on the system. | 2149 | usually limited and depends on the system. |
2142 | \end{quotation} | 2150 | \end{quotation} |
2143 | 2151 | ||
2144 | \subsubsection*{\ff {\tt appendto (filename)}}\Deffunc{appendto} | 2152 | \subsubsection*{\ff {\tt appendto (filename)}}\Deffunc{appendto} |
2145 | 2153 | ||
2146 | This function opens a file named \verb|filename| and sets it as the | 2154 | This function opens a file named \verb|filename| and sets it as the |
2147 | {\em current\/} output file. | 2155 | value of \verb|_OUTPUT|. |
2148 | It returns the file handle, | ||
2149 | or \nil\ in case of error. | ||
2150 | Unlike the \verb|writeto| operation, | 2156 | Unlike the \verb|writeto| operation, |
2151 | this function does not erase any previous content of the file. | 2157 | this function does not erase any previous content of the file. |
2152 | If this function fails, it returns \nil, | 2158 | If this function fails, it returns \nil, |
@@ -2174,7 +2180,7 @@ The file must be explicitly removed when no longer needed. | |||
2174 | 2180 | ||
2175 | \subsubsection*{\ff {\tt read ([readpattern])}}\Deffunc{read} | 2181 | \subsubsection*{\ff {\tt read ([readpattern])}}\Deffunc{read} |
2176 | 2182 | ||
2177 | This function reads the current input | 2183 | This function reads the file \verb|_INPUT| |
2178 | according to a read pattern, that specifies how much to read; | 2184 | according to a read pattern, that specifies how much to read; |
2179 | characters are read from the current input file until | 2185 | characters are read from the current input file until |
2180 | the read pattern fails or ends. | 2186 | the read pattern fails or ends. |
@@ -2196,7 +2202,7 @@ from the input if it belongs to the class; | |||
2196 | it never fails. | 2202 | it never fails. |
2197 | A character class followed by \verb|*| reads until a character that | 2203 | A character class followed by \verb|*| reads until a character that |
2198 | does not belong to the class, or end of file; | 2204 | does not belong to the class, or end of file; |
2199 | since it can match a sequence of zero characteres, it never fails.% | 2205 | since it can match a sequence of zero characters, it never fails.% |
2200 | \footnote{ | 2206 | \footnote{ |
2201 | Notice that the behavior of read patterns is different from | 2207 | Notice that the behavior of read patterns is different from |
2202 | the regular pattern matching behavior, | 2208 | the regular pattern matching behavior, |
@@ -2220,6 +2226,7 @@ Following are some examples of read patterns and their meanings: | |||
2220 | This is the default pattern. | 2226 | This is the default pattern. |
2221 | \item \verb|"{%s*}%S%S*"| returns the next word | 2227 | \item \verb|"{%s*}%S%S*"| returns the next word |
2222 | (maximal sequence of non white-space characters), | 2228 | (maximal sequence of non white-space characters), |
2229 | skipping spaces if necessary, | ||
2223 | or \nil\ on end of file. | 2230 | or \nil\ on end of file. |
2224 | \item \verb|"{%s*}[+-]?%d%d*"| returns the next integer | 2231 | \item \verb|"{%s*}[+-]?%d%d*"| returns the next integer |
2225 | or \nil\ if the next characters do not conform to an integer format. | 2232 | or \nil\ if the next characters do not conform to an integer format. |
@@ -2228,10 +2235,10 @@ or \nil\ if the next characters do not conform to an integer format. | |||
2228 | \subsubsection*{\ff {\tt write (value1, ...)}}\Deffunc{write} | 2235 | \subsubsection*{\ff {\tt write (value1, ...)}}\Deffunc{write} |
2229 | 2236 | ||
2230 | This function writes the value of each of its arguments to the | 2237 | This function writes the value of each of its arguments to the |
2231 | current output file. | 2238 | file \verb|_OUTPUT|. |
2232 | The arguments must be strings or numbers. | 2239 | The arguments must be strings or numbers. |
2233 | To write other values, | 2240 | To write other values, |
2234 | use \verb|tostring| before \verb|write|. | 2241 | use \verb|tostring| or \verb|format| before \verb|write|. |
2235 | If this function fails, it returns \nil, | 2242 | If this function fails, it returns \nil, |
2236 | plus a string describing the error. | 2243 | plus a string describing the error. |
2237 | 2244 | ||