LaTeXML

 view release on metacpan or  search on metacpan

lib/LaTeXML/Common/Error.pm  view on Meta::CPAN


sub Fatal {
  my ($category, $object, $where, $message, @details) = @_;

# Check if this is a known unsafe fatal and flag it if so (so that we reinitialize in daemon contexts)
  if ((($category eq 'internal') && ($object eq '<recursion>')) ||
    ($category eq 'too_many_errors') ||
    ($object eq 'deep_recursion')    || ($object eq 'die')) {
    $LaTeXML::UNSAFE_FATAL = 1; }

  # We'll assume that if the DIE handler is bound (presumably to this function)
  # we're in the outermost call to Fatal; we'll clear the handler so that we don't nest calls.
  die $DIE_MESSAGE if $LaTeXML::IGNORE_ERRORS    # Short circuit, w/no formatting, if in probing eval
    || (($SIG{__DIE__} eq 'DEFAULT') && $^S);    # Also missing class when parsing bindings(?!?!)

  my $inhandler = !$SIG{__DIE__};
  my $ineval    = 0;                             # whether we're in an eval should no longer matter!

  # This seemingly should be "local", but that doesn't seem to help with timeout/alarm/term?
  # It should be safe so long as the caller has bound it and rebinds it if necessary.
  local $SIG{__DIE__} = 'DEFAULT';    # Avoid recursion while preparing the message.
  my $state = $STATE;

  if (!$inhandler) {
    local $LaTeXML::BAILOUT = $LaTeXML::BAILOUT;
    if (checkRecursiveError()) {
      $LaTeXML::BAILOUT = 1;
      push(@details, "Recursive Error!"); }
    $state->noteStatus('fatal') if $state && !$ineval;
    my $detail_level = (($VERBOSITY <= 1) && ($category =~ /^(?:timeout|too_many_errors)$/)) ? 0 : 2;
    $message
      = generateMessage(colorizeString("Fatal:" . $category . ":" . ToString($object), 'fatal'),
      $where, $message, $detail_level, @details);
    # If we're about to (really) DIE, we'll bypass the usual status message, so add it here.
    # This really should be handled by the top-level program,
    # after doing all processing within an eval
    # BIZARRE: Note that die adds the "at <file> <line>" stuff IFF the message doesn't end w/ CR!
####    $message .= $state->getStatusMessage . "\n" if $state && !$ineval;
  }
  else {    # If we ARE in a recursive call, the actual message is $details[0]
    $message = $details[0] if $details[0]; }
  # inhibit message to STDERR, since die will handle that
  _printlines($message);
  hardYankProcessing();
  # Now that we have yanked the processing state, ignore any following errors
  $LaTeXML::IGNORE_ERRORS = 1;

  # If inside an eval, this won't actually die, but WILL set $@ for caller's use.
  die $DIE_MESSAGE; }

sub hardYankProcessing {
  my $state = $STATE;
  # Nothing we can do if we are called without a global $STATE bound
  return unless $state;
  # Ensure we have nothing else to do in the main processing.
  # NOTE: this recovery procedure must always be run after all logging messages are generated,
  #       as resetting the various stacks loses information (e.g. location is lost).
  my $stomach = $$state{stomach};
  my $gullet  = $$stomach{gullet};
  $$stomach{token_stack} = [];
  # If we were in an infinite loop, disable any potential busy token.
  my $relax_def = $$state{meaning}{"\\relax"}[0];
  $state->assignMeaning($LaTeXML::CURRENT_TOKEN, $relax_def, 'global') if $LaTeXML::CURRENT_TOKEN;
  for my $token (@{ $$gullet{pushback} }) {
    $state->assignMeaning($token, $relax_def, 'global'); }
  # Rescue data structures that may be serializable/resumable
  if (@LaTeXML::LIST) {
    $$stomach{rescued_boxes} = [@LaTeXML::LIST];
    @LaTeXML::LIST = ();
  }
  if ($LaTeXML::DOCUMENT) {
    $$state{rescued_document} = $LaTeXML::DOCUMENT; }
  # avoid looping at \end{document}, Fatal brings us back to the doc level
  $state->assignValue('current_environment', undef, 'global');
  # then reset the gullet
  $$gullet{pushback}         = [];
  $$gullet{mouthstack}       = [];
  $$gullet{pending_comments} = [];
  $$gullet{mouth}            = LaTeXML::Core::Mouth->new();
  return; }

sub checkRecursiveError {
  my @caller;
  for (my $frame = 2 ; @caller = caller($frame) ; $frame++) {
    if ($caller[3] =~ /^LaTeXML::(Global::ToString|Global::Stringify)$/) {
      #      print STDERR "RECURSED ON $caller[3]\n";
      return 1; } }
  return; }

# Should be fatal if strict is set, else warn.
sub Error {
  my ($category, $object, $where, $message, @details) = @_;
  return if $LaTeXML::IGNORE_ERRORS;
  my $state = $STATE;
  $state && $state->noteStatus('error');
  if ($state && $state->lookupValue('STRICT')) {
    Fatal($category, $object, $where, $message, @details); }
  else {
    my $formatted = generateMessage("Error:" . $category . ":" . ToString($object),
      $where, $message, 1, @details);
    _printline($formatted); }
  # Note that "100" is hardwired into TeX, The Program!!!
  my $maxerrors = ($state ? $state->lookupValue('MAX_ERRORS') : 100);
  if ($state && (defined $maxerrors) && (($state->getStatus('error') || 0) > $maxerrors)) {
    Fatal('too_many_errors', $maxerrors, $where, "Too many errors (> $maxerrors)!"); }
  return; }

# Warning message; results may be OK, but somewhat unlikely
sub Warn {
  my ($category, $object, $where, $message, @details) = @_;
  return if $LaTeXML::IGNORE_ERRORS;
  my $state = $STATE;
  $state && $state->noteStatus('warning');
  my $formatted = generateMessage("Warning:" . $category . ":" . ToString($object),
    $where, $message, 0, @details);
  _printline($formatted);
  return; }

# Informational message; results likely unaffected
# but the message may give clues about subsequent warnings or errors
sub Info {



( run in 0.724 second using v1.01-cache-2.11-cpan-39bf76dae61 )