passenger 5.0.28 → 5.0.29

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +5 -0
  3. data/CHANGELOG +13 -0
  4. data/build/apache2.rb +3 -3
  5. data/build/common_library.rb +3 -3
  6. data/build/nginx.rb +4 -4
  7. data/build/packaging.rb +9 -8
  8. data/build/support/cxx_dependency_map.rb +9 -7
  9. data/build/support/general.rb +39 -0
  10. data/build/support/vendor/cxxcodebuilder/CxxCodeBuilder.sublime-project +8 -0
  11. data/build/support/vendor/cxxcodebuilder/Gemfile +4 -0
  12. data/build/support/vendor/cxxcodebuilder/Gemfile.lock +28 -0
  13. data/build/support/vendor/cxxcodebuilder/LICENSE.md +19 -0
  14. data/build/support/vendor/cxxcodebuilder/README.md +98 -0
  15. data/build/support/vendor/cxxcodebuilder/Rakefile +4 -0
  16. data/build/support/vendor/cxxcodebuilder/lib/cxxcodebuilder.rb +23 -0
  17. data/build/support/vendor/cxxcodebuilder/lib/cxxcodebuilder/builder.rb +574 -0
  18. data/build/support/vendor/cxxcodebuilder/lib/cxxcodebuilder/initializer_builder.rb +166 -0
  19. data/build/test_basics.rb +2 -1
  20. data/resources/templates/standalone/server.erb +6 -4
  21. data/src/agent/Core/Controller/ForwardResponse.cpp +5 -5
  22. data/src/agent/Watchdog/WatchdogMain.cpp +0 -10
  23. data/src/apache2_module/ConfigurationCommands.cpp +181 -248
  24. data/src/apache2_module/ConfigurationCommands.cpp.cxxcodebuilder +127 -0
  25. data/src/apache2_module/ConfigurationFields.hpp +135 -51
  26. data/src/apache2_module/ConfigurationFields.hpp.cxxcodebuilder +113 -0
  27. data/src/apache2_module/ConfigurationSetters.cpp +414 -459
  28. data/src/apache2_module/ConfigurationSetters.cpp.cxxcodebuilder +144 -0
  29. data/src/apache2_module/CreateDirConfig.cpp +49 -52
  30. data/src/apache2_module/CreateDirConfig.cpp.cxxcodebuilder +81 -0
  31. data/src/apache2_module/Hooks.cpp +0 -14
  32. data/src/apache2_module/MergeDirConfig.cpp +136 -226
  33. data/src/apache2_module/MergeDirConfig.cpp.cxxcodebuilder +97 -0
  34. data/src/apache2_module/SetHeaders.cpp +92 -143
  35. data/src/apache2_module/SetHeaders.cpp.cxxcodebuilder +106 -0
  36. data/src/cxx_supportlib/Constants.h +86 -146
  37. data/src/cxx_supportlib/Constants.h.cxxcodebuilder +43 -0
  38. data/src/cxx_supportlib/DataStructures/LString.h +40 -23
  39. data/src/cxx_supportlib/MemoryKit/mbuf.cpp +60 -25
  40. data/src/cxx_supportlib/MemoryKit/mbuf.h +50 -25
  41. data/src/cxx_supportlib/ServerKit/CookieUtils.h +36 -3
  42. data/src/cxx_supportlib/ServerKit/HeaderTable.h +2 -8
  43. data/src/cxx_supportlib/ServerKit/HttpServer.h +6 -15
  44. data/src/cxx_supportlib/WatchdogLauncher.cpp +4 -4
  45. data/src/cxx_supportlib/WatchdogLauncher.h +2 -3
  46. data/src/nginx_module/CacheLocationConfig.c +623 -780
  47. data/src/nginx_module/CacheLocationConfig.c.cxxcodebuilder +214 -0
  48. data/src/nginx_module/Configuration.h +1 -1
  49. data/src/nginx_module/ConfigurationCommands.c +404 -535
  50. data/src/nginx_module/ConfigurationCommands.c.cxxcodebuilder +157 -0
  51. data/src/nginx_module/CreateLocationConfig.c +82 -206
  52. data/src/nginx_module/CreateLocationConfig.c.cxxcodebuilder +98 -0
  53. data/src/nginx_module/LocationConfig.h +97 -0
  54. data/src/nginx_module/LocationConfig.h.cxxcodebuilder +131 -0
  55. data/src/nginx_module/MergeLocationConfig.c +157 -278
  56. data/src/nginx_module/MergeLocationConfig.c.cxxcodebuilder +144 -0
  57. data/src/nginx_module/ngx_http_passenger_module.c +4 -10
  58. data/src/ruby_supportlib/phusion_passenger.rb +4 -4
  59. data/src/ruby_supportlib/phusion_passenger/config/validate_install_command.rb +2 -2
  60. data/src/ruby_supportlib/phusion_passenger/packaging.rb +2 -0
  61. data/src/ruby_supportlib/phusion_passenger/platform_info/compiler.rb +6 -0
  62. data/src/ruby_supportlib/phusion_passenger/platform_info/cxx_portability.rb +1 -1
  63. data/src/ruby_supportlib/phusion_passenger/standalone/start_command.rb +27 -8
  64. data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller.rb +120 -2
  65. data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller/lock_file.rb +1 -1
  66. data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller/spawn.rb +4 -4
  67. data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller/version.rb +1 -1
  68. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/api.rb +5 -5
  69. metadata +24 -15
  70. data/src/apache2_module/ConfigurationCommands.cpp.erb +0 -109
  71. data/src/apache2_module/ConfigurationFields.hpp.erb +0 -98
  72. data/src/apache2_module/ConfigurationSetters.cpp.erb +0 -128
  73. data/src/apache2_module/CreateDirConfig.cpp.erb +0 -72
  74. data/src/apache2_module/MergeDirConfig.cpp.erb +0 -82
  75. data/src/apache2_module/SetHeaders.cpp.erb +0 -91
  76. data/src/cxx_supportlib/Constants.h.erb +0 -41
  77. data/src/nginx_module/CacheLocationConfig.c.erb +0 -171
  78. data/src/nginx_module/ConfigurationCommands.c.erb +0 -144
  79. data/src/nginx_module/ConfigurationFields.h +0 -145
  80. data/src/nginx_module/ConfigurationFields.h.erb +0 -112
  81. data/src/nginx_module/CreateLocationConfig.c.erb +0 -78
  82. data/src/nginx_module/MergeLocationConfig.c.erb +0 -118
@@ -0,0 +1,23 @@
1
+ # Copyright (c) 2016 Phusion Holding B.V.
2
+ #
3
+ # "Union Station" and "Passenger" are trademarks of Phusion Holding B.V.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require File.expand_path(File.dirname(__FILE__) + '/cxxcodebuilder/builder')
@@ -0,0 +1,574 @@
1
+ # encoding: utf-8
2
+
3
+ # Copyright (c) 2016 Phusion Holding B.V.
4
+ #
5
+ # "Union Station" and "Passenger" are trademarks of Phusion Holding B.V.
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+
25
+ require File.expand_path(File.dirname(__FILE__) + '/initializer_builder')
26
+
27
+ module CxxCodeBuilder
28
+ # Builds C/C++ code. Use it as follows:
29
+ #
30
+ # 1. Create a CxxCodeBuilder::Builder object.
31
+ # 2. Call API methods in the Builder object to generate C/C++ code.
32
+ # 3. When done, call `#to_s` to obtain the generated code.
33
+ #
34
+ # There are two ways to use CxxCodeBuilder::Builder:
35
+ #
36
+ # 1. By passing a block to the constructor. The block is evaluated in
37
+ # the context of the builder object, so inside the block you have
38
+ # access to all the API methods of the Builder class. See README.md
39
+ # for an example of this usage.
40
+ # 2. By calling the API methods of the Builder class, without passing
41
+ # a block to the constructor.
42
+ #
43
+ # ## Internal buffer
44
+ #
45
+ # Builder has an internal buffer containing the code generated so far.
46
+ # Most API methods, such as `#function` and `#field`, generate new code
47
+ # and append to this internal buffer. `#to_s` returns the contents of
48
+ # the buffer.
49
+ #
50
+ # ## Indentation
51
+ #
52
+ # Builder keeps track of the current indentation level and generates
53
+ # code accordingly. You can temporarily increase it with the `indent`
54
+ # method. Builder generates tabs for indentation.
55
+ class Builder
56
+ def initialize(&block)
57
+ @indent_string = "\t"
58
+ @indent_level = 0
59
+ @code = ""
60
+
61
+ if block
62
+ instance_eval(&block)
63
+ end
64
+ end
65
+
66
+ # Customizes the indentation string. The default is a tab,
67
+ # but you can use this to set it to e.g. 4 spaces. You should
68
+ # call this method as early as possible because it won't
69
+ # affect the indentation of already generated code.
70
+ def set_indent_string(str)
71
+ @indent_string = str
72
+ end
73
+
74
+ # Adds some code to the internal buffer. Before adding to the internal
75
+ # buffer, extraneous indentation and leading and trailing empty lines in
76
+ # `code` are removed, and new indentation is added based on the current
77
+ # indentation level. The code is suffixed with a newline.
78
+ #
79
+ #
80
+ # Example 1:
81
+ #
82
+ # add_code 'foo();'
83
+ #
84
+ # Output 1:
85
+ #
86
+ # foo();
87
+ #
88
+ #
89
+ # Example 2:
90
+ #
91
+ # # The argument contains extraneous leading and trailing empty lines,
92
+ # # as well as extraneous indenting.
93
+ # add_code %q{
94
+ # foo();
95
+ # if (true) {
96
+ # bar();
97
+ # }
98
+ # }
99
+ #
100
+ # Output 2 (extraneous leading/trailing newlines and extraneous indenting removed):
101
+ #
102
+ # foo();
103
+ # if (true) {
104
+ # bar();
105
+ # }
106
+ def add_code(code)
107
+ add_code_without_newline(code)
108
+ newline
109
+ end
110
+
111
+ # Like `#add_code`, but does not suffix the generated code with a newline.
112
+ def add_code_without_newline(code)
113
+ @code << reindent(unindent(code.to_s), @indent_string * @indent_level, true)
114
+ end
115
+
116
+ # Adds some raw code to the internal buffer. Unlike `#add_code`, no
117
+ # preprocessing is performed to remove extraneous newlines or indenting.
118
+ def add_raw_code(code)
119
+ @code << code
120
+ end
121
+
122
+ # Temporarily increase the indentation level by 1. This new indentation
123
+ # level is only active inside the given block.
124
+ #
125
+ # Example:
126
+ #
127
+ # add_code 'foo();'
128
+ #
129
+ # indent do
130
+ # add_code 'bar();'
131
+ # end
132
+ #
133
+ # Output:
134
+ #
135
+ # foo();
136
+ # bar();
137
+ def indent
138
+ @indent_level += 1
139
+ begin
140
+ yield
141
+ ensure
142
+ @indent_level -= 1
143
+ end
144
+ end
145
+
146
+ # Adds a newline to the internal buffer.
147
+ def separator
148
+ @code << "\n"
149
+ end
150
+
151
+ alias newline separator
152
+
153
+ # Adds an `#include` statement to the internal buffer.
154
+ # `header_name` is verbatim added to the statement, so you
155
+ # need to pass either `"<header_name.h>"` or `'"header_name.h"'`
156
+ # as argument.
157
+ #
158
+ # Example:
159
+ #
160
+ # include '<stdio.h>'
161
+ # include '"Config.h"'
162
+ #
163
+ # Output:
164
+ #
165
+ # #include <stdio.h>
166
+ # #include "Config.h"
167
+ def include(header_name)
168
+ add_code("#include #{header_name}")
169
+ end
170
+
171
+ # Adds a `#define` statement to the internal buffer.
172
+ # `macro` is verbatim added to the statement. If you want
173
+ # to #define a string constant then you should use the
174
+ # `#define_string` method.
175
+ #
176
+ # Example:
177
+ #
178
+ # define 'HAVE_STDINT_H'
179
+ # define 'FOO bar'
180
+ # define 'TWO 1 + 2'
181
+ #
182
+ # Output:
183
+ #
184
+ # #define HAVE_STDINT_H
185
+ # #define FOO bar
186
+ # #define TWO 1 + 2
187
+ def define(macro)
188
+ add_code("#define #{macro}")
189
+ end
190
+
191
+ # Adds a `#define` statement to the internal buffer for defining
192
+ # a string macro.
193
+ #
194
+ # Example:
195
+ #
196
+ # define 'NAME', 'Joe Dalton'
197
+ #
198
+ # Output:
199
+ #
200
+ # #define NAME "Joe Dalton"
201
+ def define_string(name, value)
202
+ define("#{name} #{str_val(value)}")
203
+ end
204
+
205
+ # Adds header guard macros to the internal buffer. Expects
206
+ # a block which generates the code to insert inside the guard.
207
+ #
208
+ # Example:
209
+ #
210
+ # guard_macros 'MY_HEADER_H' do
211
+ # field 'int foo'
212
+ # end
213
+ #
214
+ # Output:
215
+ #
216
+ # #ifndef MY_HEADER_H
217
+ # #define MY_HEADER_H
218
+ #
219
+ # int foo;
220
+ #
221
+ # #endif /* MY_HEADER_H */
222
+ def guard_macros(name)
223
+ add_code("#ifndef #{name}")
224
+ define(name)
225
+ separator
226
+ yield
227
+ separator
228
+ add_code("#endif /* #{name} */")
229
+ end
230
+
231
+ # Adds a comment to the internal buffer. Before adding to the internal
232
+ # buffer, extraneous indentation and leading and trailing empty lines in
233
+ # `text` are removed, and new indentation is added based on the current
234
+ # indentation level. The text is also prefixed with the '*' character.
235
+ #
236
+ # Example:
237
+ #
238
+ # comment "hello\nworld"
239
+ # comment %q{
240
+ # foo
241
+ # bar
242
+ # }
243
+ #
244
+ # Output:
245
+ #
246
+ # /*
247
+ # * hello
248
+ # * world
249
+ # */
250
+ # /*
251
+ # * foo
252
+ # * bar
253
+ # */
254
+ def comment(text)
255
+ add_code '/*'
256
+ prefix = @indent_string * @indent_level
257
+ prefix << ' * '
258
+ @code << reindent(unindent(text.to_s), prefix, false)
259
+ @code << "\n"
260
+ add_code_without_newline '-'
261
+ @code.gsub!(/-\Z/, ' ')
262
+ add_raw_code "*/\n"
263
+ end
264
+
265
+ # Adds a struct definition to the internal buffer. Expects a block
266
+ # in which you must define the struct's contents. Inside the block
267
+ # you can use any Builder API methods, but you are most likely
268
+ # interested in `#member`, `#comment`, `#separator` and `#function`.
269
+ #
270
+ # Example:
271
+ #
272
+ # struct 'Car' do
273
+ # comment "The car's name"
274
+ # member 'string name'
275
+ #
276
+ # separator
277
+ # member 'unsigned int seats'
278
+ # end
279
+ #
280
+ # Outputs:
281
+ #
282
+ # struct Car {
283
+ # /*
284
+ # * The car's name.
285
+ # */
286
+ # string name;
287
+ #
288
+ # unsigned int seats;
289
+ # };
290
+ def struct(name)
291
+ add_code "struct #{name} {"
292
+ indent do
293
+ yield
294
+ end
295
+ add_code '};'
296
+ end
297
+
298
+ # Adds a struct typedef definition to the internal buffer. This works
299
+ # like the `#struct` method, but outputs a typedef struct instead.
300
+ #
301
+ # Example:
302
+ #
303
+ # typedef_struct 'Car' do
304
+ # comment "The car's name"
305
+ # member 'string name'
306
+ #
307
+ # separator
308
+ # member 'unsigned int seats'
309
+ # end
310
+ #
311
+ # Outputs:
312
+ #
313
+ # typedef struct {
314
+ # /*
315
+ # * The car's name.
316
+ # */
317
+ # string name;
318
+ #
319
+ # unsigned int seats;
320
+ # } Car;
321
+ def typedef_struct(name)
322
+ add_code 'typedef struct {'
323
+ indent do
324
+ yield
325
+ end
326
+ add_code "} #{name};"
327
+ end
328
+
329
+ # Adds a function definition to the internal buffer. There are two ways to
330
+ # supply the function body. The first is by passing a string. The second is
331
+ # by passing a block, which is expected to use Builder API methods to
332
+ # generate code for the body.
333
+ #
334
+ # If a string is passed, then extraneous indentation and leading and trailing
335
+ # empty lines inside it are removed.
336
+ #
337
+ # No matter how the body is body is supplied, the generated body is indented.
338
+ #
339
+ # Example:
340
+ #
341
+ # function 'static void foo(int x)', %q{
342
+ # printf("x = %d\n", x);
343
+ # }
344
+ #
345
+ # function 'static void bar(int x)' do
346
+ # add_code 'printf("x = %d\n", x);'
347
+ # end
348
+ #
349
+ # Output:
350
+ #
351
+ # static void
352
+ # foo(int x) {
353
+ # printf("x = %d\n", x);
354
+ # }
355
+ #
356
+ # static void
357
+ # bar(int x) {
358
+ # printf("x = %d\n", x);
359
+ # }
360
+ def function(declaration, body = nil)
361
+ declaration =~ /(.*?)([a-z0-9_:]+)\s*\((.*)\s*(const)?/mi
362
+ return_type_and_attributes = $1
363
+ name_and_params = "#{$2}(#{$3} #{$4}".strip
364
+
365
+ add_code return_type_and_attributes.strip
366
+ add_code "#{name_and_params.strip} {"
367
+ indent do
368
+ if block_given?
369
+ yield
370
+ else
371
+ add_code body
372
+ end
373
+ end
374
+ add_code '}'
375
+ separator
376
+ end
377
+
378
+ # Adds a field/member/variable definition to the internal buffer.
379
+ # You can optionally supply a value, either by passing it directly as
380
+ # an argument, or by passing a block which will generate the code for
381
+ # the value.
382
+ #
383
+ # When supplying an argument, the argument is added verbatim to the
384
+ # internal buffer, so you can even supply an expression. If you want to
385
+ # set the value to a string, then you should use the `#str_val` helper
386
+ # method. See the example below.
387
+ #
388
+ # The block form is especially useful for generating
389
+ # array/struct initializer code (see also `#array_initializer` and
390
+ # `#struct_initializer` in that case).
391
+ #
392
+ # Example:
393
+ #
394
+ # field('int a')
395
+ # field('int b', 123);
396
+ # field('int c', '1 + 2')
397
+ # field('const char *str', str_val("hello world"));
398
+ #
399
+ # separator
400
+ #
401
+ # field('int magicNumbers[]') do
402
+ # array_initializer do
403
+ # element 1
404
+ # element 2
405
+ # end
406
+ # end
407
+ #
408
+ # separator
409
+ #
410
+ # field('const char *magicStrings[]') do
411
+ # array_initializer do
412
+ # string_element "foo"
413
+ # # Equivalent:
414
+ # element str_val("foo")
415
+ # end
416
+ # end
417
+ #
418
+ # Output:
419
+ #
420
+ # int a;
421
+ # int b = 123;
422
+ # int c = 1 + 2;
423
+ # const char *str = "hello world";
424
+ #
425
+ # int magicNumbers[] = [
426
+ # 1,
427
+ # 2
428
+ # ];
429
+ #
430
+ # const char *magicStrings[] = [
431
+ # "foo",
432
+ # "foo"
433
+ # ];
434
+ #
435
+ def field(declaration, value = nil)
436
+ if block_given?
437
+ add_code_without_newline "#{declaration} ="
438
+ add_raw_code ' '
439
+ yield
440
+ @code.gsub!(/\n*\Z/m, '')
441
+ add_raw_code ';'
442
+ newline
443
+ elsif value
444
+ add_code "#{declaration} = #{value};"
445
+ else
446
+ add_code "#{declaration};"
447
+ end
448
+ end
449
+
450
+ alias variable field
451
+ alias member field
452
+
453
+ # Adds an array initializer (in the form of `[x, y, z]`) to the internal
454
+ # buffer. Expects a block which defines the elements inside the array.
455
+ # The block does not expose the Builder API methods, but exposes the
456
+ # InitializerBuilder API methods instead. See the comments in
457
+ # initializer_builder.rb for an example and to learn what API methods
458
+ # are available.
459
+ #
460
+ # Does not add a trailing newline.
461
+ #
462
+ # Example:
463
+ #
464
+ # array_initializer do
465
+ # element 1
466
+ # element 2
467
+ # end
468
+ #
469
+ # separator
470
+ #
471
+ # array_initializer do
472
+ # string_element "foo"
473
+ # # Equivalent:
474
+ # element str_val("foo")
475
+ # end
476
+ #
477
+ # Output:
478
+ #
479
+ # [
480
+ # 1,
481
+ # 2
482
+ # ]
483
+ #
484
+ # [
485
+ # "foo",
486
+ # "foo"
487
+ # ]
488
+ def array_initializer(&block)
489
+ subbuilder = InitializerBuilder.new(self, '[', ']')
490
+ subbuilder.instance_eval(&block)
491
+ subbuilder.write_code_without_newline
492
+ end
493
+
494
+ # Adds a struct initializer (in the form of `{x, y, z}`) to the internal
495
+ # buffer. Expects a block which defines the elements inside the array.
496
+ # The block does not expose the Builder API methods, but exposes the
497
+ # InitializerBuilder API methods instead. See the comments in
498
+ # initializer_builder.rb for an example and to learn what API methods
499
+ # are available.
500
+ #
501
+ # Does not add a trailing newline.
502
+ #
503
+ # Example:
504
+ #
505
+ # struct_initializer do
506
+ # element 1
507
+ # element 2
508
+ # end
509
+ #
510
+ # separator
511
+ #
512
+ # struct_initializer do
513
+ # string_element "foo"
514
+ # # Equivalent:
515
+ # element str_val("foo")
516
+ # end
517
+ #
518
+ # Output:
519
+ #
520
+ # {
521
+ # 1,
522
+ # 2
523
+ # }
524
+ #
525
+ # {
526
+ # "foo",
527
+ # "foo"
528
+ # }
529
+ def struct_initializer(&block)
530
+ subbuilder = InitializerBuilder.new(self, '{', '}')
531
+ subbuilder.instance_eval(&block)
532
+ subbuilder.write_code_without_newline
533
+ end
534
+
535
+ # Returns (and does not modify the internal buffer!) a C string representation
536
+ # of `str`. This is especially useful for supplying a string value to `#field`.
537
+ def str_val(str)
538
+ str.to_s.inspect
539
+ end
540
+
541
+ def to_s
542
+ @code
543
+ end
544
+
545
+ private
546
+ def unindent(str)
547
+ str = str.dup
548
+ str.gsub!(/\A([\s\t]*\n)+/, '')
549
+ str.gsub!(/[\s\t\n]+\Z/, '')
550
+ indent = str.split("\n").select{ |line| !line.strip.empty? }.map{ |line| line.index(/[^\s]/) }.compact.min || 0
551
+ str.gsub!(/^[[:blank:]]{#{indent}}/, '')
552
+ str
553
+ end
554
+
555
+ def reindent(str, prefix, convert_ruby_indentation)
556
+ str = unindent(str)
557
+
558
+ # Convert Ruby two-space indentation to our own indentation format
559
+ if convert_ruby_indentation
560
+ str.gsub!(/^( )+/) do |match|
561
+ @indent_string * (match.size / 2)
562
+ end
563
+ end
564
+
565
+ # Prepend supplied prefix to each line
566
+ str.gsub!(/^/, prefix)
567
+
568
+ # Remove trailing whitespaces
569
+ str.gsub!(/[ \t]+$/, '')
570
+
571
+ str
572
+ end
573
+ end
574
+ end