]> icculus.org git repositories - duncan/yast2-ruby-bindings.git/blob - src/ruby/YCP.rb
fb820b561e7181c490c0a7e3359b4a5aef81f38d
[duncan/yast2-ruby-bindings.git] / src / ruby / YCP.rb
1 #! /usr/bin/perl -w
2 # Martin Vidner
3 # $Id: YCP.pm 33405 2006-10-13 13:12:42Z mvidner $
4
5 =head1 NAME
6
7 YaST::YCP - a binary interface between Perl and YCP
8
9 =head1 SYNOPSIS
10
11  use YaST::YCP qw(:DATA :LOGGING);
12
13  YaST::YCP::Import ("SCR");
14  my $m = SCR->Read (".sysconfig.displaymanager.DISPLAYMANAGER");
15  SCR->Write (".sysconfig.kernel.CRASH_OFTEN", Boolean (1));
16
17 =head1 DATA TYPES
18
19 YaST has a richer and stricter data type system than Perl.
20
21 Note that the stdio-communicating agents, based on the modules
22 L<YaST::SCRAgent|YaST::SCRAgent> and L<ycp|ycp>, have a similar but
23 not the same data type mapping.
24
25 When the language binding knows what type to expect, eg. when passing
26 an argument to a YCP function, it will convert a Perl scalar to the
27 desired type.
28
29 On the other hand, if the type is not known, expressed
30 in YCP as C<any>, scalars will be passed as strings. If you want
31 a specific data type, use one of the data classes like
32 L<YaST::YCP::Integer|/Integer>. Of course these work also when
33 the type is known.
34
35 =over 4
36
37 =item void
38
39 Has only one value, C<nil>, which is represented as C<undef>.
40 Any data type can have C<nil> as a value.
41
42 =item any
43
44 A union of all data types. Any data type can be assigned to it.
45
46 =item string, integer, float, boolean
47
48 B<YCP to Perl:> Becomes a scalar
49
50 B<Perl to YCP:> Any scalar will become a string
51 (even if it looks like a number).
52 Use L</String>, L</Integer>, L</Float> or L</Boolean>
53 if you want a specific data type.
54
55 =item list E<lt>TE<gt>
56
57 B<YCP to Perl:> A list becomes a reference to an array.
58 (Note that it refers to a B<copy>.)
59
60 B<Perl to YCP:> A reference to an array becomes a list.
61 I<This was different before SL9.1 Beta1:>
62 Perl functions returning multiple values should not return a list
63 but a reference to it. YCP will always set a scalar calling context,
64 even if the result is assigned to a list.
65
66 =item map E<lt>T1, T2E<gt>
67
68 B<YCP to Perl:> A map becomes a reference to a hash.
69 (Note that it refers to a B<copy>.)
70
71 B<Perl to YCP:> A reference to a hash becomes a map.
72
73 =item path
74
75 B<YCP to Perl:> NOT IMPLEMENTED YET.
76
77 B<Perl to YCP:> If a path is expected, a scalar like C<".foo.bar">
78 will be converted to C<.foo.bar>.
79 Otherwise use L</Path> (which is NOT IMPLEMENTED YET).
80
81 =item symbol
82
83 B<YCP to Perl:> Becomes a L</Symbol>.
84
85 B<Perl to YCP:> If a symbol is expected, a scalar like C<"foo">
86 will be converted to C<`foo>.
87 Otherwise use L</Symbol>.
88
89 =item term
90
91 B<YCP to Perl:> Becomes a L</Term>.
92
93 B<Perl to YCP:> Use L</Term>.
94
95 =item byteblock
96
97 B<YCP to Perl:> Becomes a scalar.
98
99 B<Perl to YCP:> If a byteblock is expected, a scalar like C<"\0\1">
100 will be converted to C<#[0001]>.
101 Otherwise use L</Byteblock>.
102
103 =item locale, block E<lt>TE<gt>, ...
104
105 Not implemented.
106
107 =back
108
109 =head1 YaST::YCP
110
111 The DATA tag (in C<use YaST::YCP qw(:DATA)>) imports the data
112 constructor functions such as Boolean, Symbol or Term.
113
114 =cut
115
116 package YaST::YCP;
117 use strict;
118 use warnings;
119 use diagnostics;
120
121 require Exporter;
122 our @ISA = qw(Exporter);
123 my @e_data = qw(Boolean Byteblock Integer Float String Symbol Term);
124 my @e_logging = qw(y2debug y2milestone y2warning y2error y2security y2internal);
125 our @EXPORT_OK = (@e_data, @e_logging, "sformat");
126 our %EXPORT_TAGS = ( DATA => [@e_data], LOGGING => [@e_logging] );
127
128 =head2 debug
129
130  $olddebug = YaST::YCP::debug (1);
131  YaST::YCP::...
132  YaST::YCP::debug ($olddebug);
133
134 Enables miscellaneous unscpecified debugging
135
136 =cut
137
138 my $debug = 0;
139 sub debug (;$)
140 {
141     my $param = shift;
142     if (defined $param)
143     {
144         $debug = $param;
145     }
146     return $debug;
147 }
148
149
150 ## calls boot_YaST__YCP
151 require XSLoader;
152 XSLoader::load ('YaST::YCP');
153
154 =head2 init_ui
155
156  YaST::YCP::init_ui ();
157  YaST::YCP::init_ui "qt";
158
159 Initializes the user interface, "ncurses" (the default) or "qt".
160
161 =cut
162
163 # ensure that the ncurses window is closed
164 # and wfm and its agents are closed (#39519)
165 END {
166     close_components (); # XS
167 }
168
169 =head2 Import
170
171  YaST::YCP::Import "Namespace";
172  Namespace->foo ("bar");
173
174 Imports a YaST namespace (in YCP or Perl or any supported language).
175 Equivalent to YCP C<import>, similar to Perl C<use>.
176
177 If C<Namespace> is in YCP, its constructor is executed later than if
178 it were imported from YCP. This can have subtle effects, for example
179 in testsuites. To get closer to the YCP import behavior, call
180 C<Import> from a C<BEGIN> block.
181
182 =cut
183
184 sub Import ($)
185 {
186     my $package = shift;
187     print "Importing $package\n" if debug;
188
189     no strict;
190     # let it get our autoload
191     *{"${package}::AUTOLOAD"} = \&YaST::YCP::Autoload::AUTOLOAD;
192 }
193
194 =head2 logging
195
196 These functions go via liby2util and thus use log.conf.
197 See also ycp::y2milestone.
198
199 The multiple arguments are simply joined by a space.
200
201  y2debug ($message, $message2, ...)
202  y2milestone ($message, $message2, ...)
203  y2warning ($message, $message2, ...)
204  y2error ($message, $message2, ...)
205  y2security ($message, $message2, ...)
206  y2internal ($message, $message2, ...)
207
208 =cut
209
210 sub y2_logger_helper ($@)
211 {
212     my $level = shift;
213     # look _two_ frames up for the subroutine
214     # when called from the main script, it will be undef
215     my ($package, $filename, $line, $subroutine) = caller (2);
216     # look _one_ frame up for file and line
217     # (is it because of optimization?)
218     ($package, $filename, $line) = caller (1);
219     # this is a XS:
220     y2_logger ($level, "Perl", $filename, $line, $subroutine || "",
221                join (" ", @_));
222 }
223
224 sub y2debug (@)         { y2_logger_helper (0, @_); }
225 sub y2milestone (@)     { y2_logger_helper (1, @_); }
226 sub y2warning (@)       { y2_logger_helper (2, @_); }
227 sub y2error (@)         { y2_logger_helper (3, @_); }
228 sub y2security (@)      { y2_logger_helper (4, @_); }
229 sub y2internal (@)      { y2_logger_helper (5, @_); }
230
231 =head2 sformat
232
233 Implements the sformat YCP builtin:
234
235 C<sformat ('%2 %% %1', "a", "b")> returns C<'b % a'>
236
237 It is useful mainly for messages marked for translation.
238
239 =cut
240
241 sub sformat ($@)
242 {
243     # don't shift
244     # now the % indices can be used for @_
245     my $format = $_[0];
246
247     # g: global, replace all occurences
248     # e: expression, not a string
249     $format =~ s{%([1-9%])}{
250         ($1 eq '%') ? '%' : $_[$1]
251     }ge;
252
253     return $format;
254 }
255
256 # shortcuts for the data types
257 # for POD see packages below
258
259 sub Boolean ($)
260 {
261     return new YaST::YCP::Boolean (@_);
262 }
263
264 sub Byteblock ($)
265 {
266     return new YaST::YCP::Byteblock (@_);
267 }
268
269 sub Integer ($)
270 {
271     return new YaST::YCP::Integer (@_);
272 }
273
274 sub Float ($)
275 {
276     return new YaST::YCP::Float (@_);
277 }
278
279 sub String ($)
280 {
281     return new YaST::YCP::String (@_);
282 }
283
284 sub Symbol ($)
285 {
286     return new YaST::YCP::Symbol (@_);
287 }
288
289 sub Term ($@)
290 {
291     return new YaST::YCP::Term (@_);
292 }
293
294 # by defining AUTOLOAD in a separate package, undefined functions in
295 # the main one will be detected
296 package YaST::YCP::Autoload;
297 use strict;
298 use warnings;
299 use diagnostics;
300
301 # cannot rely on UNIVERSAL::AUTOLOAD getting automatically called
302 # http://www.rocketaware.com/perl/perldelta/Deprecated_Inherited_C_AUTOLOAD.htm
303
304 # Gets called instead of all functions in Import'ed modules
305 # It assumes a normal function, not a class or instance method
306 sub AUTOLOAD
307 {
308     our $AUTOLOAD;
309
310     # strip $self on the way from Perl to YCP,
311     # just as it is added in the reverse direction
312     my $himself = shift;
313     print "$himself $AUTOLOAD (", join (", ", @_), ")\n" if YaST::YCP::debug;
314
315     my @components = split ("::", $AUTOLOAD);
316     my $func = pop (@components);
317     return YaST::YCP::call_ycp (join ("::", @components), $func, @_);
318 }
319
320 =head2 Boolean
321
322  $b = YaST::YCP::Boolean (1);
323  $b->value (0);
324  print $b->value, "\n";
325  SCR::Write (".foo", $b);
326
327 =cut
328
329 package YaST::YCP::Boolean;
330 use strict;
331 use warnings;
332 use diagnostics;
333
334 # a Boolean is just a blessed reference to a scalar
335
336 sub new
337 {
338     my $class = shift;
339     my $val = shift;
340     return bless \$val, $class
341 }
342
343 # get/set
344 sub value
345 {
346     # see "Constructors and Instance Methods" in perltoot
347     my $self = shift;
348     if (@_) { $$self = shift; }
349     return $$self;
350 }
351
352 =head2 Byteblock
353
354 A chunk of binary data.
355
356  use YaST::YCP qw(:DATA);
357
358  read ($dev_random_fh, $r, 100);
359  $b = Byteblock ($r);
360  $b->value ("Hello\0world\0");
361  print $b->value, "\n";
362  return $b;
363
364 =cut
365
366 package YaST::YCP::Byteblock;
367 use strict;
368 use warnings;
369 use diagnostics;
370
371 # a Byteblock is just a blessed reference to a scalar
372 # just like Boolean, so use it!
373
374 our @ISA = qw (YaST::YCP::Boolean);
375
376 =head2 Integer
377
378 An explicitly typed integer, useful to put in heterogenous data structures.
379
380  use YaST::YCP qw(:DATA);
381
382  $i = Integer ("42 and more");
383  $i->value ("43, actually");
384  print $i->value, "\n";
385  return [ $i ];
386
387 =cut
388
389 package YaST::YCP::Integer;
390 use strict;
391 use warnings;
392 use diagnostics;
393
394
395 # an Integer is just a blessed reference to a scalar
396 # just like Boolean, so use it!
397
398 our @ISA = qw (YaST::YCP::Boolean);
399
400 =head2 Float
401
402 An explicitly typed float, useful to put in heterogenous data structures.
403
404  use YaST::YCP qw(:DATA);
405
406  $f = Float ("3.41 is PI");
407  $f->value ("3.14 is PI");
408  print $f->value, "\n";
409  return [ $f ];
410
411 =cut
412
413 package YaST::YCP::Float;
414 use strict;
415 use warnings;
416 use diagnostics;
417
418
419 # a Float is just a blessed reference to a scalar
420 # just like Boolean, so use it!
421
422 our @ISA = qw (YaST::YCP::Boolean);
423
424 =head2 Path
425
426 Not implemented yet.
427
428 =cut
429
430 =head2 String
431
432 An explicitly typed string, useful to put in heterogenous data structures.
433
434  use YaST::YCP qw(:DATA);
435
436  $s = String (42);
437  $s->value (1 + 1);
438  print $s->value, "\n";
439  return [ $s ];
440
441 =cut
442
443 package YaST::YCP::String;
444 use strict;
445 use warnings;
446 use diagnostics;
447
448 # a String is just a blessed reference to a scalar
449 # just like Boolean, so use it!
450
451 our @ISA = qw (YaST::YCP::Boolean);
452
453 =head2 Symbol
454
455  use YaST::YCP qw(:DATA);
456
457  $s = Symbol ("next");
458  $s->value ("back");
459  print $s->value, "\n";
460  return Term ("id", $s);
461
462 =cut
463
464 package YaST::YCP::Symbol;
465 use strict;
466 use warnings;
467 use diagnostics;
468
469
470 # a Symbol is just a blessed reference to a scalar
471 # just like Boolean, so use it!
472
473 our @ISA = qw (YaST::YCP::Boolean);
474
475 =head2 Term
476
477  $t = new YaST::YCP::Term("CzechBox", "Accept spam", new YaST::YCP::Boolean(0));
478  $t->name ("CheckBox");
479  print $t->args->[0], "\n";
480  UIx::OpenDialog ($t);
481
482 =cut
483
484 package YaST::YCP::Term;
485 use strict;
486 use warnings;
487 use diagnostics;
488
489 # a Term has a name and arguments
490
491 sub new
492 {
493     my $class = shift;
494     my $name = shift;
495     my $args = [ @_ ];
496     return bless { name => $name, args => $args }, $class
497 }
498
499 # get/set
500 sub name
501 {
502     # see "Constructors and Instance Methods" in perltoot
503     my $self = shift;
504     if (@_) { $self->{name} = shift; }
505     return $self->{name};
506 }
507
508 # get/set
509 sub args
510 {
511     # see "Constructors and Instance Methods" in perltoot
512     my $self = shift;
513     if (@_) { @{ $self->{args} } = @_; }
514     # HACK:
515     # because I don't want to process multiple return values,
516     # I return it as a reference
517     return $self->{args};
518 }
519
520 1;