optgen 0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. data/bin/optgen +729 -0
  2. data/lib/liboptgen.rb +1 -0
  3. metadata +48 -0
@@ -0,0 +1,729 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # Copyright 2015-2016 Jyri J. Virkki <jyri@virkki.com>
5
+ #
6
+ # This file is part of optgen.
7
+ #
8
+ # optgen is free software: you can redistribute it and/or modify it
9
+ # under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # optgen is distributed in the hope that it will be useful, but
14
+ # WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ # General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with optgen. If not, see <http://www.gnu.org/licenses/>.
20
+ #
21
+
22
+ $VERSION = '0.3
23
+ '
24
+
25
+
26
+ #-----------------------------------------------------------------------------
27
+ # Represents one option as read from the config file.
28
+ #
29
+ class OneOption
30
+
31
+ # type of option (required, optional, hidden)
32
+ attr_reader :option_type
33
+
34
+ # the name of this option (normalized from longarg)
35
+ attr_reader :name
36
+
37
+ # single-character form of this option (may be nil, is not required)
38
+ attr_reader :shortarg
39
+
40
+ # long form of this option (required, always present)
41
+ attr_reader :longarg
42
+
43
+ # parameter list needed by this option
44
+ attr_reader :paramlist
45
+
46
+ # callback function to call when this option processed
47
+ attr_reader :callback
48
+
49
+ # human readable documentation as provided in config file
50
+ attr_reader :description
51
+
52
+
53
+ #---------------------------------------------------------------------------
54
+ # Parse option line from config to create self.
55
+ #
56
+ def initialize(line, vars)
57
+
58
+ # First perform variable expansion
59
+ if (line =~ /\$\$\$(\w+)\$\$\$/)
60
+ name = $1
61
+ value = vars[name]
62
+ if (!value)
63
+ puts "error: #{name} undefined"
64
+ exit(1)
65
+ end
66
+
67
+ line.sub!(/\$\$\$#{name}\$\$\$/, value)
68
+ end
69
+
70
+ line =~ /(.):(.*):(.*):(.*):(.*)/;
71
+
72
+ case $1
73
+ when "R"
74
+ @option_type = "required"
75
+ when "O"
76
+ @option_type = "optional"
77
+ when "H"
78
+ @option_type = "hidden"
79
+ else
80
+ puts "error: option type '#{$1}' unknown"
81
+ exit(1)
82
+ end
83
+
84
+ arglist = $2
85
+ params = $3
86
+ @callback = $4
87
+ @description = $5
88
+
89
+ (@shortarg, @longarg) = arglist.split(',') if (arglist)
90
+ @shortarg = nil if (@shortarg == "")
91
+
92
+ if (@longarg == nil || @longarg == "")
93
+ puts "error: long arg name always required"
94
+ exit(1)
95
+ end
96
+
97
+ @paramlist = nil
98
+ @paramlist = params.split(',') if (params.length > 0)
99
+ @name = @longarg.gsub(/-/, '_')
100
+ end
101
+
102
+ def display_len
103
+ len = 2 + @longarg.length
104
+ len = len + 2 + @shortarg.length if (@shortarg != nil)
105
+ if (@paramlist)
106
+ @paramlist.each { |value|
107
+ len = len + value.length + 1
108
+ }
109
+ end
110
+ len
111
+ end
112
+
113
+ def to_s
114
+ line = @name
115
+ if (@shortarg != nil)
116
+ line = line + " (-#{@shortarg},--#{@longarg})"
117
+ else
118
+ line = line + " (--#{@longarg})"
119
+ end
120
+ if (@paramlist != nil)
121
+ @paramlist.each { |name|
122
+ line = line + " #{name}"
123
+ }
124
+ end
125
+ line = line + " : #{@description}"
126
+ end
127
+
128
+ end
129
+
130
+
131
+ #-----------------------------------------------------------------------------
132
+ # Represents one command.
133
+ #
134
+ class Command
135
+
136
+ # name of the command as given in the config file
137
+ attr_reader :name
138
+
139
+ # human readable description as given in the config file
140
+ attr_reader :description
141
+
142
+ # array of OneOption objects for each option allowed by this command
143
+ attr_reader :options
144
+
145
+ # string length of longest option this command supports
146
+ attr_reader :longest_option
147
+
148
+ #---------------------------------------------------------------------------
149
+ # Parse command line from config to create self.
150
+ #
151
+ def initialize(line, vars)
152
+ line =~ /\[([^\]]+)\](.*)/
153
+ @name = $1.strip
154
+ @description = $2.strip if ($2)
155
+ @options = Array.new()
156
+ @longest_option = 0
157
+ end
158
+
159
+ #---------------------------------------------------------------------------
160
+ # Add the given option (OneOption obj) to my set of allowed options
161
+ def addopt(option)
162
+ @options.push(option)
163
+ if (option.display_len() > @longest_option)
164
+ @longest_option = option.display_len()
165
+ end
166
+ end
167
+
168
+ end
169
+
170
+
171
+ #-----------------------------------------------------------------------------
172
+ # Represents the full optgen configuration for a given config file.
173
+ #
174
+ class OptGen
175
+
176
+ #---------------------------------------------------------------------------
177
+ # Parse an optgen config file.
178
+ #
179
+ def initialize(optgenfile)
180
+
181
+ @configfile = optgenfile
182
+ @commands = Array.new()
183
+ @options = Hash.new()
184
+ @options_array = Array.new()
185
+ @include = Array.new()
186
+ @longest_command = 0
187
+ @allargs = Hash.new()
188
+
189
+ command = nil
190
+ vars = Hash.new()
191
+ saw_global = false
192
+
193
+ fin = File.open(optgenfile)
194
+ fin.each_line { |line|
195
+ line.chomp!
196
+ line.strip!
197
+ next if (line == "")
198
+ # depending on the ruby version, char from string may return a char or an int... sigh...
199
+ next if (line[0] == '#' || line[0] == 35)
200
+
201
+ if (line[0] == '[' || line[0] == 91)
202
+ if (saw_global)
203
+ puts "error: GLOBAL section must be last"
204
+ exit(1)
205
+ end
206
+ command = Command.new(line, vars)
207
+ @commands.push(command)
208
+ if (command.name.length > @longest_command)
209
+ @longest_command = command.name.length
210
+ end
211
+ if (command.name == "GLOBAL")
212
+ saw_global = true
213
+ end
214
+
215
+ elsif (line =~ /(\w+)=(.+)/)
216
+ name = $1
217
+ value = $2
218
+ vars[name] = value
219
+
220
+ elsif (line[0] == "." || line[0] == 46)
221
+ directive(line)
222
+
223
+ else
224
+ o = OneOption.new(line, vars)
225
+ command.addopt(o)
226
+ if (@options[o.name] == nil)
227
+ @options[o.name] = o
228
+ @options_array.push(o.name)
229
+ end
230
+
231
+ if (o.shortarg != nil)
232
+ prev = @allargs[o.shortarg]
233
+ if (prev != nil && prev.longarg != o.longarg)
234
+ puts "error: mismatch: [#{o}] : [#{prev}]"
235
+ exit(1)
236
+ end
237
+ @allargs[o.shortarg] = o
238
+ end
239
+
240
+ prev = @allargs[o.longarg]
241
+ if (prev != nil && prev.shortarg != o.shortarg)
242
+ puts "error: mismatch: [#{o}] : [#{prev}]"
243
+ exit(1)
244
+ end
245
+ @allargs[o.longarg] = o
246
+ end
247
+ }
248
+ end
249
+
250
+ #---------------------------------------------------------------------------
251
+ # Handle per-config directives (lines starting with a dot in config file)
252
+ #
253
+ def directive(line)
254
+
255
+ @require_command = true if (line == ".require_command")
256
+ @strict_options = true if (line == ".strict_options")
257
+
258
+ if (line =~ /\.include (.*)/)
259
+ @include.push($1)
260
+ end
261
+
262
+ end
263
+
264
+ #---------------------------------------------------------------------------
265
+ # Create optgen handling functions for C code.
266
+ #
267
+ def gen_C
268
+
269
+ header = <<-ENDHEADER
270
+
271
+ /*
272
+ * DO NOT EDIT THIS FILE BY HAND!
273
+ *
274
+ * All changes will be lost when file gets regenerated.
275
+ *
276
+ * Generated by optgen #{$VERSION} from config file "#{@configfile}"
277
+ *
278
+ * Copyright (c) #{Time.now.year}, Jyri J. Virkki
279
+ * All rights reserved.
280
+ *
281
+ * Redistribution and use in source and binary forms, with or without
282
+ * modification, are permitted provided that the following conditions are
283
+ * met:
284
+ *
285
+ * 1. Redistributions of source code must retain the above copyright
286
+ * notice, this list of conditions and the following disclaimer.
287
+ *
288
+ * 2. Redistributions in binary form must reproduce the above copyright
289
+ * notice, this list of conditions and the following disclaimer in the
290
+ * documentation and/or other materials provided with the distribution.
291
+ *
292
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
293
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
294
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
295
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
296
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
297
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
298
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
299
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
300
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
301
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
302
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
303
+ *
304
+ */
305
+
306
+ ENDHEADER
307
+
308
+ #----- Generate header file optgen.h -----
309
+
310
+ o = File.open("optgen.h", 'w')
311
+
312
+ o.puts(header)
313
+ o.puts "#ifndef OPTGEN_H"
314
+ o.puts "#define OPTGEN_H"
315
+ o.puts
316
+ o.puts "#include <stdlib.h>"
317
+ o.puts
318
+
319
+ # Define constants OPT_* for each known option
320
+ n = 0
321
+ o.puts "#define COUNT_OPTIONS #{@options.size}"
322
+ @options_array.each { |i|
323
+ op = @options[i]
324
+ o.puts
325
+ sa = "-#{op.shortarg} " if (op.shortarg)
326
+ o.puts "// #{op.to_s}"
327
+ o.puts "#define OPT_#{op.name} #{n}"
328
+ n = n + 1
329
+ }
330
+
331
+ # Define constants COMMAND_* for each known command
332
+ n = 1
333
+ global = nil
334
+ @commands.each { |command|
335
+ if (command.name == "GLOBAL")
336
+ global = command
337
+ end
338
+
339
+ o.puts
340
+ o.puts "// #{command.name}: #{command.description}"
341
+ o.puts "#define COMMAND_#{command.name} #{n}"
342
+ n = n + 1
343
+ }
344
+
345
+ # Function prototypes
346
+ o.puts
347
+ o.puts '/**'
348
+ o.puts ' * Function to parse the arguments.'
349
+ o.puts ' *'
350
+ o.puts ' * Parameters:'
351
+ o.puts ' * argc - argv size (as passed to main)'
352
+ o.puts ' * argv - Arguments (as passed to main)'
353
+ o.puts ' * command - Command (if present) will be stored here'
354
+ o.puts ' * options - Caller-allocated array where option values will be stored'
355
+ o.puts ' *'
356
+ o.puts ' * Return:'
357
+ o.puts ' * OPTGEN_OK on success'
358
+ o.puts ' * OPTGEN_NONE if no arguments seen'
359
+ o.puts ' * command will be set to OPTGEN_NO_COMMAND if no command given, or'
360
+ o.puts ' * one of the COMMAND_* constants above.'
361
+ o.puts ' * options array has an entry for each OPT_* index for each known option.'
362
+ o.puts ' * The value of each OPT_* entry is one of:'
363
+ o.puts ' * NULL if the option was not seen'
364
+ o.puts ' * string value if the option had a value'
365
+ o.puts ' * for options with no value, a string value of an integer'
366
+ o.puts ' *'
367
+ o.puts ' * Sample call:'
368
+ o.puts ' *'
369
+ o.puts ' * char * options[COUNT_OPTIONS];'
370
+ o.puts ' * int command;'
371
+ o.puts ' *'
372
+ o.puts ' * int rv = optgen_parse(argc, argv, &command, options);'
373
+ o.puts ' *'
374
+ o.puts ' */'
375
+ o.puts 'int optgen_parse(int argc, char * argv[], int * command, char * options[]);'
376
+ o.puts '#define OPTGEN_OK 0'
377
+ o.puts '#define OPTGEN_NONE 1'
378
+ o.puts '#define OPTGEN_NO_COMMAND -1'
379
+ o.puts
380
+
381
+ o.puts '/**'
382
+ o.puts ' * Convenience function to get count of times an option was specified.'
383
+ o.puts ' * For options which take NO arguments but can be repeated multiple times,'
384
+ o.puts ' * this function returns the number of times it was seen'
385
+ o.puts ' *'
386
+ o.puts ' * Parameters:'
387
+ o.puts ' * str - A value from options array'
388
+ o.puts ' *'
389
+ o.puts ' * Return:'
390
+ o.puts ' *'
391
+ o.puts ' * Number of times an option was seen, or zero if none'
392
+ o.puts ' *'
393
+ o.puts ' */'
394
+ o.puts 'int opt_count(char * str);'
395
+ o.puts
396
+
397
+ o.puts '/**'
398
+ o.puts ' * Convenience function to return integer value of an option'
399
+ o.puts ' *'
400
+ o.puts ' * Parameters:'
401
+ o.puts ' * str - A value from options array'
402
+ o.puts ' * def - Default value if none given'
403
+ o.puts ' *'
404
+ o.puts ' * Return:'
405
+ o.puts ' *'
406
+ o.puts ' * Value of option as integer. If NULL, returns default def.'
407
+ o.puts ' *'
408
+ o.puts ' */'
409
+ o.puts 'int opt_int(char * str, int def);'
410
+ o.puts
411
+
412
+ o.puts '/**'
413
+ o.puts ' * Convenience function to single char value of an option'
414
+ o.puts ' *'
415
+ o.puts ' * Parameters:'
416
+ o.puts ' * str - A value from options array'
417
+ o.puts ' * def - Default value if none given'
418
+ o.puts ' *'
419
+ o.puts ' * Return:'
420
+ o.puts ' *'
421
+ o.puts ' * Value of option as char. If NULL, returns default def.'
422
+ o.puts ' *'
423
+ o.puts ' */'
424
+ o.puts 'char opt_char(char * str, char def);'
425
+ o.puts
426
+
427
+ o.puts '/**'
428
+ o.puts ' * Show help based on command and option descriptions.'
429
+ o.puts ' *'
430
+ o.puts ' */'
431
+ o.puts 'void opt_show_help();'
432
+ o.puts
433
+
434
+ o.puts '// Callbacks need to return one of these values'
435
+ o.puts '#define OPTGEN_CALLBACK_OK 0'
436
+ o.puts '#define OPTGEN_CALLBACK_FAIL 1'
437
+ o.puts
438
+
439
+ o.puts "#endif"
440
+ o.close()
441
+
442
+ #----- Generate code file optgen.c -----
443
+
444
+ o = File.open("optgen.c", 'w')
445
+
446
+ o.puts header
447
+ o.puts '#include <stdlib.h>'
448
+ o.puts '#include <stdio.h>'
449
+ o.puts '#include <string.h>'
450
+ o.puts '#include <sys/ioctl.h>'
451
+ o.puts '#include <stdio.h>'
452
+ o.puts '#include <unistd.h>'
453
+ o.puts '#include "optgen.h"'
454
+ @include.each { |inc|
455
+ o.puts "#include \"#{inc}\""
456
+ }
457
+
458
+ o.puts
459
+ o.puts '// LCOV_EXCL_START'
460
+ o.puts
461
+ o.puts 'char * numstring[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };'
462
+ o.puts
463
+
464
+ # Define the options allowed by each command
465
+ o.puts '// For each option, list the commands which accept it'
466
+ @options_array.each { |optname|
467
+
468
+ o.print "int option_#{optname}[] = {"
469
+ c = 1
470
+ comma = ""
471
+
472
+ @commands.each { |command|
473
+ command.options.each { |allowed|
474
+ if (optname == allowed.name)
475
+ o.print "#{comma} #{c}"
476
+ comma = ","
477
+ end
478
+ }
479
+ c = c + 1
480
+ }
481
+ o.puts " };"
482
+ }
483
+ o.puts
484
+
485
+ o.puts 'int optgen_parse(int argc, char * argv[], int * command, char * options[])'
486
+ o.puts '{'
487
+ o.puts ' int i;'
488
+ o.puts ' int pos;'
489
+ o.puts
490
+ o.puts ' *command = OPTGEN_NO_COMMAND;'
491
+ o.puts
492
+ o.puts ' for (i = 0; i < COUNT_OPTIONS; i++) {'
493
+ o.puts ' options[i] = NULL;'
494
+ o.puts ' }'
495
+ o.puts
496
+ o.puts ' if (argc < 2) {'
497
+ o.puts ' return OPTGEN_NONE;'
498
+ o.puts ' }'
499
+ o.puts
500
+ o.puts ' // Check if the first argument is a recognized command'
501
+ o.puts ' int l = strlen(argv[1]);'
502
+ o.puts
503
+
504
+ # Go through commands to see if user gave a known one
505
+ command_num = 1
506
+ @commands.each { |command|
507
+ next if command.name == "GLOBAL"
508
+ len = command.name.length
509
+ o.puts " if (l == #{len} && !strncmp(\"#{command.name}\", argv[1], #{len})) {"
510
+ o.puts " *command = #{command_num};"
511
+ o.puts ' goto OPTS;'
512
+ o.puts ' }'
513
+ command_num = command_num + 1
514
+ }
515
+
516
+ if (@require_command)
517
+ o.puts
518
+ o.puts ' // A command is required but none found'
519
+ o.puts ' if (*command == OPTGEN_NO_COMMAND) {'
520
+ o.puts ' printf("error: Command required but none given\n");'
521
+ o.puts ' exit(1);'
522
+ o.puts ' }'
523
+ end
524
+
525
+ # Go through all remaining options
526
+ o.puts
527
+ o.puts ' OPTS:'
528
+ o.puts
529
+ o.puts ' pos = *command == OPTGEN_NO_COMMAND ? 1 : 2;'
530
+ o.puts
531
+ o.puts ' while (pos < argc) {'
532
+ o.puts ' l = strlen(argv[pos]);'
533
+ o.puts
534
+
535
+ n = 0
536
+ @options_array.each { |i|
537
+ op = @options[i]
538
+ sa = nil
539
+ sa = "-#{op.shortarg}" if (op.shortarg)
540
+ sal = sa.length if sa
541
+ la = "--#{op.longarg}"
542
+ lal = la.length
543
+
544
+ o.print " if ((l == #{lal} && !strncmp(\"#{la}\", argv[pos], #{lal}))"
545
+ if (sa == nil)
546
+ o.puts ') {'
547
+ else
548
+ o.puts '||'
549
+ o.puts " (l == #{sal} && !strncmp(\"#{sa}\", argv[pos], #{sal}))) {"
550
+ end
551
+
552
+ if (op.paramlist != nil)
553
+ o.puts ' if (argv[pos+1] == NULL) {'
554
+ o.puts " printf(\"error: no value for arg #{la}\\n\");"
555
+ o.puts ' exit(1);'
556
+ o.puts ' }'
557
+
558
+ if (op.paramlist[0] == 'ABSPATH')
559
+ o.puts ' // ABSPATH: Must start with /'
560
+ o.puts " if (argv[pos+1][0] != '/') {"
561
+ o.puts " printf(\"error: #{la} must be an absolute path\\n\");"
562
+ o.puts ' exit(1);'
563
+ o.puts ' }'
564
+ elsif (op.paramlist[0] == 'CHAR')
565
+ o.puts ' // CHAR: Must be a single character'
566
+ o.puts " if (strlen(argv[pos+1]) != 1) {"
567
+ o.puts " printf(\"error: #{la} must be a single character\\n\");"
568
+ o.puts ' exit(1);'
569
+ o.puts ' }'
570
+ end
571
+
572
+ o.puts " options[#{n}] = argv[pos+1];"
573
+ o.puts ' pos += 2;'
574
+ else
575
+ o.puts " if (options[#{n}] == NULL) {"
576
+ o.puts " options[#{n}] = numstring[0];"
577
+ o.puts ' } else {'
578
+ o.puts " options[#{n}] = numstring[atoi(options[#{n}])];"
579
+ o.puts ' }'
580
+ o.puts ' pos++;'
581
+ end
582
+
583
+ if (@strict_options)
584
+ o.puts " // strict_options: is #{@options_array[n]} allowed?"
585
+ name = @options_array[n]
586
+
587
+ o.puts ' int ok = 0;'
588
+ o.puts ' unsigned int cc;'
589
+ o.puts " unsigned int len = sizeof(option_#{name}) / sizeof(option_#{name})[0];"
590
+ o.puts ' for (cc = 0; cc < len; cc++) {'
591
+ o.puts " if (option_#{name}[cc] == *command) { ok = 1; }"
592
+ o.puts " if (option_#{name}[cc] == COMMAND_GLOBAL) { ok = 1; }"
593
+ o.puts ' }'
594
+
595
+ o.puts ' if (!ok) {'
596
+ o.puts " printf(\"error: option '#{name}' not compatible with given command\\n\");"
597
+ o.puts ' exit(1);'
598
+ o.puts ' }'
599
+ end
600
+
601
+ if (op.callback != nil && op.callback != "")
602
+ o.puts ' // callback configured for this option'
603
+ o.puts " int rv = #{op.callback}(options[#{n}], *command);"
604
+ o.puts ' if (rv != OPTGEN_CALLBACK_OK) {'
605
+ o.puts " printf(\"error: problem handling option '#{name}'\\n\");"
606
+ o.puts ' exit(1);'
607
+ o.puts ' }'
608
+ o.puts
609
+ end
610
+
611
+ o.puts ' continue;'
612
+ o.puts ' }'
613
+
614
+ n = n + 1
615
+ }
616
+
617
+ o.puts
618
+ o.puts ' printf("error: unknown argument: [%s]\n", argv[pos]);'
619
+ o.puts ' exit(1);'
620
+ o.puts ' }'
621
+ o.puts
622
+
623
+ o.puts ' return OPTGEN_OK;'
624
+ o.puts '}'
625
+ o.puts
626
+
627
+ o.puts 'int opt_count(char * str)'
628
+ o.puts '{'
629
+ o.puts ' if (str == NULL) {'
630
+ o.puts ' return 0;'
631
+ o.puts ' } else {'
632
+ o.puts ' return atoi(str);'
633
+ o.puts ' }'
634
+ o.puts '}'
635
+ o.puts
636
+
637
+ o.puts 'int opt_int(char * str, int def)'
638
+ o.puts '{'
639
+ o.puts ' if (str == NULL) {'
640
+ o.puts ' return def;'
641
+ o.puts ' } else {'
642
+ o.puts ' return atoi(str);'
643
+ o.puts ' }'
644
+ o.puts '}'
645
+ o.puts
646
+
647
+ o.puts 'char opt_char(char * str, char def)'
648
+ o.puts '{'
649
+ o.puts ' if (str == NULL) {'
650
+ o.puts ' return def;'
651
+ o.puts ' } else {'
652
+ o.puts ' return str[0];'
653
+ o.puts ' }'
654
+ o.puts '}'
655
+ o.puts
656
+
657
+ o.puts 'void opt_show_help()'
658
+ o.puts '{'
659
+
660
+ @commands.each { |command|
661
+ next if (command.name == "GLOBAL")
662
+
663
+ line = command.name
664
+ line = line + " " * (2 + @longest_command - command.name.length)
665
+ line = line + command.description
666
+ o.puts " printf(\"#{line}\\n\");"
667
+
668
+ command.options.each { |opt|
669
+ if (opt.option_type != "hidden")
670
+ line = optline(opt, command.longest_option)
671
+ o.puts " printf(\"#{line}\\n\");"
672
+ end
673
+ }
674
+ o.puts ' printf("\n");'
675
+ }
676
+
677
+ if (global != nil)
678
+ o.puts ' printf("General options:\n");'
679
+ global.options.each { |opt|
680
+ if (opt.option_type != "hidden")
681
+ line = optline(opt, global.longest_option)
682
+ o.puts " printf(\"#{line}\\n\");"
683
+ end
684
+ }
685
+ end
686
+ o.puts ' printf("\n");'
687
+ o.puts '}'
688
+ o.puts '// LCOV_EXCL_STOP'
689
+
690
+ o.close()
691
+ end
692
+
693
+ #---------------------------------------------------------------------------
694
+ # Generate doc line for one option
695
+ #
696
+ def optline(opt, longest)
697
+ line = " "
698
+ if (opt.shortarg != nil && opt.shortarg != "")
699
+ line = line + "-#{opt.shortarg} "
700
+ else
701
+ line = line + " "
702
+ end
703
+ line = line + "--#{opt.longarg} "
704
+ if (opt.paramlist != nil)
705
+ opt.paramlist.each { |value|
706
+ line = line + "#{value} "
707
+ }
708
+ end
709
+ line = line + " " * (7 + longest - line.length)
710
+ line = line + opt.description
711
+
712
+ line
713
+ end
714
+
715
+ end
716
+
717
+
718
+ #-----------------------------------------------------------------------------
719
+ # main
720
+ #
721
+ genfile = ARGV.shift
722
+ if (!genfile)
723
+ puts "error: no optgen file!"
724
+ exit(1)
725
+ end
726
+
727
+ optgen = OptGen.new(genfile)
728
+
729
+ optgen.gen_C()
@@ -0,0 +1 @@
1
+ # This is just here to quiet warnings.
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: optgen
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.3'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jyri J. Virkki
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-02-13 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Generate C code to parse command line options
15
+ email: jyri@virkki.com
16
+ executables:
17
+ - optgen
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/liboptgen.rb
22
+ - bin/optgen
23
+ homepage: https://github.com/jvirkki/optgen
24
+ licenses:
25
+ - GPLv3
26
+ post_install_message:
27
+ rdoc_options: []
28
+ require_paths:
29
+ - lib
30
+ required_ruby_version: !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubyforge_project: nowarning
44
+ rubygems_version: 1.8.23
45
+ signing_key:
46
+ specification_version: 3
47
+ summary: Generate code to parse command line options
48
+ test_files: []