sassc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }