summaryrefslogtreecommitdiff
path: root/doc/Lua-API
blob: b15e911065b99ec064d60e5e9ccd3001e8723bab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
== Global ideas about the Lua API ==

- Object model -

When the C++ host pushes an object on the Lua stack, it has two choices:

1. It can push it statically, meaning the object is still owned by the C++ host,
and its presence in the Lua VM is only a borrowing from the host. It's usually
done when the host wants to push a static object that would stay forever, and
can still be used internally by the host.

2. Or it can push it dynamically, loosing the object to the Lua VM. The later
case will introduce garbage collector hooks, as well as a "destroy" method.
The object shouldn't be referenced anymore by the C++ host, and it's up to the
Lua VM to destroy it, either explicitely by calling the "destroy" method, or
implicitely, by letting the Lua garbage collector the duty to collect the
object when its table isn't referenced anymore.


In all cases, an object being pushed is a table. It's up to the host to decide
what method to put in it, but the Lua VM can pretty much mess up with the
object as it wants. Most of the time, the tables will hold metatables though,
either for the garbage collect hook, or for the index / newindex metamethods.

For the sake of object identification and reference, there will always be a
field called __obj, containing some userdata. Identification of a table as an
object is as easy as checking the presence of this field. Additionnally, the
object may most likely contain another field called __objname, which is a
string describing the object's type. Checking if the object is owned by Lua or
the C++ host is as easy as checking the presence of the "destroy" function.


- Thread model -

The system is able to handle multiple Lua VMs bound to the same environment.
Concurrent access to the variables will be properly handled via the host
provided locking mechanism. Each thread can be safely be spawned within Lua,
and will be properly be threaded using the host's provided threading mechanism.
Garbage collection on a thread is fine if it has been spanwed by Lua itself.
If the thread has been spawned by the host, it has a reference in the registry
in order to avoid collection.


== Generic API ==

- Basic VM set up -

The Lua VM contains a few binary functions by default. These are andB, orB,
xorB, notB, shl, and shr. They all take 32-bits integer numbers. Number's sex
is always considered unsigned, which is important for the shr function.

The function "hex" is exported, but is considered dangerous. It takes one
mandatory numeric argument, and one optionnal string argument, which equals
"%02x". Basically, this is the hex formatting of a single 8-bits number,
which is done using sprintf; thus the reason this function isn't safe.

The function "getglobal" is exported. It takes a single string argument, and
runs basically the following Lua code: "return <argument>".

The function "dumpvars" is exported. It takes a minimum of two arguments, and
a maximum of three. The first argument is always a Handle (see below). The
second argument is always the variable to output, which has to be a table. If
the second argument is a string, then the variable is considered global, and
its name will be used as the main table assignment in the output. If it's a
table instead, it'll be accessed directly, and its assignment name for the
output has to be the third string argument.

The function "print" is exported, and is overriding the base print function.
Its purpose is to provide an abstract printer mechanism, in order to redirect
the output based on the Lua thread.


- Modifications of the built-in Lua API -

The "base" library, if opened by the host, will contain two additional
functions: mkdir and time.

The "dir" library has been added to the system, and is openable by the host.
As a result, you'll have a "dir" function which works as an iterator usable
by for loops. You can then write code such as:

    for entry in dir "*.txt" do ... end
    
The "entry" variable will be a table containing the following fields:
    . name, as a string, containing the filename of the current entry
    . type, as a string, equals to either FLAG_DIR or FLAG_FILE.

The "string" library, if opened by the host, will contain an additional
function: iconv. It'll take 3 string arguments. The first one is the string
to convert, the second one is the input encoding, and the last one is the
output encoding.

Note that lua-interface only opens the following libraries: base, math, string,
table, dir, and debug. The io library is considered dangerous, thus the
addition of the mkdir and time functions within the base library.


- XML parser -

If opened by the C++ host, the Lua VM may have the xml table, containing two
functions, called LoadString and LoadHandle. They'll both try to parse an XML
document, and return its result. Here's a full example:

Input XML file:

<?xml version="1.0" encoding="UTF-8"?>
<html>
    <head>
        <title>Test</title>
    </head>

    <body bgcolor="#ffeedd">Normal test
        <br />

        <b>Bold test.</b>

        <!-- Hi there... -->

    </body>
</html>

Output Lua table:

{
  [1] = {
    [1] = {
      [1] = {
        [1] = "Test",
        ["name"] = "title",
        ["n"] = 1,
      },
      ["name"] = "head",
      ["n"] = 1,
    },
    [2] = {
      [1] = "Normal test",
      [2] = {
        ["name"] = "br",
      },
      [3] = {
        [1] = "Bold test.",
        ["name"] = "b",
        ["n"] = 1,
      },
      ["attr"] = {
        ["bgcolor"] = "#ffeedd",
      },
      ["name"] = "body",
      ["n"] = 3,
    },
    ["name"] = "html",
    ["n"] = 2,
  },
  ["n"] = 1,
}


== Objects exported to the Lua VM ==

The C++ host may or may not export the classes to the Lua VM. The list here is
the list of the objects present in the library, but their availability isn't
guaranteed.

- Handle -

The Handle object is probably the most versatile and useful object into the
system. It's a channel where you can write and/or read data. It can virtually
represent anything. In the C++ host, this object is a pure virtual one, which
means it has to be derived in order to be used. The C++ host provides internal
mechanisms in order to export easily new handles sub-types over the Lua VM,
which means there's basically no way to know exactly what the data is, nor
where it goes and/or comes from.

In all cases, any Handle subtype will have the following base property:
  . The string "__handletype" will explicitely tell the handle's subtype. See
    below for a list of the base subtypes. Again, the C++ host may have loaded
    code in order to introduce more subtypes.

All Handle subtypes will share the following set of methods:
  . read(size)
      Without arguments, works the same as readstring. Otherwise, it'll take
      one numerical argument, the number of bytes to read, and will return two
      results: a table containing the bytes, and the amount of bytes read. The
      table starts with a zero index.

  . write(size, table)
      With only one string argument, works the same as writestring. Otherwise,
      it'll take one numerical argument, indicating the number of bytes to
      write, and a table which starts with a zero index.

  . readstring()
      Reads a string from the file, up to the end of the line (or the file) and
      will eventually remove the end of line marker (LF or CRLF, autodetected).
      
  . writestring(string)
      Writes the string, and returns nothing.
      
  . readU8() / readU16() / readU32() / readFloat() / readDouble()
      Reads a binary number in Little Endian, and returns it.
 
  . writeU8(v) / writeU16(v) / writeU32(v) / writeFloat(v) / writeDouble(v)
      Writes a binary number in Little Endian.
      
  . copyfrom(source[, size])
      Reads up to 'size' bytes from the given source, and put them inside of
      the calling handle. If not present, size will be "-1", which means "up
      to the end". The 'source' handle will then be closed (since it hits the
      end of file)

  . copyto(dest[, size])
      Does the same thing as copyfrom, just the other way around.
      
  . isclosed() / isnonblock() / canread() / canwrite() / canseek() / canwatch()
      Returns booleans in order to describe the status of the calling handle.

  . setnonblock()
      Sets the handle as non blocking.
      
  . tell()
      Returns the actual file position pointer, or if the handle is non
      seekable, will just return a counter of the number of bytes read so far.
      
  . getname()
      Returns a string containing the name of the handle. The filename, if
      possible, or a generic text, depending on the capabilities of the input
      Handle, and its virtuality.
  
  . getsize()
      Returns the handle size in bytes. If it is a Fifo, it will return the
      number of remaining bytes. (see below)
      
  . getmodif()
      Returns ... ?

  . close()
      Closes the file, and flushes the remaining data in caches.
      
  . flush()
      Flushes the remaining data in caches.
 
  . seek(pos[, wheel])
      Seeks the file pointer at position "pos". The "wheel" argument can be of
      SEEK_SET, SEEK_CUR or SEEK_END, to specify the pointer movement.

  . setz([level])
      Enables the zlib against the handle, at the specified level, from 0 (no
      compression) to 9 (max compression). The argument 'level' is 9 by
      default. This is basically meant to produce .gz files.

The last but not the least, the Handle base object will provide the following
global functions:

  . handlecopy(from, to[, size])
      Basically the same as the method 'copyfrom'.

  . exists(fname)
      Returns a boolean specifying the existence of the filename in the
      filesystem (virtual or not).

  . zlib_inflate(from, to)
      Calls the zlib's inflate fonction onto the data in handle 'from', and
      puts the result in the handle 'to'.
      
  . zlib_deflate(from, to)
      Calls the zlib's deflate fonction onto the data in handle 'from', and
      puts the result in the handle 'to'.


- Input -

This object is a derivation of the Handle class, and doesn't contain any extra
method. The constructor takes one string argument, which is the filename that
gets opened. Note the actual file being opened may come from one of the opened
archives. See below for details. The Handle is read-only.


- Output -

This object is a derivation of the Handle class, and doesn't contain any extra
method. The constructor takes one string argument, which is the filename that
gets opened. The Handle is write-only.


- Buffer -

This object creates a buffer in memory, and is a derivation of the Handle
class. Its constructor takes one optionnal boolean argument, to set the
seekability of the created buffer. A non-seekable buffer is a fifo, and will
free memory as data is being read out of it. A seekable buffer will never free
its memory.

Seekable buffers will get these additional methods: wtell, wseek and reset.
The normal tell and seek methods will work on the read pointer, whereas the
newly introduced methods wseek and wtell methods will work on the write
pointer. The reset method will restore the Buffer into an initial, empty state.


- Regex -

You can create regular expressions objects using the following constructor:

    Regex(regexp[, cflags[, eflags]])

The regexp is a normal string describing the regular expression you want to
match. The cflags and eflags fields are the compilation and execution flags.
Look at regex(3) for more details about them. The constants are exported so
that you can use them straight in Lua. The defaults are REG_EXTENDED for
cflags, and no flags set for eflags.

The resulting object will have the method Match, which takes one string as
argument, and returns a boolean telling if the string has matched, as well as
a table with the list of the submatches.


- ConfigFile -

This object will read a Handle and transform it into a read-only associative
array. So its constructor only takes one handle. The structure of the ini files
it'll read is the standard windows-like files, such as:

[section1]
name1=value1
name2=value2

[section2]
name1=value1

And any ConfigFile object will have two tables named section1 and section2
containing the indexes mentionned in the exemple.