Advertisement
nicolas42

Library-utils

Nov 5th, 2012
3,017
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
REBOL 8.72 KB | None | 0 0
  1. rebol [
  2.     Title: "Library-utils"
  3.     File: %library-utils.r
  4.     Author: "Ladislav Mecir"
  5.     Date: 6-Jul-2010/16:38:19+2:00
  6.     Purpose: {utilities supporting external library interface}
  7. ]
  8.  
  9. comment {
  10. ===Errors in the http://www.rebol.com/docs/library.html
  11.  
  12. *the "Specifying Datatypes in Routines" section contains the "C to REBOL Datatype Conversions" table, in which the next to the last row is incorrect, since the C struct datatype actually cannot be used in routine specification
  13.  
  14. *the last row of the table contains a char datatype, while the correct datatype should have been a pointer, i.e. the char* datatype
  15.  
  16. *the last row of the "REBOL to C Datatype Conversion" table states, that the REBOL STRUCT! datatype is converted to a C struct datatype, which is wrong, since REBOL STRUCT! datatype is rather converted to a C pointer
  17.  
  18. *there are many places, where a pointer datatype is mentioned using an incorrect notation, e.g. void, instead of the proper void*, char, instead of char*
  19.  
  20. *the REBOL STRUCT! datatype is not directly compatible with C struct, it is usually handled by the interpreter as a pointer, i.e. as a C struct* datatype.
  21.  
  22. ===Computing the size of a datatype
  23.  
  24.     sizeof 'double ; == 8
  25.     sizeof 'float ; == 4
  26.     sizeof 'long ; == 4
  27.     sizeof 'int ; == 4
  28.     sizeof 'short ; == 2
  29.     sizeof 'char* ; == 4 ; pointer
  30.     sizeof [struct! []] ; == 4 ; pointer
  31.     sizeof 'integer! ; == 4
  32.     sizeof 'char ; == 1
  33.  
  34. ===What is the best REBOL counterpart of a C pointer datatype?
  35.    
  36. In the C language, there are many distinct pointer types, e.g.:
  37. void*, char*, double*, int*, float*, etc.
  38.    
  39. The C pointers have all the same size, i.e. sizeof char* is the same as sizeof void*, etc., and it is easy to convert one pointer type to another, the only difference being, that pointer arithmetic expressions like p + 1 depend on pointer type.
  40.    
  41. According to http://www.rebol.com/docs/library.html#section-25 the most convenient counterparts of C pointers are REBOL integer! values, interpreted as memory addresses.
  42.    
  43. ---Advantages
  44.    
  45. *Integer arithmetic can be used to manipulate memory addresses without performing additional conversions. Doing so, REBOL integers behave exactly like char* pointers in C.
  46.  
  47. *Integer comparison can be used to compare memory addresses. For example, this is how we can find out in REBOL, whether an address was a NULL pointer in C:
  48.  
  49.     0 = address
  50.        
  51. *Memory addresses can be used in the role of C pointer counterparts both as return values as well as arguments of routines.
  52.  
  53. *The address of a REBOL string can be obtained as follows:
  54.  
  55.     string-address? "Hello, world!" ; == 42605768
  56.  
  57. *If we know the memory address of a string using the C convention (strigs are nul-terminated in C) we can obtain a copy of the string (in this example we use the address obtained above). Note, that the REBOL interpreter automatically appends the NUL (#"^(00)") character to every string, which means, that all REBOL strings not containing the NUL character adhere to the C string convention too.
  58.  
  59.     address-to-string 42605768 ; == "Hello, world!"
  60.  
  61. *We can even obtain a REBOL binary copy of a memory region at a given address, provided we supply the length of the region we want to copy:
  62.  
  63.     get-memory 42605768 14
  64.  
  65. *This is how other values stored at the given address can be obtained:
  66.  
  67.     convert 42605768 [char] ; == #"H"
  68.  
  69. *The address of a REBOL binary can be obtained using the STRING-ADDRESS? function too.
  70.  
  71. *The address of a REBOL struct can be obtained as follows:
  72.  
  73.     struct-address? make struct! [i [int]] [1]
  74.  
  75. *Using the SET-MEMORY function it is possible to directly change the memory at the specific address.
  76.    
  77. ---Disadvantages
  78.        
  79. *It may happen, that sizeof 'int is not equal to sizeof 'char*, in which case the code below needs adjustments!
  80.  
  81. ---Alternatives
  82.  
  83. Other REBOL datatypes that can be used as C pointer counterparts are the struct! datatype, string! datatype or the binary! datatype, but:
  84.  
  85. *the struct! datatype does not support arithmetic operations, neither it supports comparisons like above
  86.  
  87. *the string! datatype supports the skip (index) arithmetic, but it does not support comparisons like above, moreover, it works well for the returned char* pointers only in case they represent nul-terminated strings; if returned, we actually obtain a copy of the string returned, not the original, which may be a problem if we want to manipulate the original memory
  88.  
  89. *the binary! datatype supports the skip (index) arithmetic, but it is not suitable to represent a routine return value
  90.  
  91. ===Converting values (or blocks of values) to binaries and vice versa
  92.  
  93. REBOL decimals are 64-bit IEEE 754 FP numbers (equivalent of C double) in little endian byte order for Intel processors e.g. This is how to convert them to binary:
  94.  
  95.     d: convert [0.2] [double]
  96.     convert d [double] ; == [0.2]
  97.  
  98. Using an Intel processor, if you prefer a big endian byte order, reverse the conversion result:
  99.  
  100.     reverse convert [0.2] [double]
  101.  
  102. Conversion to the 32-bit IEEE 754 FP format (C float):
  103.  
  104.     convert [0.2] [float]
  105.  
  106. This is how to convert more values to binary and vice versa:
  107.  
  108.     b: convert [1 2] [int int]
  109.     convert b [int int] ; == [1 2]
  110.  
  111. ===The endianness of the processor
  112.  
  113. The endianness of the processor can be found as follows:
  114.  
  115.     endian?: pick [little big] 1 = first convert [1] [int]
  116.  
  117. Another way:
  118.  
  119.     endian?: get-modes system/ports/system 'endian
  120.  
  121. ===Calling library functions
  122.  
  123. If a library function f is declared as follows:
  124.    
  125.     int f (double* a, int size);
  126.  
  127. taking a double array a with a defined size, this is how its REBOL counterpart routine can be defined:
  128.  
  129.     f: make routine! [
  130.         a [integer!] ; using REBOL integer! in place of a C pointer
  131.         size [int]
  132.         return: [int]
  133.     ] library "f"
  134.  
  135. , and this is how we can call the routine using a size = 6 element array filled with 0.0s:
  136.  
  137.     size: 6
  138.     array: make binary! size * sizeof 'double
  139.     insert/dup array convert [0.0] [double] size
  140.     result: f string-address? array size
  141. }
  142.  
  143. use [
  144.     int-struct
  145.     string-struct
  146.     struct-struct
  147. ] [
  148.     int-struct: make struct! [int [integer!]] none
  149.     string-struct: make struct! [string [char*]] none
  150.     struct-struct: make struct! [struct [struct! [[save] c [char]]]] none
  151.    
  152.     sizeof: func [
  153.         {get the size of a datatype in bytes}
  154.         datatype [word! block!]
  155.     ] [
  156.         length? third make struct! compose/deep [value [(datatype)]] none
  157.     ]
  158.  
  159.     string-address?: func [
  160.         {get the address of the given string}
  161.         string [any-string!]
  162.     ] [
  163.         string-struct/string: string
  164.         change third int-struct third string-struct
  165.         int-struct/int
  166.     ]
  167.  
  168.     address-to-string: func [
  169.         {get a copy of the nul-terminated string at the given address}
  170.         address [integer!]
  171.     ] [
  172.         int-struct/int: address
  173.         change third string-struct third int-struct
  174.         string-struct/string
  175.     ]
  176.    
  177.     struct-address?: func [
  178.         {get the address of the given struct}
  179.         struct [struct!]
  180.     ] [
  181.         string-address? third struct
  182.     ]
  183.    
  184.     get-memory: func [
  185.         {
  186.             copy a region of memory having the given address and size,
  187.             the result is a REBOL binary value
  188.         }
  189.         address [integer!]
  190.         size [integer!]
  191.         /local struct
  192.     ] [
  193.         int-struct/int: address
  194.         struct: make struct! compose/deep [string [char-array (size)]] none
  195.         change third struct third int-struct
  196.         as-binary struct/string
  197.     ]
  198.    
  199.     set-memory: func [
  200.         {change a region of memory at the given address}
  201.         address [integer!]
  202.         contents [binary! string!]
  203.     ] [
  204.         int-struct/int: address
  205.         foreach char as-string contents [
  206.             change third struct-struct third int-struct
  207.             struct-struct/struct/c: char
  208.             int-struct/int: int-struct/int + 1
  209.         ]
  210.     ]
  211.    
  212.     convert: func [
  213.         {
  214.             convert block to binary,
  215.             binary to block,
  216.             or memory region to block
  217.         }
  218.         from [block! binary! integer!]
  219.         spec [block!] {
  220.             type specification, supported types are listed in
  221.             http://www.rebol.com/docs/library.html
  222.         }
  223.         /local result struct size
  224.     ] [
  225.         switch type? from [
  226.             #[datatype! block!] [
  227.                 result: copy #{}
  228.                 repeat i min length? from length? spec [
  229.                     append result third make struct! compose/deep [
  230.                         value [(pick spec i)]
  231.                     ] reduce [pick from i]         
  232.                 ]
  233.             ]
  234.             #[datatype! binary!] [
  235.                 result: copy []
  236.                 foreach type spec [
  237.                     struct: make struct! compose/deep [value [(type)]] none
  238.                     size: length? third struct
  239.                     if size > length? from [break]
  240.                     change third struct copy/part from size
  241.                     append result struct/value
  242.                     from: skip from size
  243.                 ]
  244.             ]
  245.             #[datatype! integer!] [
  246.                 result: copy []
  247.                 foreach type spec [
  248.                     struct: make struct! compose/deep [
  249.                         s [struct! [[save] value [(type)]]]
  250.                     ] none
  251.                     size: length? third struct/s
  252.                     int-struct/int: from
  253.                     change third struct third int-struct
  254.                     append result struct/s/value
  255.                     from: from + size
  256.                 ]
  257.             ]
  258.         ]
  259.         result
  260.     ]
  261. ]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement