Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_error.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Adaptive Framework Error Handling
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
14 #include "afw_internal.h"
15 
16 
17 typedef struct impl_error_code_map_s {
18  afw_utf8_t id;
19  afw_boolean_t error_allow_in_response;
20  int http_response_code;
21  afw_utf8_t description;
22  afw_utf8_t html_description;
24 
25 
26 static const impl_error_code_map_t impl_error_code_map[] = {
27  {
28  AFW_UTF8_LITERAL("is_not_specified"),
29  false,
30  500,
31  AFW_UTF8_LITERAL("OK"),
32  AFW_UTF8_LITERAL("200 OK")
33  },
34 
35 #define XX(id, error_allow_in_response, http_response_code, description) \
36  { \
37  AFW_UTF8_LITERAL( #id ), \
38  error_allow_in_response, \
39  http_response_code, \
40  AFW_UTF8_LITERAL( #description ), \
41  AFW_UTF8_LITERAL( #http_response_code " " #description ) \
42  },
44 #undef XX
45 
46 };
47 
48 
49 static const afw_utf8_t impl_s_a_html_unknown =
50  AFW_UTF8_LITERAL("500 Unknown Error");
51 
52 
53 
54 AFW_DEFINE(void)
55 afw_error_rv_set_z(
56  afw_error_code_t code,
57  const afw_utf8_z_t *rv_source_id_z,
58  int rv,
59  const afw_utf8_z_t * source_z,
60  const afw_utf8_z_t * message_z,
61  afw_xctx_t *xctx)
62 {
64  afw_utf8_t rv_source_id;
65 
66  xctx->error->code = code;
67  xctx->error->rv_source_id_z = rv_source_id_z;
68  xctx->error->rv = rv;
69  xctx->error->rv_decoded_z = NULL;
70  xctx->error->source_z = source_z;
71  xctx->error->message_z = message_z;
72 
73  if (code != afw_error_code_memory) {
74  xctx->error->backtrace = afw_os_backtrace(code, -1, xctx);
75  }
76 
77  /* If rv nonzero and decoder available, call it to get rv_decoded_z. */
78  if (rv != 0 && rv_source_id_z)
79  {
80  rv_source_id.s = rv_source_id_z;
81  rv_source_id.len = strlen(rv_source_id_z);
82  decoder = afw_environment_get_error_rv_decoder(&rv_source_id, xctx);
83  if (decoder) {
84  xctx->error->rv_decoded_z = decoder(rv,
85  &xctx->error->decode_rv_wa[0],
86  sizeof(xctx->error->decode_rv_wa));
87  }
88  }
89 }
90 
91 
92 AFW_DEFINE(void)
93 afw_error_set_z(
94  afw_error_code_t code,
95  const afw_utf8_z_t * source_z,
96  const afw_utf8_z_t * message_z,
97  afw_xctx_t *xctx)
98 {
99  afw_error_rv_set_z(code, NULL, 0, source_z, message_z,
100  xctx);
101 }
102 
103 
105 afw_error_rv_set_fz(
106  afw_error_code_t code,
107  const afw_utf8_z_t *rv_source_id_z,
108  int rv,
109  const afw_utf8_z_t * source_z,
110  afw_xctx_t *xctx,
111  const afw_utf8_z_t * format_z, ...)
112 {
113  va_list ap;
114 
115  va_start(ap, format_z);
116  vsnprintf((char *)&(xctx->error->message_wa[0]),
117  sizeof(xctx->error->message_wa),
118  (const char *)format_z, ap);
119  afw_error_rv_set_z(code, rv_source_id_z, rv, source_z,
120  &xctx->error->message_wa[0], xctx);
121  va_end(ap);
122 }
123 
125 afw_error_set_fz(
126  afw_error_code_t code,
127  const afw_utf8_z_t * source_z,
128  afw_xctx_t *xctx,
129  const afw_utf8_z_t * format_z, ...)
130 {
131  va_list ap;
132 
133  va_start(ap, format_z);
134  vsnprintf((char *)&(xctx->error->message_wa[0]),
135  sizeof(xctx->error->message_wa),
136  (const char *)format_z, ap);
137  afw_error_rv_set_z(code, NULL, 0, source_z,
138  &xctx->error->message_wa[0], xctx);
139  va_end(ap);
140 }
141 
142 
143 AFW_DEFINE(void)
144 afw_error_rv_set_vz(
145  afw_error_code_t code,
146  const afw_utf8_z_t *rv_source_id_z,
147  int rv,
148  const afw_utf8_z_t * source_z,
149  const afw_utf8_z_t * format_z, va_list ap,
150  afw_xctx_t *xctx)
151 {
152  vsnprintf((char *)&(xctx->error->message_wa[0]),
153  sizeof(xctx->error->message_wa),
154  (const char *)format_z, ap);
155  afw_error_rv_set_z(code, rv_source_id_z, rv, source_z,
156  &xctx->error->message_wa[0], xctx);
157 }
158 
159 
160 AFW_DEFINE(void)
161 afw_error_set_vz(
162  afw_error_code_t code,
163  const afw_utf8_z_t * source_z,
164  const afw_utf8_z_t * format_z, va_list ap,
165  afw_xctx_t *xctx)
166 {
167  vsnprintf((char *)&(xctx->error->message_wa[0]),
168  sizeof(xctx->error->message_wa),
169  (const char *)format_z, ap);
170  afw_error_rv_set_z(code, NULL, 0, source_z,
171  &xctx->error->message_wa[0], xctx);
172 }
173 
174 
175 static void
176 impl_write_source_lines(
177  const afw_writer_t *w,
178  const afw_utf8_t *source,
179  afw_size_t error_line,
180  const afw_pool_t *p,
181  afw_xctx_t *xctx)
182 {
183  afw_size_t j, line;
184  afw_size_t offset;
185  afw_size_t number_of_lines;
186  afw_size_t max_column_number;
187  char buf2[(AFW_SIZE_T_MAX_BUFFER * 3) + 8];
188  int offset_cell_octets;
189  int line_cell_octets;
190  afw_boolean_t new_line;
191 
193  &number_of_lines, &max_column_number, source, 4, xctx);
194 
195  offset_cell_octets =
196  afw_number_bytes_needed_size_t(source->len);
197 
198  line_cell_octets =
199  afw_number_bytes_needed_size_t(number_of_lines);
200 
201  /* Check for \n. */
202  line = 1;
203  new_line = true;
204 
205  /* Loop writing source. */
206  for (j = 0, offset = 0; j < source->len; j++)
207  {
208  if (source->s[j] == '\t')
209  {
210  afw_writer_write_z(w, " ", xctx);
211  offset += 4;
212  }
213  else {
214  if (new_line) {
215  new_line = false;
216  snprintf(buf2, AFW_SIZE_T_MAX_BUFFER,
217  "%*" AFW_SIZE_T_FMT " "
218  "%*" AFW_SIZE_T_FMT,
219  offset_cell_octets, offset,
220  line_cell_octets, line);
221  afw_writer_write_z(w, buf2, xctx);
222  if (error_line == line) {
223  afw_writer_write_z(w, " > ", xctx);
224  }
225  else {
226  afw_writer_write_z(w, " | ", xctx);
227  }
228  }
229  if (source->s[j] == '\n')
230  {
231  if (line != 0) {
232  line++;
233  new_line = true;
234  }
235  }
236  afw_writer_write(w, source->s + j, 1, xctx);
237  offset++;
238  }
239  }
240  if (line == 0 || !new_line) {
241  afw_writer_write_eol(w, xctx);
242  }
243 }
244 
245 
246 
247 static const afw_utf8_t *
248 impl_evaluation_backtrace(
249  const afw_error_t *error,
250  const afw_pool_t *p,
251  afw_xctx_t *xctx)
252 {
253  const afw_writer_t *w;
254  afw_utf8_t s;
255  const afw_utf8_t *result;
256  afw_value_info_t info;
257  char buf[AFW_INTEGER_MAX_BUFFER];
258  char buf2[(AFW_SIZE_T_MAX_BUFFER * 3) + 8];
259  const afw_compile_value_contextual_t *last_contextual;
260  afw_integer_t i, entry_number;
261  afw_size_t j, line, parameter_number;
262  afw_size_t error_line, error_column;
263  afw_size_t error_offset;
264  afw_size_t line_number;
265  afw_size_t column_number;
266  afw_size_t number_of_lines;
267  afw_size_t max_column_number;
268  afw_size_t offset;
269  afw_boolean_t new_line, caret_on_error;
270  int offset_cell_octets;
271  int line_cell_octets;
272  int column_cell_octets;
273 
274  if (afw_stack_is_empty(xctx->evaluation_stack) &&
275  !error->parser_source)
276  {
277  return NULL;
278  }
279 
280  caret_on_error = false;
281  last_contextual = NULL;
282  offset_cell_octets = 0;
283  line_cell_octets = 0;
284  column_cell_octets = 0;
285 
286 
287  w = afw_utf8_writer_create(&afw_s_a_tab, p, xctx);
288 
289  if (error->parser_source) {
290  caret_on_error = afw_utf8_line_column_of_offset(
291  &error_line, &error_column,
292  error->parser_source, error->parser_cursor, 4, xctx);
293  afw_writer_write_z(w, "---Compile error:", xctx);
294  afw_writer_write(w, error->message_z, strlen(error->message_z), xctx);
295  afw_writer_write_eol(w, xctx);
296  afw_writer_write_eol(w, xctx);
297  impl_write_source_lines(w, error->parser_source, error_line, p, xctx);
298  afw_writer_write_eol(w, xctx);
299  }
300 
301  for (entry_number = 0,
302  i = xctx->evaluation_stack->top - xctx->evaluation_stack->first,
303  parameter_number = 0;
304  i >= 0;
305  i--)
306  {
307 
308  if (!xctx->evaluation_stack->first[i].value) {
309  afw_writer_write_utf8(w, &afw_s_a_undefined_as_string, xctx);
310  afw_writer_write_eol(w, xctx);
311  continue;
312  }
313 
314  if (xctx->evaluation_stack->first[i].entry_id ==
315  &afw_s_parameter_number)
316  {
317  i--;
318  parameter_number =
319  xctx->evaluation_stack->first[i].parameter_number;
320  continue;
321  }
322 
323 
324  /* This should not need to be here, so just note to avoid crash. */
325  if (xctx->evaluation_stack->first[i].parameter_number < 100)
326  {
328  "--- Unexpected parameter number. "
329  "Evaluation stack error.",
330  xctx);
331  afw_writer_write_eol(w, xctx);
332  parameter_number =
333  xctx->evaluation_stack->first[i].parameter_number;
334  continue;
335  }
336 
337  afw_value_get_info(xctx->evaluation_stack->first[i].value, &info,
338  w->p, xctx);
339 
340  /* Source location and source */
341  if (info.contextual && info.contextual->compiled_value)
342  {
343 
344  /* Source location each time it changes */
345  if (!last_contextual ||
346  last_contextual->source_location !=
347  info.contextual->source_location)
348  {
349  error_offset = info.contextual->value_offset;
350  if (entry_number == 0) {
351  caret_on_error = afw_utf8_line_column_of_offset(
352  &error_line, &error_column,
353  info.contextual->compiled_value->full_source,
354  info.contextual->value_offset, 4, xctx);
355  }
356  else {
357  caret_on_error = false;
358  afw_writer_write_eol(w, xctx);
359  }
360  afw_writer_write_z(w, "---CompiledValue ", xctx);
361  entry_number++;
362  snprintf(buf, AFW_INTEGER_MAX_BUFFER, "%" AFW_INTEGER_FMT,
363  entry_number);
364  afw_writer_write_z(w, buf, xctx);
365 
366  afw_writer_write_eol(w, xctx);
367  }
368 
369  /* Note when source not available. Probably needs to fix. */
370  if (!info.contextual->compiled_value) {
371  afw_writer_write_eol(w, xctx);
372  afw_writer_write_z(w, "---Source <None>", xctx);
373  afw_writer_write_eol(w, xctx);
374  afw_writer_write_eol(w, xctx);
375  afw_writer_write_z(w, "---Backtrace", xctx);
376  afw_writer_write_eol(w, xctx);
377  }
378 
379  /* Full source each time it changes */
380  else if (!last_contextual ||
381  (last_contextual->compiled_value &&
382  last_contextual->compiled_value->full_source !=
383  info.contextual->compiled_value->full_source &&
384  info.contextual->compiled_value->full_source))
385  {
387  &number_of_lines, &max_column_number,
388  info.contextual->compiled_value->full_source,
389  4, xctx);
390 
391  offset_cell_octets =
393  info.contextual->compiled_value->full_source->len);
394 
395  line_cell_octets =
396  afw_number_bytes_needed_size_t(number_of_lines);
397 
398  column_cell_octets =
399  afw_number_bytes_needed_size_t(max_column_number);
400 
401  afw_writer_write_eol(w, xctx);
402  afw_writer_write_z(w, "---Source type:", xctx);
403 
405  info.contextual->compiled_value->full_source_type,
406  xctx);
407 
408  afw_writer_write_z(w, " sourceLocation:", xctx);
410  info.contextual->source_location,
411  xctx);
412 
414  &line_number, &column_number,
415  info.contextual->compiled_value->full_source,
416  info.contextual->value_offset, 4, xctx);
417  afw_writer_write_z(w, " errorBetween:", xctx);
418  snprintf(buf2, AFW_SIZE_T_MAX_BUFFER,
419  "%" AFW_SIZE_T_FMT
420  "(%" AFW_SIZE_T_FMT ":%" AFW_SIZE_T_FMT ")",
421  info.contextual->value_offset, line_number, column_number);
422  afw_writer_write_z(w, buf2, xctx);
423 
424  offset = info.contextual->value_offset +
425  info.contextual->value_size - 1;
427  &line_number, &column_number,
428  info.contextual->compiled_value->full_source,
429  offset, 4, xctx);
430  snprintf(buf2, AFW_SIZE_T_MAX_BUFFER,
431  "-%" AFW_SIZE_T_FMT
432  "(%" AFW_SIZE_T_FMT ":%" AFW_SIZE_T_FMT ")",
433  offset, line_number, column_number);
434  afw_writer_write_z(w, buf2, xctx);
435  afw_writer_write_eol(w, xctx);
436 
437  /* Check for \n. */
438  line = 1;
439  new_line = true;
440 
441  /* Loop writing source. */
442  for (j = 0, offset = 0;
443  j < info.contextual->compiled_value->full_source->len;
444  j++)
445  {
446  if (info.contextual->compiled_value->full_source->s[j]
447  == '\t')
448  {
449  afw_writer_write_z(w, " ", xctx);
450  offset += 4;
451  }
452  else {
453  if (new_line) {
454  new_line = false;
455  snprintf(buf2, sizeof(buf2),
456  "%*" AFW_SIZE_T_FMT " "
457  "%*" AFW_SIZE_T_FMT,
458  offset_cell_octets, offset,
459  line_cell_octets, line);
460  afw_writer_write_z(w, buf2, xctx);
461  if (caret_on_error && error_line == line) {
462  afw_writer_write_z(w, " > ", xctx);
463  }
464  else {
465  afw_writer_write_z(w, " | ", xctx);
466  }
467  }
468  if (info.contextual->compiled_value->full_source->s[j]
469  == '\n')
470  {
471  if (line != 0) {
472  line++;
473  new_line = true;
474  }
475  }
477  info.contextual->compiled_value->full_source->s + j,
478  1, xctx);
479  offset++;
480  }
481  }
482  if (line == 0 || !new_line) {
483  afw_writer_write_eol(w, xctx);
484  }
485 
486  afw_writer_write_eol(w, xctx);
487  afw_writer_write_z(w, "---Backtrace", xctx);
488  afw_writer_write_eol(w, xctx);
489  }
490  }
491 
492  /* Source location and source */
493  if (info.contextual && info.contextual->compiled_value) {
495  &line_number, &column_number,
496  info.contextual->compiled_value->full_source,
497  info.contextual->value_offset, 4, xctx);
498  snprintf(buf2, AFW_SIZE_T_MAX_BUFFER,
499  "%*" AFW_SIZE_T_FMT " "
500  "%*" AFW_SIZE_T_FMT ":" "%-*" AFW_SIZE_T_FMT,
501  offset_cell_octets, info.contextual->value_offset,
502  line_cell_octets, line_number,
503  column_cell_octets, column_number);
504  afw_writer_write_z(w, buf2, xctx);
505  if (error_offset == info.contextual->value_offset) {
506  afw_writer_write_z(w, " > ", xctx);
507  }
508  else {
509  afw_writer_write_z(w, " | ", xctx);
510  }
511  }
512  else {
513  afw_writer_write_z(w, "? ", xctx);
514  }
515 
516  /* Value Inf Id */
517  afw_writer_write_utf8(w, info.value_inf_id, xctx);
518 
519  /* Detail */
520  if (info.detail) {
521  afw_writer_write_z(w, " ", xctx);
522  afw_writer_write_utf8(w, info.detail, xctx);
523  }
524 
525  if (parameter_number != 0) {
526  afw_writer_write_z(w, " (evaluating parameter ", xctx);
527  snprintf(buf, AFW_INTEGER_MAX_BUFFER, "%" AFW_SIZE_T_FMT,
528  parameter_number);
529  afw_writer_write_z(w, buf, xctx);
530  afw_writer_write_z(w, ")", xctx);
531  parameter_number = 0;
532  }
533 
534  afw_writer_write_eol(w, xctx);
535  last_contextual = info.contextual;
536  }
537 
538  afw_utf8_writer_current_string(w, &s, xctx);
539  result = afw_utf8_create_copy(s.s, s.len, p, xctx);
540  afw_writer_release(w, xctx);
541  return result;
542 }
543 
544 
545 
546 AFW_DEFINE(const afw_utf8_t *)
548  const afw_error_t *error,
549  const afw_pool_t *p,
550  afw_xctx_t *xctx)
551 {
552  const afw_utf8_t *result;
553  const afw_utf8_t *evaluation_backtrace;
554  afw_boolean_t do_contextual;
555  afw_boolean_t do_evaluation_backtrace;
556  afw_boolean_t do_code_backtrace;
557 
559  do_contextual = afw_flag_is_active(
560  xctx->env->flag_index_response_error_contextual, xctx);
561  do_evaluation_backtrace = afw_flag_is_active(
562  xctx->env->flag_index_response_error_backtraceEvaluation, xctx);
563  do_code_backtrace = afw_flag_is_active(
564  xctx->env->flag_index_response_error_backtrace, xctx);
565 
566 
567  evaluation_backtrace = impl_evaluation_backtrace(error, p, xctx);
568 
569  result = afw_utf8_printf(p, xctx,
570  "%s" /* message. */
571  " [code=%s(%d)" /* code-decoded */
572  " rv=%s%s%d%s%s" /* source:rv-decoded */
573 
574  "%s" /* recursive error */
575 
576  "%s%" AFW_UTF8_FMT "%s" /* source location */
577  "%.0" AFW_SIZE_T_FMT
578 
579  "]"
580 
581  "%s%" AFW_UTF8_FMT /* evaluation backtrace */
582 
583  "%s%" AFW_UTF8_FMT, /* code backtrace */
584 
585  /* message. */
586  error->message_z,
587 
588  /* code-decoded */
589  afw_error_code_id_z(error),
590  error->code,
591 
592  /* rv-source-decoded */
593  (error->rv_source_id_z) ? (char *)error->rv_source_id_z : "",
594  (error->rv_source_id_z) ? ":" : "",
595  error->rv,
596  (error->rv_decoded_z) ? "-" : "",
597  (error->rv_decoded_z) ? (char *)error->rv_decoded_z : "",
598 
599  /* recursive error */
600  (!error->recursive_error)
601  ? ""
602  : ((error->recursive_error_in_finally)
603  ? " recursive error in finally"
604  : " recursive error in catch"),
605 
606  /* source location */
607  (do_contextual && error->contextual && error->contextual->source_location)
608  ? " source_location=" : "",
609  (do_contextual && error->contextual && error->contextual->source_location)
610  ? error->contextual->source_location->len : 0,
611  (do_contextual && error->contextual && error->contextual->source_location)
612  ? (char *)error->contextual->source_location->s : "",
613  (do_contextual && error->contextual && error->contextual->value_offset != 0)
614  ? " +" : "",
615  (do_contextual && error->contextual && error->contextual->value_offset != 0)
616  ? error->contextual->value_offset
617  : 0,
618 
619  /* evaluation backtrace */
620  (do_evaluation_backtrace && evaluation_backtrace)
621  ? "\n\nEvaluation backtrace:\n" : "",
622  (do_evaluation_backtrace && evaluation_backtrace)
623  ? evaluation_backtrace->len : 0,
624  (do_evaluation_backtrace && evaluation_backtrace)
625  ? (char *)evaluation_backtrace->s : "",
626 
627  /* code backtrace */
628  (do_code_backtrace && error->backtrace) ? "\nCode backtrace:\n" : "",
629  (do_code_backtrace && error->backtrace) ? error->backtrace->len : 0,
630  (do_code_backtrace && error->backtrace) ? (char *)error->backtrace->s : ""
631  );
632 
633  return result;
634 }
635 
636 
637 
638 AFW_DEFINE(void)
640  const afw_error_t *error, afw_xctx_t *xctx)
641 {
642  const afw_utf8_t *s;
643 
644  if (error->contextual && error->contextual->source_location)
645  {
646  afw_log_write_fz(xctx->env->log,
647  priority,
648  afw_error_source_file(error),
649  xctx,
650  "%s [%" AFW_UTF8_FMT "%s%0d]",
651  error->message_z,
652  AFW_UTF8_FMT_ARG(error->contextual->source_location),
653  (error->contextual && error->contextual->value_offset != 0) ? " +" : "",
654  (error->contextual && error->contextual->value_offset != 0)
655  ? error->contextual->value_offset
656  : 0
657  );
658  }
659 
660  else {
661  afw_log_write_fz(xctx->env->log,
662  priority,
663  afw_error_source_file(error),
664  xctx,
665  "%s",
666  error->message_z);
667  }
668 
669  if (true ) {
670  s = afw_error_to_utf8(error, xctx->p, xctx);
671  afw_log_write(xctx->env->log,
673  s, xctx);
674  }
675 }
676 
677 
678 AFW_DEFINE(int)
679 afw_error_print(FILE *fp, const afw_error_t *error)
680 {
681  afw_integer_t line;
682  const afw_utf8_octet_t *c;
683  const afw_utf8_octet_t *end;
684  const afw_utf8_octet_t *last_nl;
685  afw_utf8_t value_source;
686  int rv;
687 
688  rv = fprintf(fp, "error type: %s\n", afw_error_code_id_z(error));
689  if (rv < 0) goto return_rv;
690  rv = fprintf(fp, "error type #: %d\n", error->code);
691  if (rv < 0) goto return_rv;
692  rv = fprintf(fp, "error source: %s\n", afw_error_source_file(error));
693  if (rv < 0) goto return_rv;
694  if (error->rv_source_id_z) {
695  rv = fprintf(fp, "rv source: %s\n", error->rv_source_id_z);
696  if (rv < 0) goto return_rv;
697  }
698  if (error->rv) {
699  rv = fprintf(fp, "rv: %d\n", error->rv);
700  if (rv < 0) goto return_rv;
701  }
702  if (error->rv_decoded_z) {
703  rv = fprintf(fp, "rv decoded: %s\n", error->rv_decoded_z);
704  if (rv < 0) goto return_rv;
705  }
706  rv = fprintf(fp, "message: %s\n", error->message_z);
707  if (rv < 0) goto return_rv;
708 
709  /* recursive error */
710  if (error->recursive_error) {
711  if (error->recursive_error_in_finally) {
712  rv = fprintf(fp, "recursive error: in finally\n");
713  }
714  else {
715  rv = fprintf(fp, "recursive error: in catch\n");
716  }
717  if (rv < 0) goto return_rv;
718  }
719 
720  if (error->contextual) {
721  afw_value_contextual_resolve_value_source(&value_source,
722  error->contextual);
723 
724  rv = fprintf(fp, "\ncontextual:\n");
725  if (rv < 0) goto return_rv;
726  if (error->contextual->source_location) {
727  rv = fprintf(fp, " source: %" AFW_UTF8_FMT "\n",
728  AFW_UTF8_FMT_ARG(error->contextual->source_location));
729  if (rv < 0) goto return_rv;
730  }
731 
732  rv = fprintf(fp, " offset: %" AFW_SIZE_T_FMT "\n",
733  error->contextual->value_offset);
734  if (rv < 0) goto return_rv;
735 
736  if (value_source.len != 0) {
737  rv = fprintf(fp, " around: %" AFW_UTF8_FMT "\n",
738  AFW_UTF8_FMT_ARG(&value_source));
739  if (rv < 0) goto return_rv;
740 
741  c = value_source.s;
742  end = c + (error->contextual->value_offset < value_source.len ?
743  error->contextual->value_offset : value_source.len);
744  last_nl = c;
745  line = 0;
746  for (; c < end; c++)
747  {
748  if (*c == '\n') {
749  line++;
750  last_nl = c;
751  }
752  }
753  if (line != 1) {
754  line++;
755  rv = fprintf(fp, " line: %" AFW_INTEGER_FMT "\n", line);
756  if (rv < 0) goto return_rv;
757  rv = fprintf(fp, " column: %" AFW_INTEGER_FMT "\n",
758  (afw_integer_t)(end - last_nl));
759  if (rv < 0) goto return_rv;
760  }
761  }
762  }
763 
764  if (error->parser_cursor > 0) {
765  rv = fprintf(fp, " cursor: %" AFW_INTEGER_FMT "\n",
766  (afw_integer_t)error->parser_cursor);
767  if (rv < 0) goto return_rv;
768  }
769 
770  if (error->backtrace) {
771  rv = fprintf(fp, "\nbacktrace:\n%" AFW_UTF8_FMT "\n",
772  AFW_UTF8_FMT_ARG(error->backtrace));
773  if (rv < 0) goto return_rv;
774  }
775 
776 return_rv:
777 
778  return rv;
779 }
780 
781 
782 AFW_DEFINE(int)
784  FILE *fp,
785  const afw_error_t *error,
786  const afw_pool_t *p,
787  afw_xctx_t *xctx)
788 {
789  int rv;
790  const afw_utf8_t *backtraceExpression;
791 
792  rv = afw_error_print(fp, error);
793  if (rv < 0) return rv;
794 
795  if (afw_flag_is_active(
796  xctx->env->flag_index_response_error_backtraceEvaluation,
797  xctx))
798  {
799  backtraceExpression = impl_evaluation_backtrace(error, p, xctx);
800  if (backtraceExpression && backtraceExpression->len > 0) {
801  rv = fprintf(fp, "evaluation backtrace:\n");
802  if (rv < 0) return rv;
803  rv = (int)fwrite(backtraceExpression->s, 1, backtraceExpression->len,
804  fp);
805  }
806  }
807  return rv;
808 }
809 
810 
811 
812 static void
813 impl_add_contextual(
814  const afw_object_t *object,
815  const afw_compile_value_contextual_t *contextual,
816  const afw_pool_t *p, afw_xctx_t *xctx)
817 {
818  afw_integer_t line;
819  const afw_utf8_octet_t *c;
820  const afw_utf8_octet_t *end;
821  const afw_utf8_octet_t *last_nl;
822  afw_utf8_t value_source;
823 
824  if (contextual->source_location) {
826  &afw_s_sourceLocation,
827  contextual->source_location, xctx);
828  }
829 
830  afw_value_contextual_resolve_value_source(&value_source, contextual);
831  if (value_source.len > 0) {
832 
834  &afw_s_offset, (afw_integer_t)contextual->value_offset, xctx);
835  line = 0;
836  c = value_source.s;
837  end = c + (contextual->value_offset < value_source.len ?
838  contextual->value_offset : value_source.len);
839  last_nl = c;
840  for (;
841  c < end;
842  c++)
843  {
844  if (*c == '\n') {
845  line++;
846  last_nl = c;
847  }
848  }
849  if (line != 1) {
850  line++;
852  &afw_s_line, line, xctx);
854  &afw_s_column, (afw_integer_t)(end - last_nl), xctx);
855  }
856  }
857 }
858 
859 
860 /* Add error info to an existing object. */
861 AFW_DECLARE(void)
863  const afw_object_t *object,
864  const afw_error_t *error,
865  afw_xctx_t *xctx)
866 {
867  const afw_pool_t *p = xctx->p;
868  const afw_utf8_t *evaluation_backtrace;
869  afw_size_t source_line;
870  afw_size_t source_column;
871 
872  /* If there is contextual information, add it. */
873  if (error->contextual) {
874  impl_add_contextual(object, error->contextual,
875  p, xctx);
876  }
877 
878  /* Contextual. */
879  if (afw_flag_is_active(
880  xctx->env->flag_index_response_error_contextual, xctx))
881  {
882  if (error->contextual) {
883  impl_add_contextual(object, error->contextual,
884  p, xctx);
885  }
887  &afw_s_errorSource,
889  afw_error_source_file(error),
890  AFW_UTF8_Z_LEN, p, xctx),
891  xctx);
892  }
893 
894 
895  /* Backtrace. */
896  if (error->backtrace &&
898  xctx->env->flag_index_response_error_backtrace, xctx))
899  {
901  &afw_s_backtrace, error->backtrace, xctx);
902  }
903 
904  /* Evaluation backtrace. */
905  if (afw_flag_is_active(
906  xctx->env->flag_index_response_error_backtraceEvaluation, xctx))
907  {
908  evaluation_backtrace = impl_evaluation_backtrace(error, p, xctx);
909  if (evaluation_backtrace) {
911  &afw_s_backtraceEvaluation, evaluation_backtrace, xctx);
912  }
913  }
914 
915 
916  /* Add properties to object. */
917 
918  afw_object_set_property(object, &afw_s_error, afw_value_true, xctx);
919 
921  &afw_s_errorCode, error->code, xctx);
922 
923 
924  /* If parser source available, set appropriate properties. */
925  if (error->parser_source) {
927  &afw_s_parserCursor,
928  (afw_integer_t)error->parser_cursor,
929  xctx);
931  &afw_s_parserSource, error->parser_source, xctx);
933  &source_line, &source_column,
934  error->parser_source, error->parser_cursor, 4, xctx);
936  &afw_s_parserLineNumber, source_line, xctx);
938  &afw_s_parserColumnNumber, source_column, xctx);
939  }
940 
941  else if (error->parser_cursor > 0) {
943  &afw_s_parserCursor,
944  (afw_integer_t)error->parser_cursor,
945  xctx);
946  }
947 
949  &afw_s_errorCodeId,
951  AFW_UTF8_Z_LEN, p, xctx),
952  xctx);
953 
954  if (error->rv_source_id_z) {
956  &afw_s_rvSourceId,
957  afw_utf8_create_copy(error->rv_source_id_z,
958  AFW_UTF8_Z_LEN, p, xctx),
959  xctx);
960  }
961 
962  if (error->rv) {
964  &afw_s_rv, error->rv, xctx);
965  }
966 
967  if (error->rv_decoded_z) {
969  &afw_s_rvDecoded,
970  afw_utf8_create_copy(error->rv_decoded_z,
971  AFW_UTF8_Z_LEN, p, xctx),
972  xctx);
973  }
974 
976  &afw_s_message,
977  afw_utf8_create_copy(error->message_z,
978  AFW_UTF8_Z_LEN, p, xctx),
979  xctx);
980 
981  if (error->recursive_error) {
983  &afw_s_recursiveError,
984  (error->recursive_error_in_finally)
985  ? &afw_s_a_in_finally
986  : &afw_s_a_in_catch,
987  xctx);
988  }
989 
990 
992  &afw_s_xctxUUID, xctx->uuid, xctx);
993 }
994 
995 
996 /* Create an object with error info in specified pool. */
997 AFW_DECLARE(const afw_object_t *)
999  const afw_error_t *error,
1000  const afw_pool_t *p, afw_xctx_t *xctx)
1001 {
1002  const afw_object_t *result;
1003 
1004  result = afw_object_create_managed(p, xctx);
1005  afw_error_add_to_object(result, error, xctx);
1006 
1007  return result;
1008 }
1009 
1010 
1011 AFW_DEFINE(const afw_utf8_z_t *)
1013  const afw_utf8_z_t *format, va_list ap, afw_xctx_t *xctx)
1014 {
1015  vsnprintf((char *)&(xctx->error->message_wa[0]),
1016  sizeof(xctx->error->message_wa), (const char *)format, ap);
1017 
1018  return &(xctx->error->message_wa[0]);
1019 }
1020 
1021 
1024  afw_xctx_t *xctx, const afw_utf8_z_t *format, ...)
1025 {
1026  va_list ap;
1027 
1028  va_start(ap, format);
1029 
1030  vsnprintf((char *)&(xctx->error->message_wa[0]),
1031  sizeof(xctx->error->message_wa), (const char *)format, ap);
1032 
1033  va_end(ap);
1034 
1035  return &(xctx->error->message_wa[0]);
1036 }
1037 
1038 
1039 /* Returns http status for error. */
1040 AFW_DEFINE(const afw_utf8_t *)
1042 {
1043  const afw_utf8_t *result;
1044 
1045  result = NULL;
1046 
1047  if (error->code < sizeof(impl_error_code_map)
1048  / sizeof(impl_error_code_map_t) &&
1049  error->code >= 0)
1050  {
1051  result = &impl_error_code_map[error->code].html_description;
1052  }
1053 
1054  if (!result) result = &impl_s_a_html_unknown;
1055 
1056  return result;
1057 }
1058 
1059 
1060 /* Returns error->code description. */
1061 AFW_DEFINE(const afw_utf8_z_t *)
1063 {
1064  const afw_utf8_z_t *result;
1065 
1066  result = NULL;
1067 
1068  if (error->code < sizeof(impl_error_code_map)
1069  / sizeof(impl_error_code_map_t) &&
1070  error->code >= 0)
1071  {
1072  result = impl_error_code_map[error->code].id.s;
1073  }
1074 
1075  if (!result) result = "unknown";
1076 
1077  return result;
1078 }
1079 
1080 
1083  if (code < sizeof(impl_error_code_map) / sizeof(impl_error_code_map_t) &&
1084  code >= 0)
1085  {
1086  return impl_error_code_map[code].error_allow_in_response;
1087  }
1088  else {
1089  return false;
1090  }
1091 }
AFW_DEFINE(const afw_object_t *)
#define AFW_DEFINE_ELLIPSIS(type)
Define a public afw function with variable arguments.
#define AFW_DECLARE(type)
Declare a public afw function.
Adaptive Framework Core Internal.
afw_object_set_property_as_integer(const afw_object_t *object, const afw_utf8_t *property_name, afw_integer_t internal, afw_xctx_t *xctx)
Set property function for data type integer values.
afw_object_set_property_as_string(const afw_object_t *object, const afw_utf8_t *property_name, const afw_utf8_t *internal, afw_xctx_t *xctx)
Set property function for data type string values.
#define AFW_UTF8_FMT_ARG(A_STRING)
Convenience Macro for use with AFW_UTF8_FMT to specify arg.
Definition: afw_common.h:605
#define AFW_UTF8_Z_LEN
String is NUL (0) terminate.
Definition: afw_common.h:266
#define AFW_UTF8_LITERAL(A_STRING)
String literal initializer.
Definition: afw_common.h:582
#define AFW_SIZE_T_MAX_BUFFER
this is the maximum number of digits that can be produced by afw_size_t plus null terminator.
Definition: afw_common.h:362
#define AFW_INTEGER_FMT
Format string specifier used for afw_integer_t.
Definition: afw_common.h:326
_Bool afw_boolean_t
Definition: afw_common.h:373
enum afw_error_code_e afw_error_code_t
#define AFW_UTF8_FMT
Format string specifier used for afw_utf8_t.
Definition: afw_common.h:588
afw_utf8_octet_t afw_utf8_z_t
NFC normalized UTF-8 null terminated string.
Definition: afw_common.h:523
char afw_utf8_octet_t
8 bits of utf-8 codepoint.
Definition: afw_common.h:236
apr_size_t afw_size_t
size_t.
Definition: afw_common.h:151
#define AFW_SIZE_T_FMT
Format string specifier used for afw_size_t.
Definition: afw_common.h:341
enum afw_log_priority_e afw_log_priority_t
Log levels. See afw_log.h for more information.
#define AFW_ERROR_CODE_MAP(XX)
Error code map. IMPORTANT>>> Do not change the order of these entries. The order must match the order...
Definition: afw_common.h:896
#define AFW_INTEGER_MAX_BUFFER
this is the maximum number of digits that can be produced by afw_integer_t plus negative sign plus nu...
Definition: afw_common.h:275
apr_int64_t afw_integer_t
typedef for big signed int.
Definition: afw_common.h:321
@ afw_log_priority_debug
Definition: afw_common.h:989
const afw_utf8_z_t *(* afw_environment_error_rv_decoder_z_t)(int rv, afw_utf8_z_t *wa, afw_size_t wa_size)
Typedef for error rv decoder functions.
afw_environment_error_rv_decoder_z_t afw_environment_get_error_rv_decoder(const afw_utf8_t *rv_source_id, afw_xctx_t *xctx)
Get the error rv decoder function associated with rv_source_id.
afw_error_http_status(const afw_error_t *error)
Returns http status for error.
Definition: afw_error.c:1041
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.
Definition: afw_error.c:783
afw_error_print(FILE *fp, const afw_error_t *error)
Print error.
Definition: afw_error.c:679
afw_error_write_log(afw_log_priority_t priority, const afw_error_t *error, afw_xctx_t *xctx)
Write error to environment log.
Definition: afw_error.c:639
afw_error_code_id_z(const afw_error_t *error)
Returns error->code id.
Definition: afw_error.c:1062
void afw_error_add_to_object(const afw_object_t *object, const afw_error_t *error, afw_xctx_t *xctx)
Add error info to existing object using specified pool.
Definition: afw_error.c:862
afw_error_message(afw_xctx_t *xctx, const afw_utf8_z_t *format,...)
Build message in xctx error message_wa and return pointer.
Definition: afw_error.c:1023
afw_error_to_utf8(const afw_error_t *error, const afw_pool_t *p, afw_xctx_t *xctx)
Convert error to utf8.
Definition: afw_error.c:547
#define afw_error_source_file(error)
Returns value of error->source_z after last '/ 'or '\'.
Definition: afw_error.h:879
afw_error_allow_in_response(afw_error_code_t code)
Determine if the error object for code is allowed in HTTP response.
Definition: afw_error.c:1082
const afw_object_t * afw_error_to_object(const afw_error_t *error, const afw_pool_t *p, afw_xctx_t *xctx)
Create an object with error info in specified pool.
Definition: afw_error.c:998
afw_error_message_vz(const afw_utf8_z_t *format, va_list ap, afw_xctx_t *xctx)
Build message in xctx error message_wa and return pointer.
Definition: afw_error.c:1012
#define afw_flag_is_active(flag_index, xctx)
Determine if flag for flag index is set in xctx.
Definition: afw_flag.h:84
#define afw_log_write(instance, priority, source_z, message, xctx)
Call method write of interface afw_log.
void afw_log_write_fz(const afw_log_t *instance, afw_log_priority_t priority, const afw_utf8_z_t *source_z, afw_xctx_t *xctx, const afw_utf8_z_t *format_z,...)
Log an message using a printf style format and parameters.
Definition: afw_log.h:249
afw_number_bytes_needed_size_t(afw_size_t i)
Determine bytes needed to hold printable size_t.
Definition: afw_number.c:425
#define afw_object_create_managed(p, xctx)
Create an empty entity object in its own pool.
Definition: afw_object.h:913
afw_object_set_property(const afw_object_t *instance, const afw_utf8_t *property_name, const afw_value_t *value, afw_xctx_t *xctx)
Set the value of an object's property.
Definition: afw_object.c:46
const afw_utf8_t * afw_os_backtrace(afw_error_code_t code, int max_backtrace, afw_xctx_t *xctx)
Provide a backtrace if possible.
Definition: nix/afw_os.c:729
#define afw_stack_is_empty(instance)
Determine is a stack is empty.
Definition: afw_stack.h:157
void afw_utf8_writer_current_string(const afw_writer_t *writer, afw_utf8_t *current_string, afw_xctx_t *xctx)
Get the current string in a UTF-8 writer.
#define afw_utf8_create_copy(s, len, p, xctx)
Make a utf-8 sting from chars in pool specified.
Definition: afw_utf8.h:369
afw_utf8_line_column_of_offset(afw_size_t *line_number, afw_size_t *column_number, const afw_utf8_t *s, afw_size_t offset, int tab_size, afw_xctx_t *xctx)
Determine the line and column of an offset in a string.
Definition: afw_utf8.c:1058
afw_utf8_line_count_and_max_column(afw_size_t *number_of_lines, afw_size_t *max_column_number, const afw_utf8_t *s, int tab_size, afw_xctx_t *xctx)
Determine the line count and maximum column in a string.
Definition: afw_utf8.c:1111
const afw_writer_t * afw_utf8_writer_create(const afw_utf8_t *tab, const afw_pool_t *p, afw_xctx_t *xctx)
Create UTF-8 writer.
afw_utf8_printf(const afw_pool_t *p, afw_xctx_t *xctx, const afw_utf8_z_t *format,...)
Create a utf-8 string using a c format string in specified pool.
Definition: afw_utf8.c:459
#define afw_utf8_create(s, len, p, xctx)
Create utf-8 string without copy unless necessary in pool specified.
Definition: afw_utf8.h:239
#define afw_value_get_info(instance, info, p, xctx)
Call method get_info of interface afw_value.
afw_value_true
Adaptive value true.
Definition: afw_value.h:348
#define afw_writer_write(instance, buffer, size, xctx)
Call method write of interface afw_writer.
#define afw_writer_release(instance, xctx)
Call method release of interface afw_writer.
#define afw_writer_write_eol(instance, xctx)
Call method write_eol of interface afw_writer.
#define afw_writer_write_z(writer, s_z, xctx)
Call afw_writer_write() with zero terminated string.
Definition: afw_writer.h:35
#define afw_writer_write_utf8(writer, S, xctx)
Call afw_writer_write() with a afw_utf8_t string.
Definition: afw_writer.h:45
Contextual information provided in some values.
afw_size_t value_size
Size in full_source of value source.
const afw_utf8_t * source_location
Source location.
const afw_value_compiled_value_t * compiled_value
Compiled value this value is part of.
afw_size_t value_offset
Offset in full source of compiled value to this value.
Adaptive Framework Error.
Definition: afw_error.h:65
afw_error_code_t code
Error code.
Definition: afw_error.h:74
const afw_utf8_z_t * rv_source_id_z
This is the source of the non-zero rv.
Definition: afw_error.h:86
const afw_utf8_z_t * message_z
Message.
Definition: afw_error.h:80
const afw_utf8_t * backtrace
If not memory error and afw_os_backtrace() supplies one.
Definition: afw_error.h:92
int rv
If non-zero, this is rc, rv, or any int value related to error.
Definition: afw_error.h:112
const afw_utf8_t * parser_source
If syntax error, this is partial/full source or NULL.
Definition: afw_error.h:109
afw_utf8_z_t decode_rv_wa[23]
Place to optionally hold rv_decoded_z.
Definition: afw_error.h:123
const afw_utf8_z_t * source_z
File:line in source error was thrown.
Definition: afw_error.h:77
const afw_utf8_z_t * rv_decoded_z
Human readable decode of rv.
Definition: afw_error.h:89
afw_utf8_z_t message_wa[255]
Place to optionally hold message_z.
Definition: afw_error.h:129
afw_size_t parser_cursor
If syntax error, this is cursor when parse error occurred or 0.
Definition: afw_error.h:101
Interface afw_object public struct.
Interface afw_pool public struct.
NFC normalized UTF-8 string.
Definition: afw_common.h:545
Filled in by afw_value get_info method.
Definition: afw_value.h:49
const afw_utf8_t * full_source_type
The type of the full source.
const afw_utf8_t * full_source
The full source that was compiled.
Interface afw_writer public struct.
Interface afw_xctx public struct.