1#ifdef _MSC_VER
2#ifndef _CRT_SECURE_NO_WARNINGS
3#define _CRT_SECURE_NO_WARNINGS 1
4#endif
5#ifndef _CRT_NONSTDC_NO_WARNINGS
6#define _CRT_NONSTDC_NO_WARNINGS 1
7#endif
8#endif
9
10#include <stdio.h>
11#include <string.h>
12#include <stdlib.h>
13#include <getopt.h>
14#include <sass.h>
15#include "sassc_version.h"
16
17#define BUFSIZE 512
18#ifdef _WIN32
19#define PATH_SEP ';'
20#else
21#define PATH_SEP ':'
22#endif
23
24#ifdef _WIN32
25#include <io.h>
26#include <fcntl.h>
27#include <windows.h>
28
29#define isatty(h) _isatty(h)
30#define fileno(m) _fileno(m)
31
32int get_argv_utf8(int* argc_ptr, char*** argv_ptr) {
33 int argc;
34 char** argv;
35 wchar_t** argv_utf16 = CommandLineToArgvW(GetCommandLineW(), &argc);
36 int i;
37 int offset = (argc + 1) * sizeof(char*);
38 int size = offset;
39 for (i = 0; i < argc; i++)
40 size += WideCharToMultiByte(CP_UTF8, 0, argv_utf16[i], -1, 0, 0, 0, 0);
41 argv = malloc(size);
42 for (i = 0; i < argc; i++) {
43 argv[i] = (char*) argv + offset;
44 offset += WideCharToMultiByte(CP_UTF8, 0, argv_utf16[i], -1,
45 argv[i], size-offset, 0, 0);
46 }
47 *argc_ptr = argc;
48 *argv_ptr = argv;
49 return 0;
50}
51#else
52#include <unistd.h>
53#include <sysexits.h>
54#endif
55
56int output(int error_status, const char* error_message, const char* output_string, const char* outfile) {
57 if (error_status) {
58 if (error_message) {
59 fprintf(stderr, format: "%s", error_message);
60 } else {
61 fprintf(stderr, format: "An error occurred; no error message available.\n");
62 }
63 return 1;
64 } else if (output_string) {
65 if(outfile) {
66 FILE* fp = fopen(filename: outfile, modes: "wb");
67 if(!fp) {
68 perror(s: "Error opening output file");
69 return 1;
70 }
71 if(fprintf(stream: fp, format: "%s", output_string) < 0) {
72 perror(s: "Error writing to output file");
73 fclose(stream: fp);
74 return 1;
75 }
76 fclose(stream: fp);
77 }
78 else {
79 #ifdef _WIN32
80 setmode(fileno(stdout), O_BINARY);
81 #endif
82 printf(format: "%s", output_string);
83 }
84 return 0;
85 } else {
86 fprintf(stderr, format: "Unknown internal error.\n");
87 return 2;
88 }
89}
90
91int compile_stdin(struct Sass_Options* options, char* outfile) {
92 int ret;
93 struct Sass_Data_Context* ctx;
94 char buffer[BUFSIZE];
95 size_t size = 1;
96 char *source_string = malloc(size: sizeof(char) * BUFSIZE);
97
98 if(source_string == NULL) {
99 perror(s: "Allocation failed");
100 #ifdef _WIN32
101 exit(ERROR_OUTOFMEMORY);
102 #else
103 exit(EX_OSERR); // system error (e.g., can't fork)
104 #endif
105 }
106
107 source_string[0] = '\0';
108
109 while(fgets(s: buffer, BUFSIZE, stdin)) {
110 char *old = source_string;
111 size += strlen(s: buffer);
112 source_string = realloc(ptr: source_string, size: size);
113 if(source_string == NULL) {
114 perror(s: "Reallocation failed");
115 free(ptr: old);
116 #ifdef _WIN32
117 exit(ERROR_OUTOFMEMORY);
118 #else
119 exit(EX_OSERR); // system error (e.g., can't fork)
120 #endif
121 }
122 strcat(dest: source_string, src: buffer);
123 }
124
125 if(ferror(stdin)) {
126 free(ptr: source_string);
127 perror(s: "Error reading standard input");
128 #ifdef _WIN32
129 exit(ERROR_READ_FAULT); //
130 #else
131 exit(EX_IOERR); // input/output error
132 #endif
133 }
134
135 ctx = sass_make_data_context(source_string);
136 struct Sass_Context* ctx_out = sass_data_context_get_context(data_ctx: ctx);
137 sass_data_context_set_options(data_ctx: ctx, opt: options);
138 sass_compile_data_context(ctx);
139 ret = output(
140 error_status: sass_context_get_error_status(ctx: ctx_out),
141 error_message: sass_context_get_error_message(ctx: ctx_out),
142 output_string: sass_context_get_output_string(ctx: ctx_out),
143 outfile
144 );
145 sass_delete_data_context(ctx);
146 return ret;
147}
148
149int compile_file(struct Sass_Options* options, char* input_path, char* outfile) {
150 int ret;
151 struct Sass_File_Context* ctx = sass_make_file_context(input_path);
152 struct Sass_Context* ctx_out = sass_file_context_get_context(file_ctx: ctx);
153 if (outfile) sass_option_set_output_path(options, output_path: outfile);
154 const char* srcmap_file = sass_option_get_source_map_file(options);
155 sass_option_set_input_path(options, input_path);
156 sass_file_context_set_options(file_ctx: ctx, opt: options);
157
158 sass_compile_file_context(ctx);
159
160 ret = output(
161 error_status: sass_context_get_error_status(ctx: ctx_out),
162 error_message: sass_context_get_error_message(ctx: ctx_out),
163 output_string: sass_context_get_output_string(ctx: ctx_out),
164 outfile
165 );
166
167 if (ret == 0 && srcmap_file) {
168 ret = output(
169 error_status: sass_context_get_error_status(ctx: ctx_out),
170 error_message: sass_context_get_error_message(ctx: ctx_out),
171 output_string: sass_context_get_source_map_string(ctx: ctx_out),
172 outfile: srcmap_file
173 );
174 }
175
176 sass_delete_file_context(ctx);
177 return ret;
178}
179
180struct
181{
182 char* style_string;
183 int output_style;
184} style_option_strings[] = {
185 { "compressed", SASS_STYLE_COMPRESSED },
186 { "compact", SASS_STYLE_COMPACT },
187 { "expanded", SASS_STYLE_EXPANDED },
188 { "nested", SASS_STYLE_NESTED }
189};
190
191#define NUM_STYLE_OPTION_STRINGS \
192 sizeof(style_option_strings) / sizeof(style_option_strings[0])
193
194void print_version() {
195 printf(format: "sassc: %s\n", SASSC_VERSION);
196 printf(format: "libsass: %s\n", libsass_version());
197 printf(format: "sass2scss: %s\n", sass2scss_version());
198 printf(format: "sass: %s\n", libsass_language_version());
199}
200
201void print_usage(char* argv0) {
202 int i;
203 printf(format: "Usage: %s [options] [INPUT] [OUTPUT]\n\n", argv0);
204 printf(format: "Options:\n");
205 printf(format: " -s, --stdin Read input from standard input instead of an input file.\n");
206 printf(format: " -t, --style NAME Output style. Can be:");
207 for(i = NUM_STYLE_OPTION_STRINGS - 1; i >= 0; i--) {
208 printf(format: " %s", style_option_strings[i].style_string);
209 printf(format: i == 0 ? ".\n" : ",");
210 }
211 printf(format: " -l, --line-numbers Emit comments showing original line numbers.\n");
212 printf(format: " --line-comments\n");
213 printf(format: " -I, --load-path PATH Set Sass import path.\n");
214 printf(format: " -P, --plugin-path PATH Set path to autoload plugins.\n");
215 printf(format: " -m, --sourcemap[=TYPE] Emit source map (auto or inline).\n");
216 printf(format: " -M, --omit-map-comment Omits the source map url comment.\n");
217 printf(format: " -p, --precision Set the precision for numbers.\n");
218 printf(format: " -a, --sass Treat input as indented syntax.\n");
219 printf(format: " -v, --version Display compiled versions.\n");
220 printf(format: " -h, --help Display this help message.\n");
221 printf(format: "\n");
222}
223
224void invalid_usage(char* argv0) {
225 fprintf(stderr, format: "See '%s -h'\n", argv0);
226 #ifdef _WIN32
227 exit(ERROR_BAD_ARGUMENTS); // One or more arguments are not correct.
228 #else
229 exit(EX_USAGE); // command line usage error
230 #endif
231
232}
233
234int main(int argc, char** argv) {
235#ifdef _MSC_VER
236 _set_error_mode(_OUT_TO_STDERR);
237 _set_abort_behavior( 0, _WRITE_ABORT_MSG);
238#endif
239#ifdef _WIN32
240 get_argv_utf8(&argc, &argv);
241#endif
242 if ((argc == 1) && isatty(fd: fileno(stdin))) {
243 print_usage(argv0: argv[0]);
244 return 0;
245 }
246
247 char *outfile = 0;
248 int from_stdin = 0;
249 bool auto_source_map = false;
250 bool generate_source_map = false;
251 struct Sass_Options* options = sass_make_options();
252 sass_option_set_output_style(options, output_style: SASS_STYLE_NESTED);
253 sass_option_set_precision(options, precision: 10);
254
255 int c;
256 size_t i;
257 int long_index = 0;
258 static struct option long_options[] =
259 {
260 { "stdin", no_argument, 0, 's' },
261 { "load-path", required_argument, 0, 'I' },
262 { "plugin-path", required_argument, 0, 'P' },
263 { "style", required_argument, 0, 't' },
264 { "line-numbers", no_argument, 0, 'l' },
265 { "line-comments", no_argument, 0, 'l' },
266 { "sourcemap", optional_argument, 0, 'm' },
267 { "omit-map-comment", no_argument, 0, 'M' },
268 { "precision", required_argument, 0, 'p' },
269 { "version", no_argument, 0, 'v' },
270 { "sass", no_argument, 0, 'a' },
271 { "help", no_argument, 0, 'h' },
272 { NULL, 0, NULL, 0}
273 };
274 while ((c = getopt_long(argc: argc, argv: argv, shortopts: "vhslm::Map:t:I:P:", longopts: long_options, longind: &long_index)) != -1) {
275 switch (c) {
276 case 's':
277 from_stdin = 1;
278 break;
279 case 'I':
280 sass_option_push_include_path(options, path: optarg);
281 break;
282 case 'P':
283 sass_option_push_plugin_path(options, path: optarg);
284 break;
285 case 't':
286 for(i = 0; i < NUM_STYLE_OPTION_STRINGS; ++i) {
287 if(strcmp(s1: optarg, s2: style_option_strings[i].style_string) == 0) {
288 sass_option_set_output_style(options, output_style: style_option_strings[i].output_style);
289 break;
290 }
291 }
292 if(i == NUM_STYLE_OPTION_STRINGS) {
293 fprintf(stderr, format: "Invalid argument for -t flag: '%s'. Allowed arguments are:", optarg);
294 for(i = 0; i < NUM_STYLE_OPTION_STRINGS; ++i) {
295 fprintf(stderr, format: " %s", style_option_strings[i].style_string);
296 }
297 fprintf(stderr, format: "\n");
298 invalid_usage(argv0: argv[0]);
299 }
300 break;
301 case 'l':
302 sass_option_set_source_comments(options, true);
303 break;
304 case 'm':
305 if (optarg) { // optional argument
306 if (strcmp(s1: optarg, s2: "auto") == 0) {
307 auto_source_map = true;
308 } else if (strcmp(s1: optarg, s2: "inline") == 0) {
309 sass_option_set_source_map_embed(options, true);
310 } else {
311 fprintf(stderr, format: "Invalid argument for -m flag: '%s'. Allowed arguments are:", optarg);
312 fprintf(stderr, format: " %s", "auto inline");
313 fprintf(stderr, format: "\n");
314 invalid_usage(argv0: argv[0]);
315 }
316 } else {
317 auto_source_map = true;
318 }
319 generate_source_map = true;
320 break;
321 case 'M':
322 sass_option_set_omit_source_map_url(options, true);
323 break;
324 case 'p':
325 sass_option_set_precision(options, precision: atoi(nptr: optarg)); // TODO: make this more robust
326 if (sass_option_get_precision(options) < 0) sass_option_set_precision(options, precision: 10);
327 break;
328 case 'a':
329 sass_option_set_is_indented_syntax_src(options, true);
330 break;
331 case 'v':
332 print_version();
333 sass_delete_options(options);
334 return 0;
335 case 'h':
336 print_usage(argv0: argv[0]);
337 sass_delete_options(options);
338 return 0;
339 case '?':
340 /* Unrecognized flag or missing an expected value */
341 /* getopt should produce it's own error message for this case */
342 invalid_usage(argv0: argv[0]);
343 default:
344 fprintf(stderr, format: "Unknown error while processing arguments\n");
345 sass_delete_options(options);
346 return 2;
347 }
348 }
349
350 if(optind < argc - 2) {
351 fprintf(stderr, format: "Error: Too many arguments.\n");
352 invalid_usage(argv0: argv[0]);
353 }
354
355 int result;
356 const char* dash = "-";
357 if(optind < argc && strcmp(s1: argv[optind], s2: dash) != 0 && !from_stdin) {
358 if (optind + 1 < argc) {
359 outfile = argv[optind + 1];
360 }
361 if (generate_source_map && outfile) {
362 const char* extension = ".map";
363 char* source_map_file = calloc(nmemb: strlen(s: outfile) + strlen(s: extension) + 1, size: sizeof(char));
364 strcpy(dest: source_map_file, src: outfile);
365 strcat(dest: source_map_file, src: extension);
366 sass_option_set_source_map_file(options, source_map_file);
367 } else if (auto_source_map) {
368 sass_option_set_source_map_embed(options, true);
369 }
370 result = compile_file(options, input_path: argv[optind], outfile);
371 } else {
372 if (optind < argc) {
373 outfile = argv[optind];
374 }
375 result = compile_stdin(options, outfile);
376 }
377
378 sass_delete_options(options);
379
380 #ifdef _WIN32
381 return result ? ERROR_INVALID_DATA : 0; // The data is invalid.
382 #else
383 return result ? EX_DATAERR : 0; // data format error
384 #endif
385}
386

source code of gtk/subprojects/sassc/sassc.c