12 #include <apr_file_io.h>
13 #include <apr_getopt.h>
48 static const apr_getopt_option_t opts[] = {
50 {
"allow",
'a', TRUE,
"Content type used to output adaptive values." },
51 {
"check",
'k', FALSE,
"Parse but don't evaluate." },
52 {
"conf",
'f', TRUE,
"Configuration file." },
53 {
"expression",
'x', TRUE,
"The first string to evaluate." },
54 {
"extension",
'e', TRUE,
"Load extension." },
55 {
"help",
'h', FALSE,
"Print this help and exit successfully." },
56 {
"local",
'l', TRUE,
"Run in \"local\" mode with output to path or fd number." },
57 {
"syntax",
's', TRUE,
"expression_tuple, expression, hybrid, parenthesized, script, template, test_script" },
58 {
"type",
't', TRUE,
"Content type of configuration file." },
59 {
"version",
'v', FALSE,
"Print version and exit successfully." },
64 static const char * impl_additional_help_text =
66 "The syntax option (-s) determines how input will be parsed:\n"
68 " -s expression_tuple - The input is an adaptive expression tuple.\n"
69 " -s expression - The input is an adaptive expression.\n"
70 " -s hybrid - The input is an adaptive hybrid.\n"
71 " -s parentheses - The input is an adaptive expression enclose in\n"
73 " -s script - The input is an adaptive script.\n"
74 " -s template - The input is an adaptive template.\n"
75 " -s test_script - The input is an adaptive test script.\n"
77 "A line ending with \"\\\" will be combined with the line that follows\n"
78 "to form one logical line.\n"
80 "When option -s expression or -s template is specified, the input is\n"
81 "evaluated one logical line at a time.\n"
83 "When option -s parentheses is specified, logical lines are evaluated up\n"
84 "up to the expression's closing parenthesis (')'). The parenthesized\n"
85 "expression can be preceded by any amount of whitespace, including\n"
86 "comments, and followed by whitespace up to the end of the line.\n"
88 "When option -s hybrid is specified and the input does not begin with a\n"
89 "square bracket ('['), the input must be on one logical line; otherwise,\n"
90 "input will be evaluated through the logical line with the hybrid's\n"
91 "closing square bracket (']').\n"
93 "The conf option (-f) is used to specify the path to a configuration\n"
94 "file. By default, this file should be encoded with a relaxed json\n"
95 "syntax, which accepts standard json, plus allows block comments\n"
96 "(/* ... */), line comments (//), unquoted property names, and several\n"
97 "other conveniences.\n"
100 "The type option (-t) can be used to specify a content type other than the\n"
101 "default. If the content type is not part of AFW core, use the extension\n"
102 "option (-e) to load the appropriate extension.\n"
104 "If the -f option is not specified, only core AFW functionality is\n"
107 "The optional adaptive expression specified by expression option (-x)\n"
108 "is evaluated first. If -x is specified and [IN] is not specified,\n"
109 "afw will end after evaluating the expression.\n"
111 "If neither -x or [IN] is specified, input is read from stdin.\n"
112 "Each line read from stdin is evaluated as an adaptive expressions\n"
113 "until either a line containing only \"exit\" or end of file is\n"
116 "If [IN] is specified but -s is not, the file is evaluated as an\n"
119 "If the -l option is specified, output is written to the path or fd\n"
120 "number specified. Input is always read from stdin so [IN] cannot be\n"
123 "When the -l option is specified, input must be, and output will be made\n"
124 "up of one or more segments that are in turn made up of one or more\n"
125 "chunks. Each chunk is preceded with a decimal length of the chunk\n"
126 "followed by a '\\n'. A line containing only \"0\\n\" is used to\n"
127 "indicate the end of a segment. The last input segment must be:\n"
130 "See the afw command documentation for information about what can be\n"
131 "contained in each segment.\n"
133 "A simple example using default directives to add 2 plus 2:\n"
135 " 8\\nadd(2,2)0\\n4\\nexit0\\n\n"
137 "The output will be:\n"
151 c = fgetc(self->fd_input);
174 if (self->eof)
return NULL;
177 if (!self->input_buffer) {
178 self->input_buffer = apr_array_make(
184 apr_array_clear(self->input_buffer);
185 for (prev_c = 0; ; prev_c = c) {
186 c = fgetc(self->fd_input);
191 if (c ==
'\n' && prev_c ==
'\\') {
192 apr_array_pop(self->input_buffer);
195 APR_ARRAY_PUSH(self->input_buffer,
unsigned char) = c;
196 if (c ==
'\n')
break;
200 return (self->input_buffer->nelts == 0)
203 self->input_buffer->nelts, xctx->p, xctx);
226 error_occurred =
false;
237 self->environment_variables_object,
true, xctx->p, xctx);
245 else if (!self->read_full) {
247 line = impl_get_input(
self, xctx);
254 if (self->compile_option == afw_compile_type_template ||
255 (self->compile_option == afw_compile_type_hybrid &&
258 if (line->s[line->len - 1] ==
'\n') {
265 impl_print_end(
self);
268 if (!keep_going)
break;
282 self->callback, self->callback_data,
283 self->source_location, self->compile_option,
284 self->residual_check,
285 NULL, NULL, xctx->p, xctx);
298 if (!self->check_mode) {
310 *exit_code = EXIT_FAILURE;
312 "Adaptive script run from shell must return "
313 "null or an integer between 0 and 255 but returned "
315 impl_print_result_value(
self, evaluated_value);
327 impl_print_result_value(
self, evaluated_value);
334 error_occurred =
true;
341 if (keep_going) impl_print_end(
self);
342 return keep_going && !
self->terminal_error;
357 const apr_getopt_option_t *opt;
360 rv = fprintf(stderr,
"Usage: afw [OPTION]... [IN]\n\n");
361 if (rv < 0) exit(EXIT_FAILURE);
363 rv = fprintf(stderr,
"\n");
364 if (rv < 0) exit(EXIT_FAILURE);
366 rv = fprintf(stderr,
"OPTION:\n");
367 if (rv < 0) exit(EXIT_FAILURE);
371 rv = fprintf(stderr,
" -%c, --%-10s %s %s\n",
374 (opt->has_arg) ?
" ARG " :
" ",
376 if (rv < 0) exit(EXIT_FAILURE);
380 rv = fprintf(stderr,
"%s", impl_additional_help_text);
381 if (rv < 0) exit(EXIT_FAILURE);
392 const char * option_arg;
399 fprintf(xctx->env->
stderr_fd,
"apr_getopt_init() error.\n");
403 self->compile_option = afw_compile_type_error;
404 self->residual_check = afw_compile_residual_check_to_full;
405 self->index_first_non_option = 1;
406 while ((rv = apr_getopt_long(os, opts, &option_ch, &option_arg))
409 self->index_first_non_option = os->ind;
413 self->type_out_z = option_arg;
414 self->type_out.len = strlen(self->type_out_z);
418 self->conf_z = option_arg;
419 self->conf.len = strlen(self->conf_z);
423 self->extension_z = option_arg;
424 self->extension.len = strlen(self->extension_z);
428 self->check_mode =
true;
432 self->local_mode_z = option_arg;
433 self->local_mode_out.len = strlen(self->local_mode_z);
440 self->compile_option = afw_compile_type_expression_tuple;
441 self->can_span_lines =
false;
446 self->compile_option = afw_compile_type_expression;
447 self->can_span_lines =
false;
452 self->compile_option = afw_compile_type_hybrid;
453 self->can_span_lines =
true;
458 self->compile_option = afw_compile_type_parenthesized_expression;
459 self->can_span_lines =
true;
464 self->compile_option = afw_compile_type_script;
465 self->can_span_lines =
false;
470 self->compile_option = afw_compile_type_template;
471 self->can_span_lines =
false;
476 self->compile_option = afw_compile_type_test_script;
477 self->can_span_lines =
false;
480 rv = fprintf(stderr,
"Invalid option --syntax %s\n", option_arg);
481 if (rv < 0) exit(EXIT_FAILURE);
489 self->type_in_z = option_arg;
490 self->type_in.len = strlen(self->type_in_z);
494 rv = fprintf(stderr,
"%s\n", AFW_COMMAND_VERSION_COMMAND_STRING);
495 if (rv < 0) exit(EXIT_FAILURE);
496 self->help_option =
true;
500 self->expression_z = option_arg;
501 self->expression.len = strlen(self->expression_z);
505 self->help_option =
true;
510 rv = fprintf(stderr,
"Error: Invalid command line parameter.\n");
511 if (rv < 0) exit(EXIT_FAILURE);
519 fprintf(xctx->env->
stderr_fd,
"Try --help.\n");
535 rv = process_args_getopt(
self, argc, argv, xctx);
536 if (rv != EXIT_SUCCESS) {
541 if (!self->type_in_z) {
542 self->type_in.s =
"json";
544 self->type_in.len = strlen(self->type_in.s);
547 if (!self->type_out_z) {
548 self->type_out.s =
"json";
550 self->type_out.len = strlen(self->type_out.s);
553 if (argc > self->index_first_non_option + 1) {
554 rv = fprintf(stderr,
"Error: Can not specify more than one positional parameter.\n");
555 if (rv < 0) exit(EXIT_FAILURE);
561 if (argc == self->index_first_non_option + 1) {
562 self->in_z = argv[
self->index_first_non_option];
563 self->in.len = strlen(self->in_z);
567 if (self->in_z && self->local_mode_z) {
568 rv = fprintf(stderr,
"Error: Can not specify [IN] if -l specified.\n");
569 if (rv < 0) exit(EXIT_FAILURE);
575 if (self->compile_option == afw_compile_type_error)
577 self->compile_option = (
self->in_z)
578 ? afw_compile_type_script
579 : afw_compile_type_expression;
583 if (!self->local_mode_z && !self->expression_z && !self->in_z) {
584 self->interactive_mode =
true;
603 va_start (ap, format);
604 rv = vfprintf(self->fd_output, format, ap);
606 if (rv < 0) exit(EXIT_FAILURE);
608 rv = fprintf(self->fd_output,
"\n");
609 if (rv < 0) exit(EXIT_FAILURE);
610 rv = fflush(self->fd_output);
611 if (rv < 0) exit(EXIT_FAILURE);
625 impl_print_result(
self,
634 self->content_type_out,
637 self->xctx->p, self->xctx);
640 impl_print_result(
self,
"%.*s",
641 (
int)(raw)->size, (
const char *)(raw)->ptr);
649 self->xctx->p, self->xctx);
650 impl_print_result(
self,
663 rv = fprintf(xctx->env->
stderr_fd,
"\n--- Error ---\n");
664 if (rv < 0) exit(EXIT_FAILURE);
667 if (rv < 0) exit(EXIT_FAILURE);
668 rv = fprintf(xctx->env->
stderr_fd,
"\n");
669 if (rv < 0) exit(EXIT_FAILURE);
671 if (rv < 0) exit(EXIT_FAILURE);
683 main(
int argc,
const char *
const *argv) {
712 self->fd_input = stdin;
713 self->fd_output = stdout;
714 self->source_location = &afw_command_s_afw_command;
717 rv = process_args(
self, argc, argv, xctx);
718 if (self->help_option || rv != EXIT_SUCCESS) {
723 self->environment_variables_object =
728 self->environment_variables_object,
true, xctx->p, xctx);
731 if (self->extension.len > 0) {
737 if (self->conf.len > 0) {
741 &self->type_in, xctx);
742 if (!self->content_type_in) {
749 conf_file, &self->conf, xctx->p, xctx);
761 &self->type_out, xctx);
762 if (!self->content_type_out) {
767 if (self->expression_z) {
768 self->source_location = &afw_command_s_afw_command_dash_x;
769 impl_evaluate(
self, &self->expression, NULL);
770 self->source_location = &afw_command_s_afw_command;
775 self->source_location = &
self->in;
776 self->fd_input = fopen(self->in_z,
"r");
777 if (!self->fd_input) {
779 "Error opening input %s errno %d - %s\n",
780 self->in_z, errno, strerror(errno));
786 if (self->local_mode_z) {
787 self->source_location = &afw_command_s_afw_command_local_mode;
788 for (s = self->local_mode_z; *s && *s >=
'0' && *s <=
'9'; s++);
791 rv = atoi(self->local_mode_z);
793 self->fd_output = fdopen(rv,
"w");
797 self->fd_output = fopen(self->local_mode_z,
"w");
799 if (!self->fd_output) {
801 "Error opening -l path %s errno %d - %s\n",
802 self->local_mode_z, errno, strerror(errno));
807 if (self->interactive_mode) {
808 self->source_location = &afw_command_s_afw_command_interactive;
812 if (self->compile_option == afw_compile_type_script ||
813 self->compile_option == afw_compile_type_test_script)
815 self->read_full =
true;
816 self->callback = impl_octet_get_cb;
817 self->callback_data =
self;
818 self->residual_check = afw_compile_residual_check_to_full;
819 if (self->compile_option == afw_compile_type_script) {
820 impl_evaluate(
self, NULL, &rv);
823 impl_evaluate(
self, NULL, NULL);
829 else if (self->local_mode_z) {
838 else if (self->in_z || self->interactive_mode) {
839 if (self->can_span_lines) {
840 self->callback = impl_octet_get_cb;
841 self->callback_data =
self;
842 self->residual_check = afw_compile_residual_check_to_newline;
844 if (self->interactive_mode) {
845 impl_print_result(
self,
846 "afw " AFW_VERSION_STRING
"\n\n"
847 "Input will be evaluated as entered. "
848 "Type exit to end.\n");
850 impl_print_end(
self);
852 while (impl_evaluate(
self, NULL, NULL));
859 impl_print_end(
self);
867 if (
self && self->fd_input && self->in_z) {
868 fclose(self->fd_input);
Adaptive Framework Core API.
void afw_command_generated_register(afw_xctx_t *xctx)
Generated register for afw_command.
Adaptive Framework afw command internal header.
Implementation for interface afw_command_local.
afw_adaptor_session_commit_and_release_cache(afw_boolean_t abort, afw_xctx_t *xctx)
Commit/Abort changes and release cached sessions and objects.
#define afw_value_is_integer(A_VALUE)
Macro to determine if value is evaluated integer.
#define afw_value_is_list(A_VALUE)
Macro to determine if value is evaluated list.
#define afw_value_is_null(A_VALUE)
Macro to determine if value is evaluated null.
afw_command_local_server_create(afw_command_self_t *command_self)
#define AFW_UTF8_FMT_ARG(A_STRING)
Convenience Macro for use with AFW_UTF8_FMT to specify arg.
#define AFW_UTF8_FMT
Format string specifier used for afw_utf8_t.
char afw_utf8_octet_t
8 bits of utf-8 codepoint.
afw_compile_to_value_with_callback(const afw_utf8_t *string, afw_utf8_octet_get_cb_t callback, void *callback_data, const afw_utf8_t *source_location, afw_compile_type_t compile_type, afw_compile_residual_check_t residual_check, const afw_value_compiled_value_t *parent, const afw_compile_shared_t *shared, const afw_pool_t *p, afw_xctx_t *xctx)
Compile string to adaptive value with callback.
#define afw_content_type_raw_to_value(instance, raw, source_location, p, xctx)
Call method raw_to_value of interface afw_content_type.
afw_content_type_value_to_raw(const afw_content_type_t *instance, const afw_value_t *value, const afw_object_options_t *options, const afw_pool_t *p, afw_xctx_t *xctx)
Convert value to the raw in specified pool.
afw_environment_set_stdout_fd(FILE *fd, afw_xctx_t *xctx)
Override fd used for stdout.
afw_environment_load_extension(const afw_utf8_t *extension_id, const afw_utf8_t *module_path, const afw_object_t *properties, afw_xctx_t *xctx)
Load and initialize environment extension.
#define AFW_ENVIRONMENT_CREATE(xctx, argc, argv, environment_create_error)
Call afw_environment_create() supplying version compiled with.
const afw_content_type_t * afw_environment_get_content_type(const afw_utf8_t *type, afw_xctx_t *xctx)
Get the afw_content_type struct associated with a content type.
afw_environment_release(afw_xctx_t *xctx)
Create the Adaptive Framework core environment and return base xctx.
void afw_environment_configure_with_object_list(const afw_list_t *entry_list, const afw_utf8_t *source_location, afw_xctx_t *xctx)
Configure environment with list of configuration entries.
const afw_object_t * afw_environment_create_environment_variables_object(afw_boolean_t preload_variables, afw_xctx_t *xctx)
Create a readonly object for accessing environment variables.
#define AFW_FINALLY
Always executed regardless of error.
afw_error_print_with_xctx(FILE *fp, const afw_error_t *error, const afw_pool_t *p, afw_xctx_t *xctx)
Print error when xctx is available.
#define AFW_CATCH_UNHANDLED
Catch an unhandled error that occurs in a AFW_TRY block.
afw_error_print(FILE *fp, const afw_error_t *error)
Print error.
#define AFW_ENDTRY
Ends an AFW try block.
#define AFW_TRY
Begin an AFW TRY block.
#define AFW_ERROR_THROWN
Access the thrown error. See AFW_TRY.
#define AFW_THROW_ERROR_Z(code, message_z, xctx)
Macro used to set error and 0 rv in xctx and throw it.
afw_file_to_memory(const afw_utf8_t *file_path, apr_size_t file_size, const afw_pool_t *p, afw_xctx_t *xctx)
Read a file into a memory in a specifed pool.
afw_object_options_whitespace
Whitespace only.
#define afw_pool_get_apr_pool(instance)
Call method get_apr_pool of interface afw_pool.
afw_runtime_xctx_set_object(const afw_object_t *object, afw_boolean_t overwrite, afw_xctx_t *xctx)
Set an object pointer in the xctx's runtime objects.
#define afw_server_run(instance, handler, xctx)
Call method run of interface afw_server.
afw_boolean_t afw_utf8_equal_utf8_z(const afw_utf8_t *s1, const afw_utf8_z_t *s2_z)
Check to see if a string equals a utf8_z string.
afw_boolean_t afw_utf8_z_equal(const afw_utf8_z_t *s1, const afw_utf8_z_t *s2)
#define afw_utf8_create(s, len, p, xctx)
Create utf-8 string without copy unless necessary in pool specified.
#define afw_value_evaluate(value, p, xctx)
Evaluate value if needed using specific pool.
const afw_utf8_t * afw_value_decompile_to_string(const afw_value_t *value, const afw_utf8_t *tab, const afw_pool_t *p, afw_xctx_t *xctx)
Decompile a value to a string.
#define afw_value_is_defined_and_evaluated(A_VALUE)
Macro to determine if value is defined and evaluated.
#define afw_value_is_undefined(A_VALUE)
Determine if value is undefined.
#define afw_xctx_release(instance, xctx)
Call method release of interface afw_xctx.
afw_xctx_push_qualifier_object(const afw_utf8_t *qualifier_name, const afw_object_t *qualifier_object, afw_boolean_t secure, const afw_pool_t *p, afw_xctx_t *xctx)
Push qualifier object on to stack.
afw_xctx_create(const afw_utf8_t *name, afw_integer_t number, afw_xctx_t *xctx)
Create an Adaptive Framework xctx.
#define afw_xctx_calloc_type(type, xctx)
Macro to allocate cleared memory to hold type in xctx's pool.
Self typedef for afw_command self.
FILE * stderr_fd
Open file descriptor used for writing error output. Default stderr.
Adaptive Framework Error.
Struct for memory pointer and size.
NFC normalized UTF-8 string.
struct for data type integer values.
struct for data type list values.
Interface afw_value public struct.
Interface afw_xctx public struct.