sassc 0.0.1

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 (151) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +9 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +24 -0
  8. data/Rakefile +21 -0
  9. data/ext/libsass/.editorconfig +15 -0
  10. data/ext/libsass/.gitattributes +2 -0
  11. data/ext/libsass/.gitignore +61 -0
  12. data/ext/libsass/.travis.yml +38 -0
  13. data/ext/libsass/COPYING +25 -0
  14. data/ext/libsass/INSTALL +1 -0
  15. data/ext/libsass/LICENSE +25 -0
  16. data/ext/libsass/Makefile +223 -0
  17. data/ext/libsass/Makefile.am +145 -0
  18. data/ext/libsass/Readme.md +93 -0
  19. data/ext/libsass/appveyor.yml +76 -0
  20. data/ext/libsass/ast.cpp +581 -0
  21. data/ext/libsass/ast.hpp +1949 -0
  22. data/ext/libsass/ast_def_macros.hpp +16 -0
  23. data/ext/libsass/ast_factory.hpp +87 -0
  24. data/ext/libsass/ast_fwd_decl.hpp +72 -0
  25. data/ext/libsass/b64/cencode.h +32 -0
  26. data/ext/libsass/b64/encode.h +77 -0
  27. data/ext/libsass/backtrace.hpp +81 -0
  28. data/ext/libsass/base64vlq.cpp +43 -0
  29. data/ext/libsass/base64vlq.hpp +28 -0
  30. data/ext/libsass/bind.cpp +187 -0
  31. data/ext/libsass/bind.hpp +18 -0
  32. data/ext/libsass/cencode.c +102 -0
  33. data/ext/libsass/color_names.hpp +324 -0
  34. data/ext/libsass/configure.ac +130 -0
  35. data/ext/libsass/constants.cpp +144 -0
  36. data/ext/libsass/constants.hpp +145 -0
  37. data/ext/libsass/context.cpp +507 -0
  38. data/ext/libsass/context.hpp +150 -0
  39. data/ext/libsass/contextualize.cpp +157 -0
  40. data/ext/libsass/contextualize.hpp +65 -0
  41. data/ext/libsass/copy_c_str.cpp +13 -0
  42. data/ext/libsass/copy_c_str.hpp +5 -0
  43. data/ext/libsass/debug.hpp +39 -0
  44. data/ext/libsass/environment.hpp +75 -0
  45. data/ext/libsass/error_handling.cpp +28 -0
  46. data/ext/libsass/error_handling.hpp +28 -0
  47. data/ext/libsass/eval.cpp +1149 -0
  48. data/ext/libsass/eval.hpp +80 -0
  49. data/ext/libsass/expand.cpp +430 -0
  50. data/ext/libsass/expand.hpp +77 -0
  51. data/ext/libsass/extconf.rb +6 -0
  52. data/ext/libsass/extend.cpp +1962 -0
  53. data/ext/libsass/extend.hpp +50 -0
  54. data/ext/libsass/file.cpp +291 -0
  55. data/ext/libsass/file.hpp +18 -0
  56. data/ext/libsass/functions.cpp +1565 -0
  57. data/ext/libsass/functions.hpp +187 -0
  58. data/ext/libsass/inspect.cpp +727 -0
  59. data/ext/libsass/inspect.hpp +108 -0
  60. data/ext/libsass/json.cpp +1411 -0
  61. data/ext/libsass/json.hpp +117 -0
  62. data/ext/libsass/kwd_arg_macros.hpp +23 -0
  63. data/ext/libsass/m4/.gitkeep +0 -0
  64. data/ext/libsass/mapping.hpp +17 -0
  65. data/ext/libsass/memory_manager.hpp +54 -0
  66. data/ext/libsass/node.cpp +251 -0
  67. data/ext/libsass/node.hpp +122 -0
  68. data/ext/libsass/operation.hpp +153 -0
  69. data/ext/libsass/output_compressed.cpp +401 -0
  70. data/ext/libsass/output_compressed.hpp +95 -0
  71. data/ext/libsass/output_nested.cpp +364 -0
  72. data/ext/libsass/output_nested.hpp +108 -0
  73. data/ext/libsass/parser.cpp +2016 -0
  74. data/ext/libsass/parser.hpp +264 -0
  75. data/ext/libsass/paths.hpp +69 -0
  76. data/ext/libsass/position.hpp +22 -0
  77. data/ext/libsass/posix/getopt.c +562 -0
  78. data/ext/libsass/posix/getopt.h +95 -0
  79. data/ext/libsass/prelexer.cpp +688 -0
  80. data/ext/libsass/prelexer.hpp +513 -0
  81. data/ext/libsass/remove_placeholders.cpp +59 -0
  82. data/ext/libsass/remove_placeholders.hpp +43 -0
  83. data/ext/libsass/res/resource.rc +35 -0
  84. data/ext/libsass/sass.cpp +33 -0
  85. data/ext/libsass/sass.h +60 -0
  86. data/ext/libsass/sass2scss.cpp +834 -0
  87. data/ext/libsass/sass2scss.h +110 -0
  88. data/ext/libsass/sass_context.cpp +709 -0
  89. data/ext/libsass/sass_context.h +120 -0
  90. data/ext/libsass/sass_functions.cpp +137 -0
  91. data/ext/libsass/sass_functions.h +90 -0
  92. data/ext/libsass/sass_interface.cpp +277 -0
  93. data/ext/libsass/sass_interface.h +97 -0
  94. data/ext/libsass/sass_util.cpp +136 -0
  95. data/ext/libsass/sass_util.hpp +259 -0
  96. data/ext/libsass/sass_values.cpp +337 -0
  97. data/ext/libsass/sass_values.h +124 -0
  98. data/ext/libsass/script/bootstrap +10 -0
  99. data/ext/libsass/script/branding +10 -0
  100. data/ext/libsass/script/ci-build-libsass +72 -0
  101. data/ext/libsass/script/ci-install-compiler +4 -0
  102. data/ext/libsass/script/ci-install-deps +19 -0
  103. data/ext/libsass/script/ci-report-coverage +25 -0
  104. data/ext/libsass/script/coveralls-debug +32 -0
  105. data/ext/libsass/script/spec +5 -0
  106. data/ext/libsass/script/tap-driver +652 -0
  107. data/ext/libsass/script/tap-runner +1 -0
  108. data/ext/libsass/source_map.cpp +133 -0
  109. data/ext/libsass/source_map.hpp +46 -0
  110. data/ext/libsass/subset_map.hpp +145 -0
  111. data/ext/libsass/support/libsass.pc.in +11 -0
  112. data/ext/libsass/test-driver +127 -0
  113. data/ext/libsass/test/test_node.cpp +98 -0
  114. data/ext/libsass/test/test_paths.cpp +29 -0
  115. data/ext/libsass/test/test_selector_difference.cpp +28 -0
  116. data/ext/libsass/test/test_specificity.cpp +28 -0
  117. data/ext/libsass/test/test_subset_map.cpp +472 -0
  118. data/ext/libsass/test/test_superselector.cpp +71 -0
  119. data/ext/libsass/test/test_unification.cpp +33 -0
  120. data/ext/libsass/to_c.cpp +61 -0
  121. data/ext/libsass/to_c.hpp +44 -0
  122. data/ext/libsass/to_string.cpp +29 -0
  123. data/ext/libsass/to_string.hpp +32 -0
  124. data/ext/libsass/token.hpp +32 -0
  125. data/ext/libsass/units.cpp +54 -0
  126. data/ext/libsass/units.hpp +10 -0
  127. data/ext/libsass/utf8.h +34 -0
  128. data/ext/libsass/utf8/checked.h +327 -0
  129. data/ext/libsass/utf8/core.h +329 -0
  130. data/ext/libsass/utf8/unchecked.h +228 -0
  131. data/ext/libsass/utf8_string.cpp +102 -0
  132. data/ext/libsass/utf8_string.hpp +36 -0
  133. data/ext/libsass/util.cpp +189 -0
  134. data/ext/libsass/util.hpp +26 -0
  135. data/ext/libsass/win/libsass.filters +291 -0
  136. data/ext/libsass/win/libsass.sln +28 -0
  137. data/ext/libsass/win/libsass.vcxproj +255 -0
  138. data/lib/sassc.rb +6 -0
  139. data/lib/sassc/engine.rb +13 -0
  140. data/lib/sassc/native.rb +44 -0
  141. data/lib/sassc/native/native_context_api.rb +140 -0
  142. data/lib/sassc/native/native_functions_api.rb +41 -0
  143. data/lib/sassc/native/sass_input_style.rb +11 -0
  144. data/lib/sassc/native/sass_output_style.rb +10 -0
  145. data/lib/sassc/native/sass_value.rb +95 -0
  146. data/lib/sassc/native/string_list.rb +8 -0
  147. data/lib/sassc/version.rb +3 -0
  148. data/sassc.gemspec +43 -0
  149. data/test/smoke_test.rb +171 -0
  150. data/test/test_helper.rb +4 -0
  151. metadata +281 -0
@@ -0,0 +1,264 @@
1
+ #define SASS_PARSER
2
+
3
+ #include <vector>
4
+ #include <map>
5
+
6
+ #ifndef SASS_PRELEXER
7
+ #include "prelexer.hpp"
8
+ #endif
9
+
10
+ #ifndef SASS_TOKEN
11
+ #include "token.hpp"
12
+ #endif
13
+
14
+ #ifndef SASS_CONTEXT
15
+ #include "context.hpp"
16
+ #endif
17
+
18
+ #ifndef SASS_AST
19
+ #include "ast.hpp"
20
+ #endif
21
+
22
+ #ifndef SASS_POSITION
23
+ #include "position.hpp"
24
+ #endif
25
+
26
+ #include <iostream>
27
+
28
+ struct Selector_Lookahead {
29
+ const char* found;
30
+ bool has_interpolants;
31
+ };
32
+
33
+ namespace Sass {
34
+ using std::string;
35
+ using std::vector;
36
+ using std::map;
37
+ using namespace Prelexer;
38
+
39
+ class Parser {
40
+ private:
41
+ void add_single_file (Import* imp, string import_path);
42
+ public:
43
+ class AST_Node;
44
+
45
+ enum Syntactic_Context { nothing, mixin_def, function_def };
46
+
47
+ Context& ctx;
48
+ vector<Syntactic_Context> stack;
49
+ const char* source;
50
+ const char* position;
51
+ const char* end;
52
+ string path;
53
+ size_t column;
54
+ Position source_position;
55
+
56
+
57
+ Token lexed;
58
+ bool dequote;
59
+
60
+ Parser(Context& ctx, string path, Position source_position)
61
+ : ctx(ctx), stack(vector<Syntactic_Context>()),
62
+ source(0), position(0), end(0), path(path), column(1), source_position(source_position)
63
+ { dequote = false; stack.push_back(nothing); }
64
+
65
+ static Parser from_string(string src, Context& ctx, string path = "", Position source_position = Position());
66
+ static Parser from_c_str(const char* src, Context& ctx, string path = "", Position source_position = Position());
67
+ static Parser from_token(Token t, Context& ctx, string path = "", Position source_position = Position());
68
+
69
+ #ifdef __clang__
70
+
71
+ // lex and peak uses the template parameter to branch on the action, which
72
+ // triggers clangs tautological comparison on the single-comparison
73
+ // branches. This is not a bug, just a merging of behaviour into
74
+ // one function
75
+
76
+ #pragma clang diagnostic push
77
+ #pragma clang diagnostic ignored "-Wtautological-compare"
78
+
79
+ #endif
80
+
81
+ template <prelexer mx>
82
+ const char* peek(const char* start = 0)
83
+ {
84
+ if (!start) start = position;
85
+ const char* after_whitespace;
86
+ if (mx == block_comment) {
87
+ after_whitespace = // start;
88
+ zero_plus< alternatives<spaces, line_comment> >(start);
89
+ }
90
+ else if (/*mx == ancestor_of ||*/ mx == no_spaces) {
91
+ after_whitespace = position;
92
+ }
93
+ else if (mx == spaces || mx == ancestor_of) {
94
+ after_whitespace = mx(start);
95
+ if (after_whitespace) {
96
+ return after_whitespace;
97
+ }
98
+ else {
99
+ return 0;
100
+ }
101
+ }
102
+ else if (mx == optional_spaces) {
103
+ after_whitespace = optional_spaces(start);
104
+ }
105
+ else if (mx == line_comment_prefix || mx == block_comment_prefix) {
106
+ after_whitespace = position;
107
+ }
108
+ else {
109
+ after_whitespace = spaces_and_comments(start);
110
+ }
111
+ const char* after_token = mx(after_whitespace);
112
+ if (after_token) {
113
+ return after_token;
114
+ }
115
+ else {
116
+ return 0;
117
+ }
118
+ }
119
+
120
+ template <prelexer mx>
121
+ const char* lex()
122
+ {
123
+ const char* after_whitespace;
124
+ if (mx == block_comment) {
125
+ after_whitespace = // position;
126
+ zero_plus< alternatives<spaces, line_comment> >(position);
127
+ }
128
+ else if (mx == url) {
129
+ after_whitespace = position;
130
+ }
131
+ else if (mx == ancestor_of || mx == no_spaces) {
132
+ after_whitespace = position;
133
+ }
134
+ else if (mx == spaces) {
135
+ after_whitespace = spaces(position);
136
+ if (after_whitespace) {
137
+ source_position.line += count_interval<'\n'>(position, after_whitespace);
138
+ lexed = Token(position, after_whitespace);
139
+ return position = after_whitespace;
140
+ }
141
+ else {
142
+ return 0;
143
+ }
144
+ }
145
+ else if (mx == optional_spaces) {
146
+ after_whitespace = optional_spaces(position);
147
+ }
148
+ else {
149
+ after_whitespace = spaces_and_comments(position);
150
+ }
151
+ const char* after_token = mx(after_whitespace);
152
+ if (after_token) {
153
+ size_t previous_line = source_position.line;
154
+ source_position.line += count_interval<'\n'>(position, after_token);
155
+
156
+ size_t whitespace = 0;
157
+ const char* ptr = after_whitespace - 1;
158
+ while (ptr >= position) {
159
+ if (*ptr == '\n')
160
+ break;
161
+ whitespace++;
162
+ ptr--;
163
+ }
164
+ if (previous_line != source_position.line) {
165
+ column = 1;
166
+ }
167
+
168
+ source_position.column = column + whitespace;
169
+ column += after_token - after_whitespace + whitespace;
170
+ lexed = Token(after_whitespace, after_token);
171
+
172
+ return position = after_token;
173
+ }
174
+ else {
175
+ return 0;
176
+ }
177
+ }
178
+
179
+ #ifdef __clang__
180
+
181
+ #pragma clang diagnostic pop
182
+
183
+ #endif
184
+
185
+ void error(string msg, Position pos = Position());
186
+ void read_bom();
187
+
188
+ Block* parse();
189
+ Import* parse_import();
190
+ Definition* parse_definition();
191
+ Parameters* parse_parameters();
192
+ Parameter* parse_parameter();
193
+ Mixin_Call* parse_mixin_call();
194
+ Arguments* parse_arguments();
195
+ Argument* parse_argument();
196
+ Assignment* parse_assignment();
197
+ Propset* parse_propset();
198
+ Ruleset* parse_ruleset(Selector_Lookahead lookahead);
199
+ Selector_Schema* parse_selector_schema(const char* end_of_selector);
200
+ Selector_List* parse_selector_group();
201
+ Complex_Selector* parse_selector_combination();
202
+ Compound_Selector* parse_simple_selector_sequence();
203
+ Simple_Selector* parse_simple_selector();
204
+ Wrapped_Selector* parse_negated_selector();
205
+ Simple_Selector* parse_pseudo_selector();
206
+ Attribute_Selector* parse_attribute_selector();
207
+ Block* parse_block();
208
+ Declaration* parse_declaration();
209
+ Expression* parse_map_value();
210
+ Expression* parse_map();
211
+ Expression* parse_list();
212
+ Expression* parse_comma_list();
213
+ Expression* parse_space_list();
214
+ Expression* parse_disjunction();
215
+ Expression* parse_conjunction();
216
+ Expression* parse_relation();
217
+ Expression* parse_expression();
218
+ Expression* parse_term();
219
+ Expression* parse_factor();
220
+ Expression* parse_value();
221
+ Function_Call* parse_calc_function();
222
+ Function_Call* parse_function_call();
223
+ Function_Call_Schema* parse_function_call_schema();
224
+ String* parse_interpolated_chunk(Token);
225
+ String* parse_string();
226
+ String_Constant* parse_static_value();
227
+ String* parse_ie_property();
228
+ String* parse_ie_keyword_arg();
229
+ String_Schema* parse_value_schema();
230
+ String* parse_identifier_schema();
231
+ String_Schema* parse_url_schema();
232
+ If* parse_if_directive(bool else_if = false);
233
+ For* parse_for_directive();
234
+ Each* parse_each_directive();
235
+ While* parse_while_directive();
236
+ Media_Block* parse_media_block();
237
+ List* parse_media_queries();
238
+ Media_Query* parse_media_query();
239
+ Media_Query_Expression* parse_media_expression();
240
+ Feature_Block* parse_feature_block();
241
+ Feature_Query* parse_feature_queries();
242
+ Feature_Query_Condition* parse_feature_query();
243
+ Feature_Query_Condition* parse_feature_query_in_parens();
244
+ Feature_Query_Condition* parse_supports_negation();
245
+ Feature_Query_Condition* parse_supports_conjunction();
246
+ Feature_Query_Condition* parse_supports_disjunction();
247
+ Feature_Query_Condition* parse_supports_declaration();
248
+ At_Rule* parse_at_rule();
249
+ Warning* parse_warning();
250
+ Error* parse_error();
251
+ Debug* parse_debug();
252
+
253
+ Selector_Lookahead lookahead_for_selector(const char* start = 0);
254
+ Selector_Lookahead lookahead_for_extension_target(const char* start = 0);
255
+
256
+ Expression* fold_operands(Expression* base, vector<Expression*>& operands, Binary_Expression::Type op);
257
+ Expression* fold_operands(Expression* base, vector<Expression*>& operands, vector<Binary_Expression::Type>& ops);
258
+
259
+ void throw_syntax_error(string message, size_t ln = 0);
260
+ void throw_read_error(string message, size_t ln = 0);
261
+ };
262
+
263
+ size_t check_bom_chars(const char* src, const char *end, const unsigned char* bom, size_t len);
264
+ }
@@ -0,0 +1,69 @@
1
+ #include <vector>
2
+ #include <iostream>
3
+ #include <string>
4
+ #include <sstream>
5
+
6
+ using namespace std;
7
+
8
+ template<typename T>
9
+ string vector_to_string(vector<T> v)
10
+ {
11
+ stringstream buffer;
12
+ buffer << "[";
13
+
14
+ if (!v.empty())
15
+ { buffer << v[0]; }
16
+ else
17
+ { buffer << "]"; }
18
+
19
+ if (v.size() == 1)
20
+ { buffer << "]"; }
21
+ else
22
+ {
23
+ for (size_t i = 1, S = v.size(); i < S; ++i) buffer << ", " << v[i];
24
+ buffer << "]";
25
+ }
26
+
27
+ return buffer.str();
28
+ }
29
+
30
+ namespace Sass {
31
+
32
+ using namespace std;
33
+
34
+ template<typename T>
35
+ vector<vector<T> > paths(vector<vector<T> > strata, size_t from_end = 0)
36
+ {
37
+ if (strata.empty()) {
38
+ return vector<vector<T> >();
39
+ }
40
+
41
+ size_t end = strata.size() - from_end;
42
+ if (end <= 1) {
43
+ vector<vector<T> > starting_points;
44
+ starting_points.reserve(strata[0].size());
45
+ for (size_t i = 0, S = strata[0].size(); i < S; ++i) {
46
+ vector<T> starting_point;
47
+ starting_point.push_back(strata[0][i]);
48
+ starting_points.push_back(starting_point);
49
+ }
50
+ return starting_points;
51
+ }
52
+
53
+ vector<vector<T> > up_to_here = paths(strata, from_end + 1);
54
+ vector<T> here = strata[end-1];
55
+
56
+ vector<vector<T> > branches;
57
+ branches.reserve(up_to_here.size() * here.size());
58
+ for (size_t i = 0, S1 = up_to_here.size(); i < S1; ++i) {
59
+ for (size_t j = 0, S2 = here.size(); j < S2; ++j) {
60
+ vector<T> branch = up_to_here[i];
61
+ branch.push_back(here[j]);
62
+ branches.push_back(branch);
63
+ }
64
+ }
65
+
66
+ return branches;
67
+ }
68
+
69
+ }
@@ -0,0 +1,22 @@
1
+ #define SASS_POSITION
2
+
3
+ #include <cstdlib>
4
+
5
+ namespace Sass {
6
+
7
+ struct Position {
8
+ size_t file;
9
+ size_t line;
10
+ size_t column;
11
+
12
+ Position()
13
+ : file(0), line(0), column(0) { }
14
+
15
+ Position(const size_t file, const size_t line, const size_t column)
16
+ : file(file), line(line), column(column) { }
17
+
18
+ Position(const size_t line, const size_t column)
19
+ : file(0), line(line), column(column) { }
20
+ };
21
+
22
+ }
@@ -0,0 +1,562 @@
1
+ /* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
2
+ /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
3
+
4
+ /*
5
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
6
+ *
7
+ * Permission to use, copy, modify, and distribute this software for any
8
+ * purpose with or without fee is hereby granted, provided that the above
9
+ * copyright notice and this permission notice appear in all copies.
10
+ *
11
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
+ *
19
+ * Sponsored in part by the Defense Advanced Research Projects
20
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
21
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
22
+ */
23
+ /*-
24
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
25
+ * All rights reserved.
26
+ *
27
+ * This code is derived from software contributed to The NetBSD Foundation
28
+ * by Dieter Baron and Thomas Klausner.
29
+ *
30
+ * Redistribution and use in source and binary forms, with or without
31
+ * modification, are permitted provided that the following conditions
32
+ * are met:
33
+ * 1. Redistributions of source code must retain the above copyright
34
+ * notice, this list of conditions and the following disclaimer.
35
+ * 2. Redistributions in binary form must reproduce the above copyright
36
+ * notice, this list of conditions and the following disclaimer in the
37
+ * documentation and/or other materials provided with the distribution.
38
+ *
39
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
40
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
41
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
43
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
44
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
45
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
46
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49
+ * POSSIBILITY OF SUCH DAMAGE.
50
+ */
51
+
52
+ #include <errno.h>
53
+ #include <stdlib.h>
54
+ #include <string.h>
55
+ #include <getopt.h>
56
+ #include <stdarg.h>
57
+ #include <stdio.h>
58
+ #include <windows.h>
59
+
60
+ #define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
61
+
62
+ #ifdef REPLACE_GETOPT
63
+ int opterr = 1; /* if error message should be printed */
64
+ int optind = 1; /* index into parent argv vector */
65
+ int optopt = '?'; /* character checked for validity */
66
+ #undef optreset /* see getopt.h */
67
+ #define optreset __mingw_optreset
68
+ int optreset; /* reset getopt */
69
+ char *optarg; /* argument associated with option */
70
+ #endif
71
+
72
+ #define PRINT_ERROR ((opterr) && (*options != ':'))
73
+
74
+ #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
75
+ #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
76
+ #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
77
+
78
+ /* return values */
79
+ #define BADCH (int)'?'
80
+ #define BADARG ((*options == ':') ? (int)':' : (int)'?')
81
+ #define INORDER (int)1
82
+
83
+ #ifndef __CYGWIN__
84
+ #define __progname __argv[0]
85
+ #else
86
+ extern char __declspec(dllimport) *__progname;
87
+ #endif
88
+
89
+ #ifdef __CYGWIN__
90
+ static char EMSG[] = "";
91
+ #else
92
+ #define EMSG ""
93
+ #endif
94
+
95
+ static int getopt_internal(int, char * const *, const char *,
96
+ const struct option *, int *, int);
97
+ static int parse_long_options(char * const *, const char *,
98
+ const struct option *, int *, int);
99
+ static int gcd(int, int);
100
+ static void permute_args(int, int, int, char * const *);
101
+
102
+ static char *place = EMSG; /* option letter processing */
103
+
104
+ /* XXX: set optreset to 1 rather than these two */
105
+ static int nonopt_start = -1; /* first non option argument (for permute) */
106
+ static int nonopt_end = -1; /* first option after non options (for permute) */
107
+
108
+ /* Error messages */
109
+ static const char recargchar[] = "option requires an argument -- %c";
110
+ static const char recargstring[] = "option requires an argument -- %s";
111
+ static const char ambig[] = "ambiguous option -- %.*s";
112
+ static const char noarg[] = "option doesn't take an argument -- %.*s";
113
+ static const char illoptchar[] = "unknown option -- %c";
114
+ static const char illoptstring[] = "unknown option -- %s";
115
+
116
+ static void
117
+ _vwarnx(const char *fmt,va_list ap)
118
+ {
119
+ (void)fprintf(stderr,"%s: ",__progname);
120
+ if (fmt != NULL)
121
+ (void)vfprintf(stderr,fmt,ap);
122
+ (void)fprintf(stderr,"\n");
123
+ }
124
+
125
+ static void
126
+ warnx(const char *fmt,...)
127
+ {
128
+ va_list ap;
129
+ va_start(ap,fmt);
130
+ _vwarnx(fmt,ap);
131
+ va_end(ap);
132
+ }
133
+
134
+ /*
135
+ * Compute the greatest common divisor of a and b.
136
+ */
137
+ static int
138
+ gcd(int a, int b)
139
+ {
140
+ int c;
141
+
142
+ c = a % b;
143
+ while (c != 0) {
144
+ a = b;
145
+ b = c;
146
+ c = a % b;
147
+ }
148
+
149
+ return (b);
150
+ }
151
+
152
+ /*
153
+ * Exchange the block from nonopt_start to nonopt_end with the block
154
+ * from nonopt_end to opt_end (keeping the same order of arguments
155
+ * in each block).
156
+ */
157
+ static void
158
+ permute_args(int panonopt_start, int panonopt_end, int opt_end,
159
+ char * const *nargv)
160
+ {
161
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
162
+ char *swap;
163
+
164
+ /*
165
+ * compute lengths of blocks and number and size of cycles
166
+ */
167
+ nnonopts = panonopt_end - panonopt_start;
168
+ nopts = opt_end - panonopt_end;
169
+ ncycle = gcd(nnonopts, nopts);
170
+ cyclelen = (opt_end - panonopt_start) / ncycle;
171
+
172
+ for (i = 0; i < ncycle; i++) {
173
+ cstart = panonopt_end+i;
174
+ pos = cstart;
175
+ for (j = 0; j < cyclelen; j++) {
176
+ if (pos >= panonopt_end)
177
+ pos -= nnonopts;
178
+ else
179
+ pos += nopts;
180
+ swap = nargv[pos];
181
+ /* LINTED const cast */
182
+ ((char **) nargv)[pos] = nargv[cstart];
183
+ /* LINTED const cast */
184
+ ((char **)nargv)[cstart] = swap;
185
+ }
186
+ }
187
+ }
188
+
189
+ /*
190
+ * parse_long_options --
191
+ * Parse long options in argc/argv argument vector.
192
+ * Returns -1 if short_too is set and the option does not match long_options.
193
+ */
194
+ static int
195
+ parse_long_options(char * const *nargv, const char *options,
196
+ const struct option *long_options, int *idx, int short_too)
197
+ {
198
+ char *current_argv, *has_equal;
199
+ size_t current_argv_len;
200
+ int i, ambiguous, match;
201
+
202
+ #define IDENTICAL_INTERPRETATION(_x, _y) \
203
+ (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
204
+ long_options[(_x)].flag == long_options[(_y)].flag && \
205
+ long_options[(_x)].val == long_options[(_y)].val)
206
+
207
+ current_argv = place;
208
+ match = -1;
209
+ ambiguous = 0;
210
+
211
+ optind++;
212
+
213
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
214
+ /* argument found (--option=arg) */
215
+ current_argv_len = has_equal - current_argv;
216
+ has_equal++;
217
+ } else
218
+ current_argv_len = strlen(current_argv);
219
+
220
+ for (i = 0; long_options[i].name; i++) {
221
+ /* find matching long option */
222
+ if (strncmp(current_argv, long_options[i].name,
223
+ current_argv_len))
224
+ continue;
225
+
226
+ if (strlen(long_options[i].name) == current_argv_len) {
227
+ /* exact match */
228
+ match = i;
229
+ ambiguous = 0;
230
+ break;
231
+ }
232
+ /*
233
+ * If this is a known short option, don't allow
234
+ * a partial match of a single character.
235
+ */
236
+ if (short_too && current_argv_len == 1)
237
+ continue;
238
+
239
+ if (match == -1) /* partial match */
240
+ match = i;
241
+ else if (!IDENTICAL_INTERPRETATION(i, match))
242
+ ambiguous = 1;
243
+ }
244
+ if (ambiguous) {
245
+ /* ambiguous abbreviation */
246
+ if (PRINT_ERROR)
247
+ warnx(ambig, (int)current_argv_len,
248
+ current_argv);
249
+ optopt = 0;
250
+ return (BADCH);
251
+ }
252
+ if (match != -1) { /* option found */
253
+ if (long_options[match].has_arg == no_argument
254
+ && has_equal) {
255
+ if (PRINT_ERROR)
256
+ warnx(noarg, (int)current_argv_len,
257
+ current_argv);
258
+ /*
259
+ * XXX: GNU sets optopt to val regardless of flag
260
+ */
261
+ if (long_options[match].flag == NULL)
262
+ optopt = long_options[match].val;
263
+ else
264
+ optopt = 0;
265
+ return (BADARG);
266
+ }
267
+ if (long_options[match].has_arg == required_argument ||
268
+ long_options[match].has_arg == optional_argument) {
269
+ if (has_equal)
270
+ optarg = has_equal;
271
+ else if (long_options[match].has_arg ==
272
+ required_argument) {
273
+ /*
274
+ * optional argument doesn't use next nargv
275
+ */
276
+ optarg = nargv[optind++];
277
+ }
278
+ }
279
+ if ((long_options[match].has_arg == required_argument)
280
+ && (optarg == NULL)) {
281
+ /*
282
+ * Missing argument; leading ':' indicates no error
283
+ * should be generated.
284
+ */
285
+ if (PRINT_ERROR)
286
+ warnx(recargstring,
287
+ current_argv);
288
+ /*
289
+ * XXX: GNU sets optopt to val regardless of flag
290
+ */
291
+ if (long_options[match].flag == NULL)
292
+ optopt = long_options[match].val;
293
+ else
294
+ optopt = 0;
295
+ --optind;
296
+ return (BADARG);
297
+ }
298
+ } else { /* unknown option */
299
+ if (short_too) {
300
+ --optind;
301
+ return (-1);
302
+ }
303
+ if (PRINT_ERROR)
304
+ warnx(illoptstring, current_argv);
305
+ optopt = 0;
306
+ return (BADCH);
307
+ }
308
+ if (idx)
309
+ *idx = match;
310
+ if (long_options[match].flag) {
311
+ *long_options[match].flag = long_options[match].val;
312
+ return (0);
313
+ } else
314
+ return (long_options[match].val);
315
+ #undef IDENTICAL_INTERPRETATION
316
+ }
317
+
318
+ /*
319
+ * getopt_internal --
320
+ * Parse argc/argv argument vector. Called by user level routines.
321
+ */
322
+ static int
323
+ getopt_internal(int nargc, char * const *nargv, const char *options,
324
+ const struct option *long_options, int *idx, int flags)
325
+ {
326
+ char *oli; /* option letter list index */
327
+ int optchar, short_too;
328
+ static int posixly_correct = -1;
329
+
330
+ if (options == NULL)
331
+ return (-1);
332
+
333
+ /*
334
+ * XXX Some GNU programs (like cvs) set optind to 0 instead of
335
+ * XXX using optreset. Work around this braindamage.
336
+ */
337
+ if (optind == 0)
338
+ optind = optreset = 1;
339
+
340
+ /*
341
+ * Disable GNU extensions if POSIXLY_CORRECT is set or options
342
+ * string begins with a '+'.
343
+ *
344
+ * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
345
+ * optreset != 0 for GNU compatibility.
346
+ */
347
+ if (posixly_correct == -1 || optreset != 0)
348
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
349
+ if (*options == '-')
350
+ flags |= FLAG_ALLARGS;
351
+ else if (posixly_correct || *options == '+')
352
+ flags &= ~FLAG_PERMUTE;
353
+ if (*options == '+' || *options == '-')
354
+ options++;
355
+
356
+ optarg = NULL;
357
+ if (optreset)
358
+ nonopt_start = nonopt_end = -1;
359
+ start:
360
+ if (optreset || !*place) { /* update scanning pointer */
361
+ optreset = 0;
362
+ if (optind >= nargc) { /* end of argument vector */
363
+ place = EMSG;
364
+ if (nonopt_end != -1) {
365
+ /* do permutation, if we have to */
366
+ permute_args(nonopt_start, nonopt_end,
367
+ optind, nargv);
368
+ optind -= nonopt_end - nonopt_start;
369
+ }
370
+ else if (nonopt_start != -1) {
371
+ /*
372
+ * If we skipped non-options, set optind
373
+ * to the first of them.
374
+ */
375
+ optind = nonopt_start;
376
+ }
377
+ nonopt_start = nonopt_end = -1;
378
+ return (-1);
379
+ }
380
+ if (*(place = nargv[optind]) != '-' ||
381
+ (place[1] == '\0' && strchr(options, '-') == NULL)) {
382
+ place = EMSG; /* found non-option */
383
+ if (flags & FLAG_ALLARGS) {
384
+ /*
385
+ * GNU extension:
386
+ * return non-option as argument to option 1
387
+ */
388
+ optarg = nargv[optind++];
389
+ return (INORDER);
390
+ }
391
+ if (!(flags & FLAG_PERMUTE)) {
392
+ /*
393
+ * If no permutation wanted, stop parsing
394
+ * at first non-option.
395
+ */
396
+ return (-1);
397
+ }
398
+ /* do permutation */
399
+ if (nonopt_start == -1)
400
+ nonopt_start = optind;
401
+ else if (nonopt_end != -1) {
402
+ permute_args(nonopt_start, nonopt_end,
403
+ optind, nargv);
404
+ nonopt_start = optind -
405
+ (nonopt_end - nonopt_start);
406
+ nonopt_end = -1;
407
+ }
408
+ optind++;
409
+ /* process next argument */
410
+ goto start;
411
+ }
412
+ if (nonopt_start != -1 && nonopt_end == -1)
413
+ nonopt_end = optind;
414
+
415
+ /*
416
+ * If we have "-" do nothing, if "--" we are done.
417
+ */
418
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
419
+ optind++;
420
+ place = EMSG;
421
+ /*
422
+ * We found an option (--), so if we skipped
423
+ * non-options, we have to permute.
424
+ */
425
+ if (nonopt_end != -1) {
426
+ permute_args(nonopt_start, nonopt_end,
427
+ optind, nargv);
428
+ optind -= nonopt_end - nonopt_start;
429
+ }
430
+ nonopt_start = nonopt_end = -1;
431
+ return (-1);
432
+ }
433
+ }
434
+
435
+ /*
436
+ * Check long options if:
437
+ * 1) we were passed some
438
+ * 2) the arg is not just "-"
439
+ * 3) either the arg starts with -- we are getopt_long_only()
440
+ */
441
+ if (long_options != NULL && place != nargv[optind] &&
442
+ (*place == '-' || (flags & FLAG_LONGONLY))) {
443
+ short_too = 0;
444
+ if (*place == '-')
445
+ place++; /* --foo long option */
446
+ else if (*place != ':' && strchr(options, *place) != NULL)
447
+ short_too = 1; /* could be short option too */
448
+
449
+ optchar = parse_long_options(nargv, options, long_options,
450
+ idx, short_too);
451
+ if (optchar != -1) {
452
+ place = EMSG;
453
+ return (optchar);
454
+ }
455
+ }
456
+
457
+ if ((optchar = (int)*place++) == (int)':' ||
458
+ (optchar == (int)'-' && *place != '\0') ||
459
+ (oli = strchr(options, optchar)) == NULL) {
460
+ /*
461
+ * If the user specified "-" and '-' isn't listed in
462
+ * options, return -1 (non-option) as per POSIX.
463
+ * Otherwise, it is an unknown option character (or ':').
464
+ */
465
+ if (optchar == (int)'-' && *place == '\0')
466
+ return (-1);
467
+ if (!*place)
468
+ ++optind;
469
+ if (PRINT_ERROR)
470
+ warnx(illoptchar, optchar);
471
+ optopt = optchar;
472
+ return (BADCH);
473
+ }
474
+ if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
475
+ /* -W long-option */
476
+ if (*place) /* no space */
477
+ /* NOTHING */;
478
+ else if (++optind >= nargc) { /* no arg */
479
+ place = EMSG;
480
+ if (PRINT_ERROR)
481
+ warnx(recargchar, optchar);
482
+ optopt = optchar;
483
+ return (BADARG);
484
+ } else /* white space */
485
+ place = nargv[optind];
486
+ optchar = parse_long_options(nargv, options, long_options,
487
+ idx, 0);
488
+ place = EMSG;
489
+ return (optchar);
490
+ }
491
+ if (*++oli != ':') { /* doesn't take argument */
492
+ if (!*place)
493
+ ++optind;
494
+ } else { /* takes (optional) argument */
495
+ optarg = NULL;
496
+ if (*place) /* no white space */
497
+ optarg = place;
498
+ else if (oli[1] != ':') { /* arg not optional */
499
+ if (++optind >= nargc) { /* no arg */
500
+ place = EMSG;
501
+ if (PRINT_ERROR)
502
+ warnx(recargchar, optchar);
503
+ optopt = optchar;
504
+ return (BADARG);
505
+ } else
506
+ optarg = nargv[optind];
507
+ }
508
+ place = EMSG;
509
+ ++optind;
510
+ }
511
+ /* dump back option letter */
512
+ return (optchar);
513
+ }
514
+
515
+ #ifdef REPLACE_GETOPT
516
+ /*
517
+ * getopt --
518
+ * Parse argc/argv argument vector.
519
+ *
520
+ * [eventually this will replace the BSD getopt]
521
+ */
522
+ int
523
+ getopt(int nargc, char * const *nargv, const char *options)
524
+ {
525
+
526
+ /*
527
+ * We don't pass FLAG_PERMUTE to getopt_internal() since
528
+ * the BSD getopt(3) (unlike GNU) has never done this.
529
+ *
530
+ * Furthermore, since many privileged programs call getopt()
531
+ * before dropping privileges it makes sense to keep things
532
+ * as simple (and bug-free) as possible.
533
+ */
534
+ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
535
+ }
536
+ #endif /* REPLACE_GETOPT */
537
+
538
+ /*
539
+ * getopt_long --
540
+ * Parse argc/argv argument vector.
541
+ */
542
+ int
543
+ getopt_long(int nargc, char * const *nargv, const char *options,
544
+ const struct option *long_options, int *idx)
545
+ {
546
+
547
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
548
+ FLAG_PERMUTE));
549
+ }
550
+
551
+ /*
552
+ * getopt_long_only --
553
+ * Parse argc/argv argument vector.
554
+ */
555
+ int
556
+ getopt_long_only(int nargc, char * const *nargv, const char *options,
557
+ const struct option *long_options, int *idx)
558
+ {
559
+
560
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
561
+ FLAG_PERMUTE|FLAG_LONGONLY));
562
+ }