build: Allow 'make quickcheck' test-tool args to be overridden.
[libguestfs.git] / generator / generator_java.ml
1 (* libguestfs
2  * Copyright (C) 2009-2011 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *)
18
19 (* Please read generator/README first. *)
20
21 open Printf
22
23 open Generator_types
24 open Generator_utils
25 open Generator_pr
26 open Generator_docstrings
27 open Generator_optgroups
28 open Generator_actions
29 open Generator_structs
30 open Generator_c
31
32 (* Generate Java bindings GuestFS.java file. *)
33 let rec generate_java_java () =
34   generate_header CStyle LGPLv2plus;
35
36   pr "\
37 package com.redhat.et.libguestfs;
38
39 import java.util.HashMap;
40 import java.util.Map;
41 import com.redhat.et.libguestfs.LibGuestFSException;
42 import com.redhat.et.libguestfs.PV;
43 import com.redhat.et.libguestfs.VG;
44 import com.redhat.et.libguestfs.LV;
45 import com.redhat.et.libguestfs.Stat;
46 import com.redhat.et.libguestfs.StatVFS;
47 import com.redhat.et.libguestfs.IntBool;
48 import com.redhat.et.libguestfs.Dirent;
49
50 /**
51  * The GuestFS object is a libguestfs handle.
52  *
53  * @author rjones
54  */
55 public class GuestFS {
56   // Load the native code.
57   static {
58     System.loadLibrary (\"guestfs_jni\");
59   }
60
61   /**
62    * The native guestfs_h pointer.
63    */
64   long g;
65
66   /**
67    * Create a libguestfs handle.
68    *
69    * @throws LibGuestFSException
70    */
71   public GuestFS () throws LibGuestFSException
72   {
73     g = _create ();
74   }
75   private native long _create () throws LibGuestFSException;
76
77   /**
78    * Close a libguestfs handle.
79    *
80    * You can also leave handles to be collected by the garbage
81    * collector, but this method ensures that the resources used
82    * by the handle are freed up immediately.  If you call any
83    * other methods after closing the handle, you will get an
84    * exception.
85    *
86    * @throws LibGuestFSException
87    */
88   public void close () throws LibGuestFSException
89   {
90     if (g != 0)
91       _close (g);
92     g = 0;
93   }
94   private native void _close (long g) throws LibGuestFSException;
95
96   public void finalize () throws LibGuestFSException
97   {
98     close ();
99   }
100
101 ";
102
103   List.iter (
104     fun (name, (ret, args, optargs as style), _, flags, _, shortdesc, longdesc) ->
105       if not (List.mem NotInDocs flags); then (
106         let doc = replace_str longdesc "C<guestfs_" "C<g." in
107         let doc =
108           if optargs <> [] then
109             doc ^ "\n\nOptional arguments are supplied in the final Map<String,Object> parameter, which is a hash of the argument name to its value (cast to Object).  Pass an empty Map for no optional arguments."
110           else doc in
111         let doc =
112           if List.mem ProtocolLimitWarning flags then
113             doc ^ "\n\n" ^ protocol_limit_warning
114           else doc in
115         let doc =
116           if List.mem DangerWillRobinson flags then
117             doc ^ "\n\n" ^ danger_will_robinson
118           else doc in
119         let doc =
120           match deprecation_notice flags with
121           | None -> doc
122           | Some txt -> doc ^ "\n\n" ^ txt in
123         let doc = pod2text ~width:60 name doc in
124         let doc = List.map (            (* RHBZ#501883 *)
125           function
126           | "" -> "<p>"
127           | nonempty -> nonempty
128         ) doc in
129         let doc = String.concat "\n   * " doc in
130
131         pr "  /**\n";
132         pr "   * %s\n" shortdesc;
133         pr "   * <p>\n";
134         pr "   * %s\n" doc;
135         pr "   * @throws LibGuestFSException\n";
136         pr "   */\n";
137       );
138       pr "  ";
139       generate_java_prototype ~public:true ~semicolon:false name style;
140       pr "\n";
141       pr "  {\n";
142       pr "    if (g == 0)\n";
143       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
144         name;
145       (match ret with
146        | RErr ->
147            pr "    _%s " name;
148            generate_java_call_args ~handle:"g" style;
149            pr ";\n"
150        | RHashtable _ ->
151            pr "    String[] r = _%s " name;
152            generate_java_call_args ~handle:"g" style;
153            pr ";\n";
154            pr "\n";
155            pr "    HashMap rhash = new HashMap ();\n";
156            pr "    for (int i = 0; i < r.length; i += 2)\n";
157            pr "      rhash.put (r[i], r[i+1]);\n";
158            pr "    return rhash;\n"
159        | _ ->
160            pr "    return _%s " name;
161            generate_java_call_args ~handle:"g" style;
162            pr ";\n"
163       );
164       pr "  }\n";
165       pr "  ";
166       generate_java_prototype ~privat:true ~native:true name style;
167       pr "\n";
168       pr "\n";
169   ) all_functions;
170
171   pr "}\n"
172
173 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
174 and generate_java_call_args ~handle (_, args, optargs) =
175   pr "(%s" handle;
176   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
177   if optargs <> [] then pr ", optargs";
178   pr ")"
179
180 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
181     ?(semicolon=true) name (ret, args, optargs) =
182   if privat then pr "private ";
183   if public then pr "public ";
184   if native then pr "native ";
185
186   (* return type *)
187   (match ret with
188    | RErr -> pr "void ";
189    | RInt _ -> pr "int ";
190    | RInt64 _ -> pr "long ";
191    | RBool _ -> pr "boolean ";
192    | RConstString _ | RConstOptString _ | RString _
193    | RBufferOut _ -> pr "String ";
194    | RStringList _ -> pr "String[] ";
195    | RStruct (_, typ) ->
196        let name = java_name_of_struct typ in
197        pr "%s " name;
198    | RStructList (_, typ) ->
199        let name = java_name_of_struct typ in
200        pr "%s[] " name;
201    | RHashtable _ ->
202        if not native then
203          pr "Map<String,String> "
204        else
205          pr "String[] ";
206   );
207
208   if native then pr "_%s " name else pr "%s " name;
209   pr "(";
210   let needs_comma = ref false in
211   if native then (
212     pr "long g";
213     needs_comma := true
214   );
215
216   (* args *)
217   List.iter (
218     fun arg ->
219       if !needs_comma then pr ", ";
220       needs_comma := true;
221
222       match arg with
223       | Pathname n
224       | Device n | Dev_or_Path n
225       | String n
226       | OptString n
227       | FileIn n
228       | FileOut n
229       | Key n ->
230           pr "String %s" n
231       | BufferIn n ->
232           pr "byte[] %s" n
233       | StringList n | DeviceList n ->
234           pr "String[] %s" n
235       | Bool n ->
236           pr "boolean %s" n
237       | Int n ->
238           pr "int %s" n
239       | Int64 n | Pointer (_, n) ->
240           pr "long %s" n
241   ) args;
242
243   if optargs <> [] then (
244     if !needs_comma then pr ", ";
245     needs_comma := true;
246     pr "HashMap optargs"
247   );
248
249   pr ")\n";
250   pr "    throws LibGuestFSException";
251   if semicolon then pr ";"
252
253 and generate_java_struct jtyp cols () =
254   generate_header CStyle LGPLv2plus;
255
256   pr "\
257 package com.redhat.et.libguestfs;
258
259 /**
260  * Libguestfs %s structure.
261  *
262  * @author rjones
263  * @see GuestFS
264  */
265 public class %s {
266 " jtyp jtyp;
267
268   List.iter (
269     function
270     | name, FString
271     | name, FUUID
272     | name, FBuffer -> pr "  public String %s;\n" name
273     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
274     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
275     | name, FChar -> pr "  public char %s;\n" name
276     | name, FOptPercent ->
277         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
278         pr "  public float %s;\n" name
279   ) cols;
280
281   pr "}\n"
282
283 and generate_java_c () =
284   generate_header CStyle LGPLv2plus;
285
286   pr "\
287 #include <stdio.h>
288 #include <stdlib.h>
289 #include <string.h>
290
291 #include \"com_redhat_et_libguestfs_GuestFS.h\"
292 #include \"guestfs.h\"
293
294 /* Note that this function returns.  The exception is not thrown
295  * until after the wrapper function returns.
296  */
297 static void
298 throw_exception (JNIEnv *env, const char *msg)
299 {
300   jclass cl;
301   cl = (*env)->FindClass (env,
302                           \"com/redhat/et/libguestfs/LibGuestFSException\");
303   (*env)->ThrowNew (env, cl, msg);
304 }
305
306 JNIEXPORT jlong JNICALL
307 Java_com_redhat_et_libguestfs_GuestFS__1create
308   (JNIEnv *env, jobject obj)
309 {
310   guestfs_h *g;
311
312   g = guestfs_create ();
313   if (g == NULL) {
314     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
315     return 0;
316   }
317   guestfs_set_error_handler (g, NULL, NULL);
318   return (jlong) (long) g;
319 }
320
321 JNIEXPORT void JNICALL
322 Java_com_redhat_et_libguestfs_GuestFS__1close
323   (JNIEnv *env, jobject obj, jlong jg)
324 {
325   guestfs_h *g = (guestfs_h *) (long) jg;
326   guestfs_close (g);
327 }
328
329 ";
330
331   List.iter (
332     fun (name, (ret, args, optargs as style), _, _, _, _, _) ->
333       pr "JNIEXPORT ";
334       (match ret with
335        | RErr -> pr "void ";
336        | RInt _ -> pr "jint ";
337        | RInt64 _ -> pr "jlong ";
338        | RBool _ -> pr "jboolean ";
339        | RConstString _ | RConstOptString _ | RString _
340        | RBufferOut _ -> pr "jstring ";
341        | RStruct _ | RHashtable _ ->
342            pr "jobject ";
343        | RStringList _ | RStructList _ ->
344            pr "jobjectArray ";
345       );
346       pr "JNICALL\n";
347       pr "Java_com_redhat_et_libguestfs_GuestFS_";
348       pr "%s" (replace_str ("_" ^ name) "_" "_1");
349       pr "\n";
350       pr "  (JNIEnv *env, jobject obj, jlong jg";
351       List.iter (
352         function
353         | Pathname n
354         | Device n | Dev_or_Path n
355         | String n
356         | OptString n
357         | FileIn n
358         | FileOut n
359         | Key n ->
360             pr ", jstring j%s" n
361         | BufferIn n ->
362             pr ", jbyteArray j%s" n
363         | StringList n | DeviceList n ->
364             pr ", jobjectArray j%s" n
365         | Bool n ->
366             pr ", jboolean j%s" n
367         | Int n ->
368             pr ", jint j%s" n
369         | Int64 n | Pointer (_, n) ->
370             pr ", jlong j%s" n
371       ) args;
372       if optargs <> [] then
373         pr ", jobject joptargs";
374       pr ")\n";
375       pr "{\n";
376       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
377       (match ret with
378        | RErr -> pr "  int r;\n"
379        | RBool _
380        | RInt _ -> pr "  int r;\n"
381        | RInt64 _ -> pr "  int64_t r;\n"
382        | RConstString _ -> pr "  const char *r;\n"
383        | RConstOptString _ -> pr "  const char *r;\n"
384        | RString _ ->
385            pr "  jstring jr;\n";
386            pr "  char *r;\n"
387        | RStringList _
388        | RHashtable _ ->
389            pr "  jobjectArray jr;\n";
390            pr "  int r_len;\n";
391            pr "  jclass cl;\n";
392            pr "  jstring jstr;\n";
393            pr "  char **r;\n"
394        | RStruct (_, typ) ->
395            pr "  jobject jr;\n";
396            pr "  jclass cl;\n";
397            pr "  jfieldID fl;\n";
398            pr "  struct guestfs_%s *r;\n" typ
399        | RStructList (_, typ) ->
400            pr "  jobjectArray jr;\n";
401            pr "  jclass cl;\n";
402            pr "  jfieldID fl;\n";
403            pr "  jobject jfl;\n";
404            pr "  struct guestfs_%s_list *r;\n" typ
405        | RBufferOut _ ->
406            pr "  jstring jr;\n";
407            pr "  char *r;\n";
408            pr "  size_t size;\n"
409       );
410
411       List.iter (
412         function
413         | Pathname n
414         | Device n | Dev_or_Path n
415         | String n
416         | OptString n
417         | FileIn n
418         | FileOut n
419         | Key n ->
420             pr "  const char *%s;\n" n
421         | BufferIn n ->
422             pr "  jbyte *%s;\n" n;
423             pr "  size_t %s_size;\n" n
424         | StringList n | DeviceList n ->
425             pr "  int %s_len;\n" n;
426             pr "  const char **%s;\n" n
427         | Bool n
428         | Int n ->
429             pr "  int %s;\n" n
430         | Int64 n ->
431             pr "  int64_t %s;\n" n
432         | Pointer (t, n) ->
433             pr "  %s %s;\n" t n
434       ) args;
435
436       let needs_i =
437         (match ret with
438          | RStringList _ | RStructList _ | RHashtable _ -> true
439          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
440          | RConstOptString _
441          | RString _ | RBufferOut _ | RStruct _ -> false) ||
442           List.exists (function
443                        | StringList _ -> true
444                        | DeviceList _ -> true
445                        | _ -> false) args in
446       if needs_i then
447         pr "  size_t i;\n";
448
449       pr "\n";
450
451       (* Get the parameters. *)
452       List.iter (
453         function
454         | Pathname n
455         | Device n | Dev_or_Path n
456         | String n
457         | FileIn n
458         | FileOut n
459         | Key n ->
460             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
461         | OptString n ->
462             (* This is completely undocumented, but Java null becomes
463              * a NULL parameter.
464              *)
465             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
466         | BufferIn n ->
467             pr "  %s = (*env)->GetByteArrayElements (env, j%s, NULL);\n" n n;
468             pr "  %s_size = (*env)->GetArrayLength (env, j%s);\n" n n
469         | StringList n | DeviceList n ->
470             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
471             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
472             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
473             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
474               n;
475             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
476             pr "  }\n";
477             pr "  %s[%s_len] = NULL;\n" n n;
478         | Bool n
479         | Int n
480         | Int64 n ->
481             pr "  %s = j%s;\n" n n
482         | Pointer (t, n) ->
483             pr "  %s = (%s) j%s;\n" n t n
484       ) args;
485
486       if optargs <> [] then (
487         (* XXX *)
488         pr "  throw_exception (env, \"%s: internal error: please let us know how to read a Java HashMap parameter from JNI bindings!\");\n" name;
489         pr "  return NULL;\n";
490         pr "  /*\n";
491       );
492
493       (* Make the call. *)
494       if optargs = [] then
495         pr "  r = guestfs_%s " name
496       else
497         pr "  r = guestfs_%s_argv " name;
498       generate_c_call_args ~handle:"g" style;
499       pr ";\n";
500
501       (* Release the parameters. *)
502       List.iter (
503         function
504         | Pathname n
505         | Device n | Dev_or_Path n
506         | String n
507         | FileIn n
508         | FileOut n
509         | Key n ->
510             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
511         | OptString n ->
512             pr "  if (j%s)\n" n;
513             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
514         | BufferIn n ->
515             pr "  (*env)->ReleaseByteArrayElements (env, j%s, %s, 0);\n" n n
516         | StringList n | DeviceList n ->
517             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
518             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
519               n;
520             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
521             pr "  }\n";
522             pr "  free (%s);\n" n
523         | Bool _
524         | Int _
525         | Int64 _
526         | Pointer _ -> ()
527       ) args;
528
529       (* Check for errors. *)
530       (match errcode_of_ret ret with
531        | `CannotReturnError -> ()
532        | `ErrorIsMinusOne ->
533            pr "  if (r == -1) {\n";
534            pr "    throw_exception (env, guestfs_last_error (g));\n";
535            pr "    return -1;\n";
536            pr "  }\n"
537        | `ErrorIsNULL ->
538            pr "  if (r == NULL) {\n";
539            pr "    throw_exception (env, guestfs_last_error (g));\n";
540            pr "    return NULL;\n";
541            pr "  }\n"
542       );
543
544       (* Return value. *)
545       (match ret with
546        | RErr -> ()
547        | RInt _ -> pr "  return (jint) r;\n"
548        | RBool _ -> pr "  return (jboolean) r;\n"
549        | RInt64 _ -> pr "  return (jlong) r;\n"
550        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
551        | RConstOptString _ ->
552            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
553        | RString _ ->
554            pr "  jr = (*env)->NewStringUTF (env, r);\n";
555            pr "  free (r);\n";
556            pr "  return jr;\n"
557        | RStringList _
558        | RHashtable _ ->
559            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
560            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
561            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
562            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
563            pr "  for (i = 0; i < r_len; ++i) {\n";
564            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
565            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
566            pr "    free (r[i]);\n";
567            pr "  }\n";
568            pr "  free (r);\n";
569            pr "  return jr;\n"
570        | RStruct (_, typ) ->
571            let jtyp = java_name_of_struct typ in
572            let cols = cols_of_struct typ in
573            generate_java_struct_return typ jtyp cols
574        | RStructList (_, typ) ->
575            let jtyp = java_name_of_struct typ in
576            let cols = cols_of_struct typ in
577            generate_java_struct_list_return typ jtyp cols
578        | RBufferOut _ ->
579            pr "  jr = (*env)->NewStringUTF (env, r); // XXX size\n";
580            pr "  free (r);\n";
581            pr "  return jr;\n"
582       );
583
584       if optargs <> [] then
585         pr "  */\n";
586
587       pr "}\n";
588       pr "\n"
589   ) all_functions
590
591 and generate_java_struct_return typ jtyp cols =
592   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
593   pr "  jr = (*env)->AllocObject (env, cl);\n";
594   List.iter (
595     function
596     | name, FString ->
597         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
598         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
599     | name, FUUID ->
600         pr "  {\n";
601         pr "    char s[33];\n";
602         pr "    memcpy (s, r->%s, 32);\n" name;
603         pr "    s[32] = 0;\n";
604         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
605         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
606         pr "  }\n";
607     | name, FBuffer ->
608         pr "  {\n";
609         pr "    int len = r->%s_len;\n" name;
610         pr "    char s[len+1];\n";
611         pr "    memcpy (s, r->%s, len);\n" name;
612         pr "    s[len] = 0;\n";
613         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
614         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
615         pr "  }\n";
616     | name, (FBytes|FUInt64|FInt64) ->
617         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
618         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
619     | name, (FUInt32|FInt32) ->
620         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
621         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
622     | name, FOptPercent ->
623         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
624         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
625     | name, FChar ->
626         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
627         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
628   ) cols;
629   pr "  free (r);\n";
630   pr "  return jr;\n"
631
632 and generate_java_struct_list_return typ jtyp cols =
633   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
634   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
635   pr "  for (i = 0; i < r->len; ++i) {\n";
636   pr "    jfl = (*env)->AllocObject (env, cl);\n";
637   List.iter (
638     function
639     | name, FString ->
640         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
641         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
642     | name, FUUID ->
643         pr "    {\n";
644         pr "      char s[33];\n";
645         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
646         pr "      s[32] = 0;\n";
647         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
648         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
649         pr "    }\n";
650     | name, FBuffer ->
651         pr "    {\n";
652         pr "      int len = r->val[i].%s_len;\n" name;
653         pr "      char s[len+1];\n";
654         pr "      memcpy (s, r->val[i].%s, len);\n" name;
655         pr "      s[len] = 0;\n";
656         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
657         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
658         pr "    }\n";
659     | name, (FBytes|FUInt64|FInt64) ->
660         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
661         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
662     | name, (FUInt32|FInt32) ->
663         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
664         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
665     | name, FOptPercent ->
666         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
667         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
668     | name, FChar ->
669         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
670         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
671   ) cols;
672   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
673   pr "  }\n";
674   pr "  guestfs_free_%s_list (r);\n" typ;
675   pr "  return jr;\n"
676
677 and generate_java_makefile_inc () =
678   generate_header HashStyle GPLv2plus;
679
680   pr "java_built_sources = \\\n";
681   List.iter (
682     fun (typ, jtyp) ->
683         pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
684   ) java_structs;
685   pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"