1  /* Copyright 2010-2023 Free Software Foundation, Inc.
       2  
       3     This program is free software: you can redistribute it and/or modify
       4     it under the terms of the GNU General Public License as published by
       5     the Free Software Foundation, either version 3 of the License, or
       6     (at your option) any later version.
       7  
       8     This program is distributed in the hope that it will be useful,
       9     but WITHOUT ANY WARRANTY; without even the implied warranty of
      10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      11     GNU General Public License for more details.
      12  
      13     You should have received a copy of the GNU General Public License
      14     along with this program.  If not, see <http://www.gnu.org/licenses/>. */
      15  
      16  #include <config.h>
      17  #include <stdlib.h>
      18  
      19  #include "debug.h"
      20  #include "context_stack.h"
      21  #include "commands.h"
      22  #include "errors.h"
      23  
      24  static enum context *context_stack;
      25  static size_t top; /* One above last pushed context. */
      26  static size_t space;
      27  
      28  /* Kept in sync with context_stack. */
      29  static COMMAND_STACK command_stack;
      30  
      31  /* Generic command stack functions */
      32  
      33  void
      34  reset_command_stack (COMMAND_STACK *stack)
      35  {
      36    stack->top = 0;
      37    stack->space = 0;
      38    free (stack->stack);
      39    stack->stack = 0;
      40  }
      41  
      42  void
      43  push_command (COMMAND_STACK *stack, enum command_id cmd)
      44  {
      45    if (stack->top >= stack->space)
      46      {
      47        stack->stack
      48          = realloc (stack->stack,
      49                     (stack->space += 5) * sizeof (enum command_id));
      50      }
      51  
      52    stack->stack[stack->top] = cmd;
      53    stack->top++;
      54  }
      55  
      56  enum command_id
      57  pop_command (COMMAND_STACK *stack)
      58  {
      59    if (stack->top == 0)
      60      fatal ("command stack empty");
      61  
      62    return stack->stack[--stack->top];
      63  }
      64  
      65  enum command_id
      66  top_command (COMMAND_STACK *stack)
      67  {
      68    if (stack->top == 0)
      69      fatal ("command stack empty for top");
      70  
      71    return stack->stack[stack->top - 1];
      72  }
      73  
      74  enum command_id
      75  current_context_command (void)
      76  {
      77    int i;
      78  
      79    if (top == 0)
      80      return CM_NONE;
      81    for (i = top -1; i >= 0; i--)
      82      {
      83        if (command_stack.stack[i] != CM_NONE)
      84          return command_stack.stack[i];
      85      }
      86    return CM_NONE;
      87  }
      88  
      89  /* Context stacks */
      90  
      91  void
      92  reset_context_stack (void)
      93  {
      94    top = 0;
      95    reset_command_stack (&command_stack);
      96  }
      97  
      98  char *
      99  context_name (enum context c)
     100  {
     101    return c == ct_preformatted ? "ct_preformatted"
     102           : c == ct_line ? "ct_line"
     103           : c == ct_def ? "ct_def"
     104           : c == ct_brace_command ? "ct_brace_command"
     105           : "";
     106  }
     107  
     108  void
     109  push_context (enum context c, enum command_id cmd)
     110  {
     111    if (top >= space)
     112      context_stack = realloc (context_stack,
     113                               (space += 5) * sizeof (enum context));
     114  
     115    /* debug not in perl parser
     116    debug (">>>>>>>>>>>>>>>>>PUSHING STACK AT %d  -- %s @%s", top,
     117           context_name (c), command_name(cmd));
     118     */
     119    context_stack[top] = c;
     120    top++;
     121  
     122    push_command (&command_stack, cmd);
     123  }
     124  
     125  enum context
     126  pop_context ()
     127  {
     128    if (top == 0)
     129      fatal ("context stack empty");
     130  
     131    (void) pop_command (&command_stack);
     132  
     133    /* debug not in perl parser
     134    debug (">>>>>>>>>>>>>POPPING STACK AT %d", top - 1);
     135     */
     136    return context_stack[--top];
     137  }
     138  
     139  enum context
     140  current_context (void)
     141  {
     142    if (top == 0)
     143      return ct_NONE;
     144  
     145    return context_stack[top - 1];
     146  }
     147  
     148  int
     149  in_context (enum context context)
     150  {
     151    int i;
     152  
     153    if (top == 0)
     154      return 0;
     155  
     156    for (i = 0; i < top; i++)
     157      {
     158        if (context_stack[i] == context)
     159          return 1;
     160      }
     161    return 0;
     162  }
     163  
     164  
     165  
     166  /* Command nesting context. */
     167  
     168  NESTING_CONTEXT nesting_context;
     169  
     170  
     171  
     172  /* used for @kbd */
     173  int
     174  in_preformatted_context_not_menu()
     175  {
     176    int i;
     177  
     178    if (top == 0)
     179      return 0;
     180    for (i = top -1; i >= 0; i--)
     181      {
     182        enum context ct;
     183        enum command_id cmd;
     184        ct = context_stack[i];
     185        if (ct != ct_line && ct != ct_preformatted)
     186          return 0;
     187        cmd = command_stack.stack[i];
     188        if (command_data(cmd).flags & CF_block
     189            && command_data(cmd).data != BLOCK_menu
     190            && ct == ct_preformatted)
     191          return 1;
     192      }
     193    return 0;
     194  }