Commit ab5c746882370c93874c8d827d4f46296c62d515

Authored by Cédric RICARD
1 parent 4d407e6b

Back port of recent library changes to version 1.9

anubis_dev/library/data_base/alter_table.anubis
... ... @@ -16,6 +16,7 @@
16 16 read tools/basis.anubis
17 17 read data_base/sqlite.anubis
18 18 read system/logger.anubis
  19 +read system/string.anubis
19 20  
20 21  
21 22  
... ... @@ -66,10 +67,11 @@ define Maybe(String)
66 67 get_original_query
67 68 (
68 69 SQLite3DataBase db,
  70 + String dbName, // alias for attached database, 'main' for main database.
69 71 String tableName,
70 72 Logger log
71 73 ) =
72   - if sql_query(db, "SELECT sql FROM sqlite_master where (type='table') and tbl_name='" + tableName + "'") is
  74 + if sql_query(db, "SELECT sql FROM " + dbName + ".sqlite_master where (type='table') and tbl_name='" + tableName + "'") is
73 75 {
74 76 error(sql_error) then logError(log, "alter_table/get_original_query ERROR '" + sql_error.text + "'"); failure,
75 77 ok(table_cursor) then
... ... @@ -88,7 +90,7 @@ define Bool
88 90 String tableName,
89 91 Logger log
90 92 ) =
91   - if sql_query(db, "SELECT count(*) FROM '" + tableName + "'") is
  93 + if sql_query(db, "SELECT count(*) FROM " + tableName) is
92 94 {
93 95 error(sql_error) then logError(log, "has_rows query ERROR '" + sql_error.text + "'"); false,
94 96 ok(table_cursor) then
... ... @@ -165,28 +167,61 @@ define String
165 167 else ""
166 168 }.
167 169  
  170 +// false = different, true = same
  171 +define Bool
  172 + compare_creation_queries
  173 + (
  174 + String tableName,
  175 + String query1,
  176 + String query2,
  177 + ) =
  178 + if find(tableName, query1, 0) is
  179 + {
  180 + failure then false,
  181 + success(p1) then
  182 + if find(tableName, query2, 0) is
  183 + {
  184 + failure then false,
  185 + success(p2) then
  186 + if sub_string(query1, p1, length(query1) - p1) is
  187 + {
  188 + failure then false,
  189 + success(s1) then
  190 + if sub_string(query2, p2, length(query2) - p2) is
  191 + {
  192 + failure then false,
  193 + success(s2) then s1 = s2
  194 + }
  195 + }
  196 + }
  197 + }.
  198 +
168 199 public define Maybe(One)
169 200 alter_table
170 201 (
171 202 SQLite3DataBase db,
  203 + String dbName, // alias for attached database, 'main' for main database.
172 204 String tableName,
173 205 String newTableQuery,
174 206 Logger log
175 207 ) =
176   - if get_original_query(db, tableName, log) is
  208 + with fullTableName = dbName + "." + tableName,
  209 + if get_original_query(db, dbName, tableName, log) is
177 210 {
178 211 failure then
179   - logInfo(log, "Creating table '" + tableName + "'... ");
  212 + logInfo(log, "Creating table '" + fullTableName + "'... ");
180 213 if sql_query(db, newTableQuery) is error(sql_error)
181 214 then logError(log, "ERROR : " + sql_error.text); failure
182 215 else logInfo(log, " --> ok."); success(unique),
183 216 success(originalTableQuery) then
184   - if originalTableQuery /= newTableQuery then
185   - logInfo(log, "Updating table '" + tableName + "' on database... ");
186   - if has_rows(db, tableName, log) is
  217 + if compare_creation_queries(tableName, originalTableQuery, newTableQuery) = false then
  218 + logInfo(log, "Updating table '" + fullTableName + "' on database... ");
  219 + println(originalTableQuery);
  220 + println(newTableQuery);
  221 + if has_rows(db, fullTableName, log) is
187 222 {
188 223 false then
189   - if my_sql_query(db, "DROP TABLE '" + tableName + "'", log) is failure
  224 + if my_sql_query(db, "DROP TABLE " + fullTableName, log) is failure
190 225 then failure
191 226 else if my_sql_query(db, newTableQuery, log ) is
192 227 {
... ... @@ -195,22 +230,22 @@ public define Maybe(One)
195 230 },
196 231 true then
197 232 with tempNameTable = tableName + "_temp",
198   - forget(sql_query(db, "DROP TABLE '" + tempNameTable + "'"));
199   - if my_sql_query(db, "CREATE TEMP TABLE '" + tempNameTable + "' AS SELECT * from '" + tableName + "'", log) is failure then failure else
200   - if my_sql_query(db, "DROP TABLE '" + tableName + "'", log) is failure then failure else
  233 + forget(sql_query(db, "DROP TABLE " + tempNameTable));
  234 + if my_sql_query(db, "CREATE TEMP TABLE " + tempNameTable + " AS SELECT * from " + fullTableName, log) is failure then failure else
  235 + if my_sql_query(db, "DROP TABLE " + fullTableName, log) is failure then failure else
201 236 if my_sql_query(db, newTableQuery , log) is failure then failure else
202   - if sql_query(db, "SELECT * FROM '" + tempNameTable + "'") is
  237 + if sql_query(db, "SELECT * FROM " + tempNameTable) is
203 238 {
204 239 error(sql_error) then logError(log, "alter_table: select * tempTable ERROR '" + sql_error.text + "'"); failure,
205 240 ok(table_cursor2) then
206 241 with oldColumns = alter_table_extract_columns_list(table_cursor2, log),
207   - print_list(oldColumns);
208   - if sql_query(db, "PRAGMA table_info('" + tableName + "')") is
  242 + //print_list(oldColumns);
  243 + if sql_query(db, "PRAGMA " + dbName + ".table_info(" + tableName + ")") is
209 244 {
210 245 error(sql_error) then logError(log, "alter_table: pragma table_info() ERROR '" + sql_error.text + "'"); failure,
211 246 ok(table_cursor3) then
212 247 with newColumnsStr = alter_table_extract_column_string(table_cursor3, oldColumns, log),
213   - sql = "INSERT INTO '" + tableName + "' (" + newColumnsStr + ") SELECT " + newColumnsStr + " FROM '" + tempNameTable + "'",
  248 + sql = "INSERT INTO " + fullTableName + " (" + newColumnsStr + ") SELECT " + newColumnsStr + " FROM " + tempNameTable,
214 249 if sql_query(db, sql) is
215 250 {
216 251 error(sql_error) then logError(log, "alter_table ERROR '" + sql_error.text + "'\n\tquery = [" + sql + "]"); failure,
... ... @@ -223,3 +258,13 @@ public define Maybe(One)
223 258 success(unique)
224 259 }.
225 260  
  261 +public define Maybe(One)
  262 + alter_table
  263 + (
  264 + SQLite3DataBase db,
  265 + String tableName,
  266 + String newTableQuery,
  267 + Logger log
  268 + ) =
  269 + alter_table(db, "main", tableName, newTableQuery, log).
  270 +
... ...
anubis_dev/library/data_base/sqlite.anubis
... ... @@ -313,7 +313,7 @@ public define SQLite3QueryResult
313 313 if sql_error.code = 5 then
314 314 unique
315 315 else
316   - print_db_error(sql_error)
  316 + println(db_error(sql_error) + "executing [" + sql_command + "]")
317 317 );
318 318 sleep(ms_retry_delay);
319 319 do_query(unique),
... ...
anubis_dev/library/lexical_analysis/fast_lexer.anubis
... ... @@ -451,7 +451,7 @@ public define Maybe(LexingStream) make_lexing_stream(SSL_Connection stream,
451 451  
452 452 To each lexing stream is attached a function for counting of type 'One -> Int'. When
453 453 applied to 'unique', this function returns the number of bytes already read from the
454   - lexing stream, i.e. the position from which the reading of te next token will
  454 + lexing stream, i.e. the position from which the reading of the next token will
455 455 occur. This function is obtained as follows:
456 456  
457 457 public define One -> Int
... ... @@ -460,7 +460,7 @@ public define One -> Int
460 460 LexingStream ls
461 461 ).
462 462  
463   - If youn need this function, it is recommended to call 'offset_counter' only once just
  463 + If you need this function, it is recommended to call 'offset_counter' only once just
464 464 after the lexing stream is created.
465 465  
466 466  
... ...
anubis_dev/library/network/dns.anubis
... ... @@ -132,6 +132,7 @@ public type DNS_RecordType:
132 132 _HINFO, // host information
133 133 _MX, // mail exchange
134 134 _TXT, // text information
  135 + _SPF, // psf information
135 136 unknown(Word32 type_code).
136 137  
137 138  
... ... @@ -218,6 +219,7 @@ public type DNS_RecordData:
218 219 _HINFO (String cpu, String os),
219 220 _MX (Word32 preference, String name),
220 221 _TXT (String info),
  222 + _SPF (String info),
221 223 unknown (Word32 type_code).
222 224  
223 225  
... ... @@ -458,6 +460,7 @@ define One debogge(String s) = unique.
458 460 HINFO 13 host information
459 461 MX 15 mail exchange
460 462 TXT 16 text
  463 + SPF 99 spf
461 464 AXFR 252 request for the transfert of an entire zone
462 465 * 255 all records
463 466  
... ... @@ -923,6 +926,7 @@ define Word32
923 926 _HINFO then (Word32)13,
924 927 _MX then (Word32)15,
925 928 _TXT then (Word32)16,
  929 + _SPF then (Word32)99,
926 930 unknown(n) then (Word32)n
927 931 }.
928 932  
... ... @@ -1361,6 +1365,7 @@ define Result(DNS_DecodeError,DNS_RecordType)
1361 1365 if n = 13 then ok(_HINFO) else
1362 1366 if n = 15 then ok(_MX) else
1363 1367 if n = 16 then ok(_TXT) else
  1368 + if n = 99 then ok(_SPF) else
1364 1369 ok(unknown(n))
1365 1370 }.
1366 1371  
... ... @@ -1639,12 +1644,14 @@ define Result(DNS_DecodeError,(Int,DNS_RecordData))
1639 1644 ByteArray s,
1640 1645 Int start,
1641 1646 String so_far,
1642   - Int size_so_far
  1647 + Int size_so_far,
  1648 + Bool is_spf
1643 1649 ) =
1644 1650 if decode_character_string(s,start) is
1645 1651 {
1646   - error(msg) then ok((size_so_far,_TXT(so_far))),
1647   - ok(s1) then decode_TXT_record_data(s,start+1+length(s1),s1,1+length(s1))
  1652 + error(msg) then ok((size_so_far, if is_spf then _SPF(so_far) else _TXT(so_far))),
  1653 +// ok(s1) then decode_TXT_record_data(s, start+1+length(s1), if length(so_far) > 0 then so_far + " " + s1 else s1, 1+length(s1), is_spf)
  1654 + ok(s1) then decode_TXT_record_data(s, start+1+length(s1), so_far + s1, 1+length(s1), is_spf)
1648 1655 }.
1649 1656  
1650 1657  
... ... @@ -1666,7 +1673,7 @@ define Result(DNS_DecodeError,(Int,DNS_RecordData))
1666 1673 if decode_character_string(s,start) is
1667 1674 {
1668 1675 error(msg) then ok((size_so_far,_TXT(so_far))),
1669   - ok(s1) then decode_TXT_record_data(s,start+1+length(s1),s1,1+length(s1))
  1676 + ok(s1) then decode_TXT_record_data(s,start+1+length(s1),s1,1+length(s1), false)
1670 1677 }.
1671 1678  
1672 1679  
... ... @@ -1693,7 +1700,8 @@ define Result(DNS_DecodeError,(Int,DNS_RecordData))
1693 1700 _PTR then decode_PTR_record_data(s,start),
1694 1701 _HINFO then decode_HINFO_record_data(s,start),
1695 1702 _MX then decode_MX_record_data(s,start),
1696   - _TXT then decode_TXT_record_data(s,start,"",0),
  1703 + _TXT then decode_TXT_record_data(s,start,"",0, false),
  1704 + _SPF then decode_TXT_record_data(s,start,"",0, true),
1697 1705 unknown(n) then decode_unknown_record_data(s,start,n,rdlength)
1698 1706 }.
1699 1707  
... ... @@ -1850,10 +1858,15 @@ define One
1850 1858 ) =
1851 1859 if (Maybe(RWStream))file("toto",new) is
1852 1860 {
1853   - failure then unique,
  1861 + failure then println("Can't create dump file."); unique,
1854 1862 success(file) then dump(weaken(file),s,0,0)
  1863 + };
  1864 + if (Maybe(RWStream))file("toto.bin",new) is
  1865 + {
  1866 + failure then println("Can't create binary dump file."); unique,
  1867 + success(file) then forget(write(weaken(file),s))
1855 1868 }.
1856   -
  1869 +
1857 1870  
1858 1871  
1859 1872  
... ... @@ -1946,6 +1959,7 @@ public define Result(DNS_Error,DNS_Answer)
1946 1959 // that packet is not truncated
1947 1960 //
1948 1961 ok(response, trunc, addr_ok ,port) then
  1962 + //dump(response);
1949 1963 if trunc is
1950 1964 {
1951 1965 truncated then error(reponse_truncated),
... ... @@ -2206,6 +2220,7 @@ define Maybe(Word32)
2206 2220 _HINFO(_,_) then resolve_address(name,t,auth,addi),
2207 2221 _MX(_,_) then resolve_address(name,t,auth,addi),
2208 2222 _TXT(_) then resolve_address(name,t,auth,addi),
  2223 + _SPF(_) then resolve_address(name,t,auth,addi),
2209 2224 unknown(type_code) then resolve_address(name,t,auth,addi)
2210 2225 }
2211 2226 }.
... ...
anubis_dev/library/network/dns_tools.anubis
... ... @@ -157,6 +157,7 @@ define String
157 157 _HINFO then "HINFO",
158 158 _MX then "MX",
159 159 _TXT then "TXT",
  160 + _SPF then "SPF"
160 161 unknown(n) then "unknown["+n+"]"
161 162 }.
162 163  
... ... @@ -226,6 +227,7 @@ define String
226 227 _HINFO(cpu,os) then " HINFO "+cpu+" "+os,
227 228 _MX(pref,name) then " MX "+pref+" "+name,
228 229 _TXT(info) then " TXT "+info,
  230 + _SPF(info) then " SPF "+info,
229 231 unknown(type_code) then " unknow record type: "+type_code
230 232 }.
231 233  
... ... @@ -368,6 +370,7 @@ define Maybe(DNS_RecordType)
368 370 if s = "HINFO" then success(_HINFO) else
369 371 if s = "MX" then success(_MX) else
370 372 if s = "TXT" then success(_TXT) else
  373 + if s = "SPF" then success(_SPF) else
371 374 failure.
372 375  
373 376  
... ...
anubis_dev/library/network/sntp.anubis
... ... @@ -26,6 +26,7 @@
26 26 read tools/basis.anubis //contain the definition of .
27 27 read locale/L3LanguageInfo.anubis //date and time formating
28 28 read system/string.anubis
  29 +read network/dns.anubis
29 30 read network/tools.anubis
30 31  
31 32 public define Int ntp_epoch = 86400 * ((365 * 70) + 17).
... ... @@ -331,39 +332,56 @@ public define NTP_Record
331 332 public define Maybe(NTP_Record)
332 333 get_sntp_record
333 334 (
334   - String server_address
  335 + Word32 address
335 336 )=
336   - if dns(server_address) is ok(address) then
337   - //we retreive the IP address of the server
338   - if create_udp_client_socket is
339   - {
340   - cannot_create_the_socket then failure,
341   - ok(socket) then
342   - //the necessary UDP socket was created, hence we send the SNTP query packet
343   - if udp_send(socket, address, 123 , encode(make_default_query_record(unique))) is
  337 + if create_udp_client_socket is
  338 + {
  339 + cannot_create_the_socket then failure,
  340 + ok(socket) then
  341 + //the necessary UDP socket was created, hence we send the SNTP query packet
  342 + if udp_send(socket, address, 123 , encode(make_default_query_record(unique))) is
  343 + {
  344 + network_unreachable then failure,
  345 + packet_sent then
  346 + if udp_receive(socket, 48, 5) is
344 347 {
345   - network_unreachable then failure,
346   - packet_sent then
347   - if udp_receive(socket, 48, 5) is
  348 + out_of_time then print("SNTP reponse TimeOut\n");failure,
  349 + network_unreachable then print("SNTP server unreachable \n");failure,
  350 + //we received the SNTP Packet in reponse of our query, now we must check if
  351 + //that packet is not truncated
  352 + ok(ntp_packet, trunc, addr ,port) then
  353 + if trunc is
348 354 {
349   - out_of_time then print("SNTP reponse TimeOut\n");failure,
350   - network_unreachable then print("SNTP server unreachable \n");failure,
351   - //we received the SNTP Packet in reponse of our query, now we must check if
352   - //that packet is not truncated
353   - ok(ntp_packet, trunc, addr ,port) then
354   - if trunc is
355   - {
356   - truncated then failure,
357   - //All is ok, now we decode that packet and return it to caller
358   - not_truncated then success(decode(ntp_packet))
359   - }
  355 + truncated then failure,
  356 + //All is ok, now we decode that packet and return it to caller
  357 + not_truncated then success(decode(ntp_packet))
360 358 }
361 359 }
362   - }
363   - else
364   - failure. //we can't resolve the IP address of the server
  360 + }
  361 + }.
  362 +
365 363  
366   -
  364 +public define Maybe(NTP_Record)
  365 + get_sntp_record
  366 + (
  367 + String server_address
  368 + ) =
  369 + if resolve_address(server_address) is success(address) then
  370 + get_sntp_record(address)
  371 + else
  372 + failure. //we can't resolve the IP address of the server
  373 +
  374 +public define Maybe(NTP_Record)
  375 + get_sntp_record
  376 + (
  377 + List(IpAddress) dns_list,
  378 + String server_address
  379 + ) =
  380 + if resolve_address(dns_list, server_address) is success(address) then
  381 + get_sntp_record(address)
  382 + else
  383 + failure. //we can't resolve the IP address of the server
  384 +
367 385  
368 386 public define Maybe(UTime)
369 387 get_sntp_time
... ... @@ -378,3 +396,15 @@ public define Maybe(UTime)
378 396 }.
379 397  
380 398  
  399 +public define Maybe(UTime)
  400 + get_sntp_time
  401 + (
  402 + List(IpAddress) dns_list,
  403 + String server_address
  404 + ) =
  405 + if get_sntp_record(dns_list, server_address) is
  406 + {
  407 + failure then failure,
  408 + //here we only extract the time we want
  409 + success(ntp_record) then success(ntp_record.transmit_timestamp)
  410 + }.
... ...
anubis_dev/library/predefined.anubis
... ... @@ -2384,9 +2384,8 @@ public define MVar($T)
2384 2384  
2385 2385 mv(i)
2386 2386  
2387   - (where 'i' is an integer such that 0 =< i < n) represents the i-th slot of the
2388   - variable. However, 'mv(i)' is not a term of the language, it is only used in the
2389   - following terms:
  2387 + (where 'i' is a Word32 such that 0 =< i < n) represents the i-th slot of the variable.
  2388 + However, 'mv(i)' is not a term of the language, it is only used in the following terms:
2390 2389  
2391 2390 *mv(i) which allows to read the value of the i-th slot of mv,
2392 2391 mv(i) <- a which puts 'a' in the i-th slot of mv,
... ... @@ -2403,12 +2402,6 @@ public define MVar($T)
2403 2402 to do: length(MVar($T)) should return an Int.
2404 2403 public define Word32 length(MVar($T) mv).
2405 2404  
2406   -
2407   - Multiple variables (of the same type) may be concatenated. The result of concatenating
2408   - mv1 and mv2 is a new multiple variable whose slots contain the values taken from the
2409   - slots of mv1 and mv2. The operation for concatenating multiple variables is '+':
2410   -
2411   -public define MVar($T) MVar($T) mv1 + MVar($T) mv2.
2412 2405  
2413 2406 Multiple variables also have an identification number, given by:
2414 2407  
... ... @@ -4523,7 +4516,9 @@ public define MakeFastLexerResult
4523 4516 The external library (actually the wrapper library) must be loaded before you can use
4524 4517 it. This is acheived by:
4525 4518  
4526   - public define Maybe(WrapperLibrary)
  4519 +public type WrapperLibrary:... an opaque type
  4520 +
  4521 +public define Maybe(WrapperLibrary)
4527 4522 load_wrapper_library
4528 4523 (
4529 4524 String wrapper_library_name
... ... @@ -4540,11 +4535,11 @@ public define MakeFastLexerResult
4540 4535  
4541 4536 In order to call an external library function, use the following:
4542 4537  
4543   - public define Maybe($U)
  4538 +public define Maybe($U)
4544 4539 wrapper_library_call
4545 4540 (
4546 4541 WrapperLibrary library,
4547   - String name_of_wrapper_function
  4542 + String name_of_wrapper_function,
4548 4543 $T arguments
4549 4544 ).
4550 4545  
... ... @@ -4630,8 +4625,7 @@ public define MakeFastLexerResult
4630 4625  
4631 4626 So, we only need to explain how data of this type are handled in a wrapper function.
4632 4627  
4633   - The serialization of a datum of type 'PtrKeeper' occupies 8 bytes, more precisely two
4634   - 32 bits words:
  4628 + The serialization of a datum of type 'PtrKeeper' occupies two 32 bits words:
4635 4629  
4636 4630 +-----------------+-----------------+
4637 4631 | del | ptr |
... ... @@ -4642,9 +4636,14 @@ public define MakeFastLexerResult
4642 4636  
4643 4637 When the garbage-collector decides to delete the structure, it just applies 'del' to
4644 4638 'ptr' (only if 'del' is not 0 of course).
  4639 +
  4640 + Be careful: create such a pair only if the pointer is not yet shared, otherwise the
  4641 + counting by the garbage-collector would be wrong. In particular never construct two
  4642 + such pairs with the same pointer.
4645 4643  
4646   -
4647   -
  4644 + Be careful: The order of the bytes within 'del' and 'ptr' is not necessarily little
  4645 + endian. It must be the byte order of the underlying machine, since they are used by
  4646 + Anubis as pointers when 'del' is applied to 'ptr'.
4648 4647  
4649 4648  
4650 4649  
... ...
anubis_dev/library/system/data_io.anubis
... ... @@ -19,16 +19,18 @@ public type Data_IO_Result:
19 19 success(ByteArray),
20 20 truncated(ByteArray).
21 21  
22   -public define Data_IO_Result read_bytes (Data_IO data, Int how_many).
  22 +public define Data_IO_Result read_bytes (Data_IO data, Int how_many).
23 23  
24 24 public define Data_IO make_data_io(RStream file).
25 25 public define Data_IO make_data_io(ByteArray byte_array).
26 26  
27 27  
28 28 public type Data_IO:
29   - data_io(Int -> Data_IO_Result read_bytes,// read a bytes
  29 + data_io(Int -> Data_IO_Result read_bytes,// read a bytes function
30 30 One -> Int offset, // offset
31   - One -> Bool rewind).
  31 + One -> Bool rewind, // rewind the reader head to begining of the Data_IO
  32 + One -> Int size // total size of the Data_IO
  33 + ).
32 34  
33 35 /* File interface */
34 36  
... ... @@ -36,7 +38,7 @@ define Int -&gt; Data_IO_Result
36 38 make_read_bytes // making the 'rb' function
37 39 (
38 40 RStream file,
39   - Var(Int) offset,
  41 + Var(Int) offset,
40 42 ) =
41 43 (Int how_many) |->
42 44 if read(file, how_many, 10) is //by default the time_out is 10 seconds
... ... @@ -61,7 +63,9 @@ public define Data_IO
61 63 data_io(
62 64 make_read_bytes(file, o),
63 65 (One u) |-> *o,
64   - (One u) |-> seek(file, 0)).
  66 + (One u) |-> seek(file, 0),
  67 + (One u) |-> file_size(file)
  68 + ).
65 69  
66 70 /* ByteArray interface */
67 71  
... ... @@ -90,15 +94,38 @@ public define Data_IO
90 94 ) =
91 95 with o = var((Int)0), // offset
92 96 data_io(
93   - make_read_bytes(byte_array, o),
94   - (One u) |-> *o,
95   - (One u) |-> o<-0;true).
96   -
97   -
  97 + make_read_bytes(byte_array, o), // reader function
  98 + (One u) |-> *o, // current position of the offset
  99 + (One u) |-> o<-0;true, // set the offset to 0 and return true
  100 + (One u) |-> length(byte_array) // total size of the ByteArray
  101 + ).
  102 +
98 103 public define Data_IO_Result
99   - read_bytes
100   - (
101   - Data_IO io,
102   - Int how_many
103   - ) =
104   - read_bytes(io)(how_many).
  104 + read_bytes
  105 + (
  106 + Data_IO io,
  107 + Int how_many
  108 + ) =
  109 + read_bytes(io)(how_many).
  110 +
  111 +
  112 +define Int
  113 + get_size
  114 + (
  115 + List(Data_IO) left,
  116 + Int current_size
  117 + )=
  118 + if left is
  119 + {
  120 + [] then current_size,
  121 + [h . t] then get_size(t, current_size + size(h)(unique))
  122 + }
  123 + .
  124 +
  125 +public define Int
  126 + get_size
  127 + (
  128 + List(Data_IO) list
  129 + )=
  130 + get_size(list, 0).
  131 +
... ...
anubis_dev/library/system/files.anubis
... ... @@ -429,18 +429,19 @@ public define Maybe(String)
429 429 define Int
430 430 last_char
431 431 (
432   - List(Word8) path,
433   - Int last_slash,
434   - Int current_pos
  432 + List(Word8) path,
  433 + Word8 token,
  434 + Int last_token,
  435 + Int current_pos
435 436 ) =
436 437 if path is
437 438 {
438   - [] then last_slash,
  439 + [] then last_token,
439 440 [h . t ] then
440   - if h = '/' then
441   - last_char(t, current_pos, current_pos + 1)
  441 + if h = token then
  442 + last_char(t, token, current_pos, current_pos + 1)
442 443 else
443   - last_char(t, last_slash, current_pos + 1)
  444 + last_char(t, token, last_token, current_pos + 1)
444 445 }.
445 446  
446 447 /** extract dir, extract the directory path from the given path. The given path
... ... @@ -455,7 +456,7 @@ public define String
455 456 String given_path
456 457 )=
457 458 with path = normalize_path(given_path),
458   - with pos = last_char(explode(path), 0, 0),
  459 + with pos = last_char(explode(path),'/', 0, 0),
459 460 if sub_string(path, 0, pos+1) is
460 461 {
461 462 failure then given_path,
... ... @@ -485,13 +486,31 @@ public define String
485 486 )=
486 487 with path = normalize_path(given_path),
487 488 len = length(path),
488   - pos = last_char(explode(path), -1, 0),
  489 + pos = last_char(explode(path), '/', -1, 0),
489 490 file_len = len - (pos+1),
490 491 if sub_string(path, pos + 1, file_len) is
491 492 {
492 493 failure then "",
493 494 success(file_name) then file_name
494   - } .
  495 + }.
  496 +
  497 +public define String
  498 + remove_extension
  499 + (
  500 + String given_path
  501 + )=
  502 + with path = normalize_path(given_path),
  503 + len = length(path),
  504 + pos = last_char(explode(path), '.', -1, 0),
  505 + //pos = -1 mean no dot found in the path, hence no extension need to remove
  506 + if pos = -1 then
  507 + given_path
  508 + else
  509 + if sub_string(path, 0, pos) is
  510 + {
  511 + failure then "",
  512 + success(file_name) then file_name
  513 + }.
495 514  
496 515 public define Bool
497 516 is_dir
... ... @@ -542,3 +561,85 @@ public define Bool
542 561 )=
543 562 with norm_path = normalize_path(path),
544 563 remove_files(norm_path +"/", directory_list(norm_path, mask)).
  564 +
  565 +
  566 +/**
  567 + * Check if the specified path is a relative or an absolute path
  568 + * Returns true if the path is relative.
  569 + */
  570 +public define Bool
  571 + is_relative
  572 + (
  573 + String path
  574 + ) =
  575 + if nth(0, path) is
  576 + {
  577 + failure then true, // empty path
  578 + success(c1) then
  579 + if c1 = '/' | c1 = '\\' then false
  580 + else if (c1 >=+ 'A' & c1 +=< 'Z') | (c1 >=+ 'a' & c1 +=< 'z') then
  581 + if nth(1, path) is
  582 + {
  583 + failure then true, // one letter path ('c')
  584 + success(c2) then
  585 + if c2 = ':' then
  586 + if nth(2, path) is
  587 + {
  588 + failure then true,
  589 + success(c3) then
  590 + if c3 = '/' | c3 = '\\' then false
  591 + else true // strange path 'C:xxxxx'
  592 + }
  593 + else true
  594 + }
  595 + else true
  596 + }.
  597 +
  598 +/**
  599 + * Check if the specified path is a relative or an absolute path
  600 + * Returns true if the path is relative.
  601 + */
  602 +public define inline Bool
  603 + is_absolute
  604 + (
  605 + String path
  606 + ) =
  607 + if is_relative(path) then false else true.
  608 +
  609 +
  610 +public define Maybe(String)
  611 + make_relative_path
  612 + (
  613 + String root,
  614 + String path,
  615 + ) =
  616 + if is_relative(path) & is_absolute(root) then failure
  617 + else
  618 + if normalize_path_ex(root) is
  619 + {
  620 + failure then failure,
  621 + success(root_norm) then
  622 + if normalize_path_ex(path) is
  623 + {
  624 + failure then failure,
  625 + success(path_norm) then
  626 + with root_folders = map_select((String s) |-> if s = "" then failure else success(s), split(root_norm, '/')),
  627 + path_folders = map_select((String s) |-> if s = "" then failure else success(s), split(path_norm, '/')),
  628 + compare = (List(String) fold1, List(String) fold2, List(String) so_far) |-compare->
  629 + if fold1 is
  630 + {
  631 + [] then success(join("/", reverse(so_far) + fold2)),
  632 + [h . t] then
  633 + if fold2 is
  634 + {
  635 + [] then compare(t, [], [".." . so_far]),
  636 + [h2 . t2] then
  637 + if h = h2 then
  638 + compare(t, t2, so_far)
  639 + else
  640 + failure
  641 + }
  642 + },
  643 + compare(root_folders, path_folders, [])
  644 + }
  645 + }.
... ...
anubis_dev/library/system/parameter/inifile.anubis
... ... @@ -15,6 +15,7 @@
15 15 read tools/streams.anubis
16 16 read tools/basis.anubis
17 17 read tools/base64.anubis
  18 +read system/string.anubis
18 19  
19 20  
20 21 type IniValType:
... ... @@ -190,7 +191,7 @@ define Maybe(IniVar) getVar(List(IniVar) varList, String varName) =
190 191 [] then failure,
191 192 [h . t] then
192 193 if h is iniVar(name, value, type) then
193   - if name = varName
  194 + if insensitive_equal(name, varName)
194 195 then success(h)
195 196 else getVar( t , varName)
196 197 }.
... ...
anubis_dev/library/system/string.anubis
... ... @@ -666,6 +666,49 @@ public define List(String)
666 666 )=
667 667 split_by_tokens(explode(line), [token], [], []).
668 668  
  669 +define List(String)
  670 + _split_lines
  671 + (
  672 + List(Word8) text,
  673 + List(Word8) current,
  674 + List(String) so_far
  675 + ) =
  676 + if text is
  677 + {
  678 + [] then
  679 + if length(current) > 0 then
  680 + reverse([ implode(reverse(current)) . so_far])
  681 + else
  682 + reverse(so_far),
  683 + [ char . t ] then
  684 + if char = 13 then // CR
  685 + if t is
  686 + {
  687 + [] then
  688 + if length(current) > 0 then
  689 + reverse([ implode(reverse(current)) . so_far])
  690 + else
  691 + reverse(so_far),
  692 + [ char2 . t2 ] then
  693 + if char2 = 10 then // LF
  694 + _split_lines( t2, [], [ implode(reverse(current)) . so_far])
  695 + else
  696 + _split_lines( t, [], [ implode(reverse(current)) . so_far])
  697 + }
  698 + else if char = 10 then // LF
  699 + _split_lines( t, [], [ implode(reverse(current)) . so_far])
  700 + else
  701 + _split_lines( t, [ char . current ], so_far)
  702 + }.
  703 +
  704 +/// Split a text into lines, whether the line ends are (CRLF / LF / CR)
  705 +public define List(String)
  706 + split_lines
  707 + (
  708 + String text,
  709 + )=
  710 + _split_lines(explode(text), [], []).
  711 +
669 712 define (Int, Int)
670 713 trim
671 714 (
... ...
anubis_dev/library/test/all_unit_test.anubis
... ... @@ -50,5 +50,6 @@ global define One
50 50 )=
51 51 execute_tests(make_all_tests_list(unique), args).
52 52  
  53 + execute anbexec all_unit_test &
53 54  
54 55  
... ...
anubis_dev/library/test/system/files.unit_test.anubis
1   -read tools/basis.anubis
  1 +
  2 +read tools/basis.anubis
2 3 read system/types.anubis
3 4 read system/files.anubis
4 5  
... ... @@ -31,10 +32,39 @@ define One
31 32 unique.
32 33  
33 34  
  35 +define One
  36 + is_relative_test
  37 + (
  38 + UnitTestContext ut
  39 + )=
  40 + assertIsTrue(ut, is_relative("a/simple/relative/path"), "Line " + to_decimal(__LINE__));
  41 + assertIsTrue(ut, is_relative("a/simple/relative/path/"), "Line " + to_decimal(__LINE__));
  42 + assertIsTrue(ut, is_relative("a"), "single letter");
  43 + assertIsTrue(ut, is_relative("../../a/relative/path"), "Line " + to_decimal(__LINE__));
  44 + assertIsTrue(ut, is_relative("./a/relative/path"), "Line " + to_decimal(__LINE__));
  45 + assertIsTrue(ut, is_relative("a\\not/normalized\\relative/path\\"), "Line " + to_decimal(__LINE__));
  46 + assertIsTrue(ut, is_relative("../../a/relative/path"), "Line " + to_decimal(__LINE__));
  47 + assertIsFalse(ut, is_relative("/an/absolute/path"), "Line " + to_decimal(__LINE__));
  48 + assertIsFalse(ut, is_relative("D:\\an\\absolute\\windows\\path"), "Line " + to_decimal(__LINE__));
  49 + assertIsFalse(ut, is_relative("D:/an/absolute/windows/path"), "Line " + to_decimal(__LINE__));
  50 + unique.
  51 +
  52 +
  53 +define One
  54 + make_relative_path_test
  55 + (
  56 + UnitTestContext ut
  57 + )=
  58 + assertIsSameString(ut, force_Type(make_relative_path("/root/path", "/root/path/to/the/object"), "failure"), "to/the/object", "Line " + to_decimal(__LINE__));
  59 + assertIsSameString(ut, force_Type(make_relative_path("/", "/to/the/object"), "failure"), "to/the/object", "Line " + to_decimal(__LINE__));
  60 + unique.
34 61  
  62 +
35 63 public define UnitTestSuite make_files_test_suite
36 64 =
37 65 ut_suite("system.files",
38 66 [
39 67 ut_fixture("Normalize path", normalize_path_test),
  68 + ut_fixture("is_relative", is_relative_test),
  69 + ut_fixture("make_relative_path", make_relative_path_test),
40 70 ]).
... ...
anubis_dev/library/tools/line_reader.anubis
... ... @@ -14,23 +14,27 @@ type Token:
14 14 line(String),
15 15 eol.
16 16  
  17 +public type LineReaderLexer:
  18 + line_reader_lexer(LexingStream -> One -> LexerOutput(Token) /*lexer_base*/).
  19 +
17 20 public type LineReader:
18 21 line_reader(One -> LexerOutput(Token) /*lexer*/,
19   - One -> Int /*offset*/).
  22 + One -> Int /*offset*/,
  23 + LineReaderLexer /*lexer_base*/).
20 24  
21 25 public define Int
22 26 current_offset
23 27 (
24 28 LineReader lr,
25 29 ) =
26   - if lr is line_reader(_, offset) then offset(unique).
  30 + if lr is line_reader(_, offset, _) then offset(unique).
27 31  
28 32 public define Maybe(String)
29 33 read_line
30 34 (
31 35 LineReader lr,
32 36 ) =
33   - if lr is line_reader(lexer, offset) then
  37 + if lr is line_reader(lexer, offset, _) then
34 38 if lexer(unique) is
35 39 {
36 40 end_of_input then /* no more token: exit the main loop */
... ... @@ -57,11 +61,9 @@ public define Maybe(String)
57 61  
58 62  
59 63  
60   -public define Maybe(LineReader)
61   - make_line_reader
62   - (
63   - LexingStream ls,
64   - ) =
  64 +public define Maybe(LineReaderLexer)
  65 + make_line_reader_lexer
  66 + =
65 67 if make_lexer_and_automaton([
66 68 lexer_item("#r?#n", return((ByteArray b) |-> token(eol))),
67 69 lexer_item("#r", return((ByteArray b) |-> token(eol))),
... ... @@ -70,11 +72,32 @@ public define Maybe(LineReader)
70 72 '#') is
71 73 {
72 74 error(msg) then print("Syntax error in regular expression: "+to_English(msg)+"\n"); failure,
73   - ok(p) then if p is (lexer, automaton) then
  75 + ok(p) then if p is (lexer, automaton) then success(line_reader_lexer(lexer))
  76 + }.
  77 +
  78 +public define LineReader
  79 + make_line_reader
  80 + (
  81 + LexingStream ls,
  82 + LineReaderLexer make_lexer
  83 + ) =
  84 + if make_lexer is line_reader_lexer(lexer) then
  85 + line_reader(lexer(ls), offset_counter(ls), make_lexer).
  86 +
  87 +public define Maybe(LineReader)
  88 + make_line_reader
  89 + (
  90 + LexingStream ls,
  91 + ) =
  92 + if make_line_reader_lexer is
  93 + {
  94 + failure then failure,
  95 + success(lexer) then
74 96 /* prepare the input stream */
75   - success(line_reader(lexer(ls), offset_counter(ls)))
  97 + success(make_line_reader(ls, lexer))
76 98 }.
77 99  
  100 +
78 101 public define Maybe(LineReader)
79 102 make_line_reader
80 103 (
... ... @@ -98,3 +121,11 @@ public define Maybe(LineReader)
98 121 }.
99 122  
100 123  
  124 +public define LineReader
  125 + reset_line_reader
  126 + (
  127 + LineReader lr,
  128 + LexingStream ls,
  129 + ) =
  130 + if lr is line_reader(lexer, offset, make_lexer) then
  131 + make_line_reader(ls, make_lexer).
... ...
anubis_dev/library/tools/streams.anubis
... ... @@ -55,6 +55,7 @@ public define List(StreamCapability) get_capabilities(Stream s).
55 55  
56 56 public define Maybe(Word8) read_byte (Stream s).
57 57 public define Maybe(String) read_line (Stream s).
  58 +public define List(String) read_lines (Stream s).
58 59 public define One skip_blanks (Stream s).
59 60 public define Maybe(String) read_symbol (Stream s).
60 61 public define Maybe(String) read_integer (Stream s).
... ... @@ -431,7 +432,7 @@ define List(String)
431 432 }.
432 433  
433 434  
434   -define List(String)
  435 +public define List(String)
435 436 read_lines
436 437 (
437 438 Stream s
... ...