Clarify licensing for Debian.
[ocaml-bitstring.git] / cil-tools / bitmatch_import_c.ml
index c61f751..0bf655f 100644 (file)
@@ -1,19 +1,19 @@
 (* Import a C header file.
  * Copyright (C) 2008 Red Hat Inc., Richard W.M. Jones
  *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * This library is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Id$
  *)
@@ -24,6 +24,10 @@ open ExtString
 
 open Cil
 
+module P = Bitmatch_persistent
+
+let (//) = Filename.concat
+
 let () =
   (* Parse command line arguments. *)
   let debug = ref false in
@@ -97,8 +101,9 @@ OPTIONS" in
     ) in
 
   let cmd =
-    sprintf "cpp %s -include bitmatch-import-prefix.h %s > %s"
+    sprintf "cpp %s -I %s -include bitmatch-import-prefix.h %s > %s"
       (String.concat " " (List.map Filename.quote cpp_args))
+      (Filename.quote (Bitmatch_config.ocamllibdir // "bitmatch"))
       (Filename.quote input_file) (Filename.quote tmp) in
   if debug then prerr_endline cmd;
   if Sys.command cmd <> 0 then (
@@ -161,11 +166,15 @@ OPTIONS" in
     ) structs;
   );
 
-  (* Output constants. *)
+(*
+  (* Output constants.
+   * XXX Disabled at the moment until we work out where to put them XXX
+   *)
   List.iter (
     fun (vname, vinit, loc) ->
       printf "let %s = 0x%LX\n" vname vinit
   ) constants;
+*)
 
   (* Output structures. *)
   List.iter (
@@ -176,44 +185,28 @@ OPTIONS" in
        *)
       (*Errormsg.log "%a: %s %a\n" d_loc loc tname d_plaintype ttype;*)
 
-      (* Match on the type of this structure, and from it generate
-       * a single parsing function.
-       *)
-      match ttype with
-       (* struct or union *)
-      | TComp ({ cdefined = true; cname = cname }, _) ->
-         printf "let %s_of_bitstring bits =\n" tname;
-         printf "  bitmatch bits with\n";
-         printf "  | {\n";
-         (*output_struct [] NoOffset None ttype;*)
-         printf "    } ->\n";
-         printf "    Some (...)\n";
-         printf "  | { _ } -> None\n\n"
-
-      (* An undefined struct or union -- means one which was only ever
-       * defined with 'struct foo;'.  This is an error.
-       *)
-      | TComp ({ cdefined = false; cname = cname }, _) ->
-         Errormsg.error
-           "%a: struct or union has no definition: %s" d_loc loc cname
-
-      (* Types which are not allowed, eg. void, int, arrays. *)
-      | TVoid _ | TInt _ | TFloat _ | TPtr _ | TArray _ | TFun _
-      | TNamed _ | TBuiltin_va_list _ ->
-         Errormsg.error
-           "%a: not a struct or union: %a" d_loc loc d_type ttype
-
-      (* Types which we might implement in the future.
-       * For enum we should probably split out enums separately
-       * from structs above, since enums are more like constants.
+      (* Recursive function to generate a persistent pattern from a
+       * C struct or union.  Quite a few limitations at the moment:
+       *   (1) Structure elements must be in order.
+       *   (2) Doesn't really work with unions [XXX].
+       *
+       * Parameters:
+       *   ?names   List of names of parent structs.  Used in the
+       *              recursive case for nested structs.
+       *   ?offset  Offset of struct within parent, usually NoOffset.  Used
+       *              in the recursive case for nested structs.
+       *   ?endian  Inherited endianness, usually None.  Used for C
+       *                __attribute__((bitwise)).
+       *   ttype    CIL type of struct.
+       * Returns:
+       *   pattern  A bitmatch persistent pattern.
        *)
-      | TEnum ({ ename = ename }, _) ->
-         Errormsg.unimp "%a: %a" d_loc loc d_type ttype
-(*
-      let rec to_fields names offset endian = function
-         (* Some types contain attributes to indicate their
-          * endianness.  See many examples from <linux/types.h>.
-          *)
+      let rec pattern_of_struct ?(names=[]) ?(offset=NoOffset) ?(endian=None)
+         ttype =
+       match ttype with
+       (* Some types contain attributes to indicate their
+        * endianness.  See many examples from <linux/types.h>.
+        *)
        | (TNamed ({ tname = tname;
                     ttype = TNamed (_, attrs) },
                   _) as t)
@@ -228,11 +221,11 @@ OPTIONS" in
                  d_loc loc tname;
                endian
              ) in
-           to_fields names offset endian (unrollType t)
+           pattern_of_struct ~names ~offset ~endian (unrollType t)
 
         (* See into named types. *)
        | (TNamed _ as t) ->
-           to_fields names offset endian (unrollType t)
+           pattern_of_struct ~names ~offset ~endian (unrollType t)
 
        (* struct or union *)
        | TComp ({ cdefined = true; cfields = cfields }, _) ->
@@ -241,21 +234,15 @@ OPTIONS" in
                fun ({ fname = fname; ftype = ftype } as finfo) ->
                  let offset = Field (finfo, offset) in
                  let names = fname :: names in
-                 to_fields names offset endian ftype
+                 pattern_of_struct ~names ~offset ~endian ftype
              ) cfields in
            List.flatten cfields
 
        (* int array with constant length *)
-       | TArray (basetype, (Some _ as len), _)
-           when isIntegralType basetype ->
-           let len = lenOfArray len in
+       | TArray (basetype, (Some _ as len), _) when isIntegralType basetype ->
+           let nr_elems = lenOfArray len in
            let bitsoffset, totalwidth = bitsOffset ttype offset in
-           let bitswidth = totalwidth / len (* of the element *) in
-           (*if debug then (
-             let name = String.concat "." (List.rev names) in
-             Errormsg.log "%s: int array: %d, %d, len %d\n"
-               name bitsoffset bitswidth len
-           );*)
+           let bitswidth = totalwidth / nr_elems (* of the element *) in
            let basetype = unrollType basetype in
            let ikind =
              match basetype with
@@ -263,14 +250,25 @@ OPTIONS" in
              | t ->
                  Errormsg.unimp "%a: unhandled type: %a" d_loc loc d_type t;
                  IInt in
-           let field =
-             to_int_field "" bitsoffset bitswidth ikind endian in
            let fname = String.concat "_" (List.rev names) in
-           let byteoffset = bitsoffset lsr 3 in
-           let bytetotalwidth = totalwidth lsr 3 in
-           printf "--> array %s: byteoffset=%d bytetotalwidth=%d len=%d\n"
-             fname byteoffset bytetotalwidth len (* field *);
-           []
+
+           (* If the base type is 8 bits then we always translate this to
+            * a string (whether the C type is signed or unsigned).  There
+            * is no endianness in bytes so ignore that.
+            *)
+           if bitswidth = 8 then
+             [pattern_field_of_string fname bitsoffset nr_elems]
+           else (
+             (* XXX Realistically we don't handle arrays well at
+              * the moment.  Perhaps we should give up and match
+              * this to a bitstring?
+              *)
+             let signed = isSigned ikind in
+             if debug then
+               eprintf "--> array %s: nr_elems=%d signed=%b\n"
+                 fname nr_elems signed;
+             [] (* XXX *)
+           )
 
        (* basic integer type *)
        | TInt (ikind, _) ->
@@ -281,7 +279,7 @@ OPTIONS" in
            );*)
            let fname = String.concat "_" (List.rev names) in
            let field =
-             to_int_field fname bitsoffset bitswidth ikind endian in
+             pattern_field_of_int fname bitsoffset bitswidth ikind endian in
            [field]
 
        (* a pointer - in this mapping we assume this is an address
@@ -292,49 +290,83 @@ OPTIONS" in
        | TPtr _ ->
            let bitsoffset, bitswidth = bitsOffset ttype offset in
            let fname = String.concat "_" (List.rev names) in
-           printf "--> pointer %s: bitsoffset=%d bitswidth=%d\n"
-             fname bitsoffset bitswidth;
-           []
+           if debug then
+             eprintf "--> pointer %s: bitsoffset=%d bitswidth=%d\n"
+               fname bitsoffset bitswidth;
+           [] (* XXX *)
 
        | t ->
-           Errormsg.unimp "to_fields: %a: unhandled type: %a"
+           Errormsg.warn "pattern_of_struct: %a: unhandled type: %a"
              d_loc loc d_type t;
            []
 
-      and to_int_field fname bitsoffset bitswidth ikind endian =
-       let byteoffset = bitsoffset lsr 3 in
-       let bytewidth = bitswidth lsr 3 in
+      (* Convert a single int field into a pattern field.
+       * Could be a bitfield, byte, short, etc.
+       *)
+      and pattern_field_of_int fname bitsoffset bitswidth ikind endian =
        let signed = isSigned ikind in
-
-       if bitsoffset land 7 = 0 && bitswidth land 7 = 0 then (
-         (* Not a bitfield. *)
-         match bitswidth with
-         | 8 ->
-             printf "--> byte %s: byteoffset=%d bytewidth=%d signed=%b\n"
-               fname byteoffset bytewidth signed
-         | 16 ->
-             printf "--> short %s: byteoffset=%d bytewidth=%d signed=%b endian=%s\n"
-               fname byteoffset bytewidth signed (Option.map_default Bitmatch.string_of_endian "None" endian)
-         | 32 ->
-             printf "--> int %s: byteoffset=%d bytewidth=%d signed=%b endian=%s\n"
-               fname byteoffset bytewidth signed (Option.map_default Bitmatch.string_of_endian "None" endian)
-         | 64 ->
-             printf "--> long %s: byteoffset=%d bytewidth=%d signed=%b endian=%s\n"
-               fname byteoffset bytewidth signed (Option.map_default Bitmatch.string_of_endian "None" endian)
-         | _ ->
-             Errormsg.unimp "%s: unhandled integer width: %d bits"
-               fname bitswidth
-       ) else (
-         (* It's a bitfield if either the offset or width isn't
-          * byte-aligned.
-          *)
-         let bitsoffset = bitsoffset land 7 in
-         printf "--> bitfield %s: byteoffset=%d bytewidth=%d signed=%b endian=%s bitsoffset=%d bitswidth=%d\n"
-           fname byteoffset bytewidth
-           signed (Option.map_default Bitmatch.string_of_endian "None" endian) bitsoffset bitswidth
-       )
+       let _loc = camlp4_loc_of_cil_loc loc in
+
+       let field = P.create_pattern_field _loc in
+       let field = P.set_lident_patt field fname in
+       let field = P.set_type_int field in
+       let field = P.set_length_int field bitswidth in
+       let field = P.set_offset_int field bitsoffset in
+       let field = P.set_signed field signed in
+       let field =
+         match endian with
+         | Some endian -> P.set_endian field endian
+         | None -> P.set_endian field Bitmatch.NativeEndian in
+
+       field
+
+      and pattern_field_of_string fname bitsoffset nr_elems =
+       let _loc = camlp4_loc_of_cil_loc loc in
+       let field = P.create_pattern_field _loc in
+       let field = P.set_lident_patt field fname in
+       let field = P.set_type_string field in
+       let field = P.set_length_int field (nr_elems*8) in
+       let field = P.set_offset_int field bitsoffset in
+       field
+
+      (* Convert a CIL location into a camlp4 location.  Grrr these
+       * should be compatible!
+       *)
+      and camlp4_loc_of_cil_loc loc =
+       let _loc = Camlp4.PreCast.Syntax.Ast.Loc.mk loc.file in
+       Camlp4.PreCast.Syntax.Ast.Loc.move_line loc.line _loc
       in
-*)
+
+      (* Match on the type of this structure, and from it generate
+       * a single parsing function.
+       *)
+      match ttype with
+      (* struct or union *)
+      | TComp ({ cdefined = true; cname = cname }, _) ->
+         let pattern = pattern_of_struct ttype in
+         let named_pattern = cname, P.Pattern pattern in
+         P.named_to_channel stdout named_pattern
+
+      (* An undefined struct or union -- means one which was only ever
+       * defined with 'struct foo;'.  This is an error.
+       *)
+      | TComp ({ cdefined = false; cname = cname }, _) ->
+         Errormsg.error
+           "%a: struct or union has no definition: %s" d_loc loc cname
+
+      (* Types which are not allowed, eg. void, int, arrays. *)
+      | TVoid _ | TInt _ | TFloat _ | TPtr _ | TArray _ | TFun _
+      | TNamed _ | TBuiltin_va_list _ ->
+         Errormsg.error
+           "%a: not a struct or union: %a" d_loc loc d_type ttype
+
+      (* Types which we might implement in the future.
+       * For enum we should probably split out enums separately
+       * from structs above, since enums are more like constants.
+       *)
+      | TEnum ({ ename = ename }, _) ->
+         Errormsg.unimp "%a: %a" d_loc loc d_type ttype
+
   ) structs;
 
   if !Errormsg.hadErrors then exit 1;