home *** CD-ROM | disk | FTP | other *** search
/ HyperLib 1997 Winter - Disc 1 / HYPERLIB-1997-Winter-CD1.ISO.7z / HYPERLIB-1997-Winter-CD1.ISO / オンラインウェア / PRG / bwbasic-2.10.sit / bwbasic-2.10 / bwbasic.c < prev    next >
Text File  |  1993-11-09  |  33KB  |  1,451 lines

  1. /***************************************************************
  2.  
  3.         bwbasic.c       Main Program File
  4.                         for Bywater BASIC Interpreter
  5.  
  6.                         Copyright (c) 1993, Ted A. Campbell
  7.                         Bywater Software
  8.  
  9.             "I was no programmer, neither was I a
  10.             programmer's son; but I was an herdman
  11.             and a gatherer of sycomore fruit."
  12.                  - Amos 7:14b AV, slightly adapted
  13.  
  14.                         email: tcamp@delphi.com
  15.  
  16.         Copyright and Permissions Information:
  17.  
  18.         All U.S. and international rights are claimed by the author,
  19.         Ted A. Campbell.
  20.  
  21.     This software is released under the terms of the GNU General
  22.     Public License (GPL), which is distributed with this software
  23.     in the file "COPYING".  The GPL specifies the terms under
  24.     which users may copy and use the software in this distribution.
  25.  
  26.     A separate license is available for commercial distribution,
  27.     for information on which you should contact the author.
  28.  
  29. ***************************************************************/
  30.  
  31. #include <stdio.h>
  32. #include <ctype.h>
  33. #include <math.h>
  34.  
  35. #include "bwbasic.h"
  36. #include "bwb_mes.h"
  37.  
  38. #if HAVE_SIGNAL
  39. #include <signal.h>
  40. #endif
  41.  
  42. #if HAVE_LONGJUMP
  43. #include <setjmp.h>
  44. #endif
  45.  
  46. char *bwb_ebuf;                /* error buffer */
  47. static char *read_line;
  48. int bwb_trace = FALSE;
  49. FILE *errfdevice = stderr;              /* output device for error messages */
  50.  
  51. #if HAVE_LONGJUMP
  52. jmp_buf mark;
  53. #endif
  54.  
  55. static int program_run = 0;        /* has the command-line program been run? */
  56. int bwb_curtask = 0;            /* current task */
  57.  
  58. struct bwb_variable *ed;                /* BWB.EDITOR$ variable */
  59. struct bwb_variable *fi;                /* BWB.FILES$ variable */
  60. struct bwb_variable *pr;                /* BWB.PROMPT$ variable */
  61. struct bwb_variable *im;                /* BWB.IMPLEMENTATION$ variable */
  62. struct bwb_variable *co;                /* BWB.COLORS variable */
  63.  
  64. #if PARACT
  65. struct bwb_task *bwb_tasks[ TASKS ];    /* table of task pointers */
  66. #else
  67. char progfile[ MAXARGSIZE ];        /* program file */
  68. int rescan = TRUE;                      /* program needs to be rescanned */
  69. int number = 0;                /* current line number */
  70. struct bwb_line *bwb_l;            /* current line pointer */
  71. struct bwb_line bwb_start;        /* starting line marker */
  72. struct bwb_line bwb_end;        /* ending line marker */
  73. struct bwb_line *data_line;         /* current line to read data */
  74. int data_pos = 0;                       /* position in data_line */
  75. struct bwb_variable var_start;        /* variable list start marker */
  76. struct bwb_variable var_end;        /* variable list end marker */
  77. struct bwb_function fnc_start;        /* function list start marker */
  78. struct bwb_function fnc_end;        /* function list end marker */
  79. struct fslte fslt_start;        /* function-sub-label lookup table start marker */
  80. struct fslte fslt_end;            /* function-sub-label lookup table end marker */
  81. int exsc = -1;                /* EXEC stack counter */
  82. int expsc = 0;                /* expression stack counter */
  83. int xtxtsc = 0;                /* eXecute TeXT stack counter */
  84. struct exse *excs;            /* EXEC stack */
  85. struct exp_ese *exps;            /* Expression stack */
  86. struct xtxtsl *xtxts;                   /* Execute Text stack */
  87. #endif
  88.  
  89. /* Prototypes for functions visible only to this file */
  90.  
  91. #if ANSI_C
  92. extern int is_ln( char *buffer );
  93. #else
  94. extern int is_ln();
  95. #endif
  96.  
  97. /***************************************************************
  98.  
  99.         FUNCTION:       bwb_init()
  100.  
  101.         DESCRIPTION:    This function initializes bwBASIC.
  102.  
  103. ***************************************************************/
  104.  
  105. void
  106. #if ANSI_C
  107. bwb_init( int argc, char **argv )
  108. #else
  109. bwb_init( argc, argv )
  110.    int argc;
  111.    char **argv;
  112. #endif
  113.    {
  114.    static FILE *input = NULL;
  115.    register int n;
  116. #if PROFILE
  117.    struct bwb_variable *v;
  118. #endif
  119. #if REDIRECT_STDERR
  120.    FILE *newerr;
  121. #endif
  122. #if PROFILE
  123.    FILE *profile;
  124. #endif
  125. #if PARACT
  126. #else
  127.    static char start_buf[] = "¥0";
  128.    static char end_buf[] = "¥0";
  129. #endif
  130.  
  131. #if INTENSIVE_DEBUG
  132.    prn_xprintf( stderr, "Memory Allocation Statistics:¥n" );
  133.    prn_xprintf( stderr, "----------------------------¥n" );
  134. #if PARACT
  135.    sprintf( bwb_ebuf, "task structure:   %ld bytes¥n",
  136.       (long) sizeof( struct bwb_task ) );
  137.    prn_xprintf( stderr, bwb_ebuf );
  138.    getchar();
  139. #endif
  140. #endif
  141.  
  142.    /* set all task pointers to NULL */
  143.  
  144. #if PARACT
  145.  
  146.    for ( n = 0; n < TASKS; ++n )
  147.       {
  148.       bwb_tasks[ n ] = NULL;
  149.       }
  150.  
  151. #else
  152.  
  153.    /* Memory allocation */
  154.    /* eXecute TeXT stack */
  155.  
  156.    if ( ( xtxts = calloc( XTXTSTACKSIZE, sizeof( struct xtxtsl ) ) ) == NULL )
  157.       {
  158. #if PROG_ERRORS
  159.       bwb_error( "in bwb_init(): failed to find memory for xtxts" );
  160. #else
  161.       bwb_error( err_getmem );
  162. #endif
  163.       }
  164.  
  165.    /* expression stack */
  166.  
  167.    if ( ( exps = calloc( ESTACKSIZE, sizeof( struct exp_ese ) ) ) == NULL )
  168.       {
  169. #if PROG_ERRORS
  170.       bwb_error( "in bwb_init(): failed to find memory for exps" );
  171. #else
  172.       bwb_error( err_getmem );
  173. #endif
  174.       }
  175.  
  176.    /* EXEC stack */
  177.  
  178.    if ( ( excs = calloc( EXECLEVELS, sizeof( struct exse ) ) ) == NULL )
  179.       {
  180. #if PROG_ERRORS
  181.       bwb_error( "in bwb_init(): failed to find memory for excs" );
  182. #else
  183.       bwb_error( err_getmem );
  184. #endif
  185.       }
  186.  
  187.    /* initialize tables of variables, functions */
  188.  
  189.    bwb_start.number = 0;
  190.    bwb_start.next = &bwb_end;
  191.    bwb_end.number = MAXLINENO + 1;
  192.    bwb_end.next = &bwb_end;
  193.    bwb_start.buffer = start_buf;
  194.    bwb_end.buffer = end_buf;
  195.    data_line = &bwb_start;
  196.    data_pos = 0;
  197.    exsc = -1;
  198.    expsc = 0;
  199.    xtxtsc = 0;
  200.    bwb_start.position = 0;
  201.    bwb_l = &bwb_start; 
  202.  
  203.    var_init( 0 );
  204.    fnc_init( 0 );
  205.    fslt_init( 0 );
  206.  
  207. #endif
  208.  
  209.    /* character buffers */
  210.  
  211.    if ( ( bwb_ebuf = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  212.       {
  213. #if PROG_ERRORS
  214.       bwb_error( "in bwb_init(): failed to find memory for bwb_ebuf" );
  215. #else
  216.       bwb_error( err_getmem );
  217. #endif
  218.       }
  219.    if ( ( read_line = calloc( MAXREADLINESIZE + 1, sizeof(char) ) ) == NULL )
  220.       {
  221. #if PROG_ERRORS
  222.       bwb_error( "in bwb_init(): failed to find memory for read_line" );
  223. #else
  224.       bwb_error( err_getmem );
  225. #endif
  226.       }
  227.  
  228. #if PARACT
  229.  
  230.    /* request task 0 as current (base) task */
  231.  
  232.    bwb_curtask = bwb_newtask( 0 );
  233.  
  234.    if ( bwb_curtask == -1 )
  235.       {
  236.       return;                /* error message has already been called*/
  237.       }
  238.  
  239. #endif
  240.  
  241. #if TEST_BSTRING
  242.    for ( n = 0; n < ESTACKSIZE; ++n )
  243.       {
  244.       sprintf( CURTASK exps[ n ].sval.name, "<Exp stack bstring %d>", n );
  245.       }
  246. #endif
  247.  
  248.    /* assign memory for the device table */
  249.  
  250. #if COMMON_CMDS
  251.    if ( ( dev_table = calloc( DEF_DEVICES, sizeof( struct dev_element ) ) ) == NULL )
  252.       {
  253. #if PROG_ERRORS
  254.       bwb_error( "in bwb_init(): failed to find memory for dev_table" );
  255. #else
  256.       bwb_error( err_getmem );
  257. #endif
  258.       bwx_terminate();
  259.       }
  260.  
  261.    /* initialize all devices to DEVMODE_AVAILABLE */
  262.  
  263.    for ( n = 0; n < DEF_DEVICES; ++n )
  264.       {
  265.       dev_table[ n ].mode = DEVMODE_AVAILABLE;
  266.       dev_table[ n ].reclen = -1;
  267.       dev_table[ n ].cfp = NULL;
  268.       dev_table[ n ].buffer = NULL;
  269.       dev_table[ n ].width = DEF_WIDTH;
  270.       dev_table[ n ].col = 1;
  271.       }
  272. #endif            /* COMMON_CMDS */
  273.  
  274.    /* initialize preset variables */
  275.  
  276.    ed = var_find( DEFVNAME_EDITOR );
  277.    ed->preset = TRUE;
  278.    ed->common = TRUE;
  279.    str_ctob( var_findsval( ed, ed->array_pos ), DEF_EDITOR );
  280.  
  281.    fi = var_find( DEFVNAME_FILES );
  282.    fi->preset = TRUE;
  283.    fi->common = TRUE;
  284.    str_ctob( var_findsval( fi, fi->array_pos ), DEF_FILES );
  285.  
  286.    pr = var_find( DEFVNAME_PROMPT );
  287.    pr->preset = TRUE;
  288.    pr->common = TRUE;
  289.    str_ctob( var_findsval( pr, pr->array_pos ), PROMPT );
  290.  
  291.    im = var_find( DEFVNAME_IMPL );
  292.    im->preset = TRUE;
  293.    im->common = TRUE;
  294.    str_ctob( var_findsval( im, im->array_pos ), IMP_IDSTRING );
  295.  
  296.    co = var_find( DEFVNAME_COLORS );
  297.    co->preset = TRUE;
  298.    co->common = TRUE;
  299.    * var_findnval( co, co->array_pos ) = (bnumber) DEF_COLORS;
  300.  
  301.    /* Signon message */
  302.  
  303.    bwx_signon();
  304.  
  305.    /* Redirect stderr if specified */
  306.  
  307. #if REDIRECT_STDERR
  308.    newerr = freopen( ERRFILE, "w", stderr );
  309.    if ( newerr == NULL )
  310.       {
  311.       sprintf( bwb_ebuf, "Failed to redirect error messages to file <%s>¥n",
  312.          ERRFILE );
  313.       errfdevice = stdout;
  314.       prn_xprintf( errfdevice, bwb_ebuf );
  315.       }
  316.    else
  317.       {
  318.       sprintf( bwb_ebuf, "NOTE: Error messages are redirected to file <%s>¥n",
  319.          ERRFILE );
  320.       prn_xprintf( errfdevice, bwb_ebuf );
  321.       errfdevice = stderr;
  322.       }
  323. #else
  324.    errfdevice = stdout;
  325. #endif
  326.  
  327.    /* if there is a profile.bas, execute it */
  328.  
  329. #if PROFILE
  330.    if ( ( profile = fopen( PROFILENAME, "r" )) != NULL )
  331.       {
  332.       bwb_fload( profile );    /* load profile */
  333.       bwb_run( &CURTASK bwb_start );    /* run profile */
  334.  
  335.       /* profile must be run immediately, not by scheduler */
  336.  
  337.       while ( CURTASK exsc > -1 )
  338.            {
  339.            bwb_execline();
  340.            }
  341.  
  342.       /* mark all profiled variables as preset */
  343.  
  344.       for ( v = CURTASK var_start.next; v != &CURTASK var_end; v = v->next )
  345.          {
  346.  
  347. #if INTENSIVE_DEBUG
  348.          sprintf( bwb_ebuf, "in bwb_init(): marked variable <%s> preset TRUE",
  349.             v->name );
  350.          bwb_debug( bwb_ebuf );
  351. #endif
  352.  
  353.          v->preset = TRUE;
  354.          }
  355.  
  356.       bwb_new( &CURTASK bwb_start );     /* remove profile from memory */
  357.       }
  358. #endif
  359.  
  360. #if INTENSIVE_DEBUG
  361.    sprintf( bwb_ebuf, "in main(): Ready to save jump MARKER" );
  362.    bwb_debug( bwb_ebuf );
  363. #endif
  364.  
  365.    /* set a buffer for jump: program execution returns to this point
  366.       in case of a jump (error, interrupt, or finish program) */
  367.  
  368. #if INTERACTIVE
  369.  
  370. #if HAVE_SIGNAL
  371.    signal( SIGINT, break_mes );
  372. #endif
  373.  
  374. #if HAVE_LONGJUMP
  375.    setjmp( mark );
  376. #endif
  377.  
  378. #if INTENSIVE_DEBUG
  379.    sprintf( bwb_ebuf, "in bwb_init(): Return from jump MARKER, program run <%d>",
  380.       program_run + 1 );
  381.    bwb_debug( bwb_ebuf );
  382.    getchar();
  383. #endif
  384.  
  385.    /* if INTERACTIVE is FALSE, then we must have a program file */
  386.  
  387. #else
  388.  
  389.    if ( argc < 2 )
  390.       {
  391.       bwb_error( err_noprogfile );
  392.       }
  393.  
  394. #endif                /* INTERACTIVE */
  395.  
  396.    /* check to see if there is a program file: but do this only the first
  397.       time around! */
  398.  
  399.    ++program_run;
  400.    if (( argc > 1 ) && ( program_run == 1 ))
  401.       {
  402.       if ( ( input = fopen( argv[ 1 ], "r" )) == NULL )
  403.          {
  404.          strcpy( CURTASK progfile, argv[ 1 ] );
  405.          strcat( CURTASK progfile, ".bas" );
  406.          if ( ( input = fopen( CURTASK progfile, "r" )) == NULL )
  407.             {
  408.             CURTASK progfile[ 0 ] = 0;
  409.             sprintf( bwb_ebuf, err_openfile, argv[ 1 ] );
  410.             bwb_error( bwb_ebuf );
  411.             }
  412.          }
  413.       if ( input != NULL )
  414.          {
  415.          strcpy( CURTASK progfile, argv[ 1 ] );
  416. #if INTENSIVE_DEBUG
  417.          sprintf( bwb_ebuf, "in main(): progfile is <%s>.", CURTASK progfile );
  418.          bwb_debug( bwb_ebuf );
  419. #endif
  420.  
  421.          bwb_fload( input );
  422.          bwb_run( &CURTASK bwb_start );
  423.          }
  424.       }
  425.  
  426.    }
  427.  
  428. /***************************************************************
  429.  
  430.         FUNCTION:       bwb_interact()
  431.  
  432.         DESCRIPTION:     This function gets a line from the user
  433.             and processes it.
  434.  
  435. ***************************************************************/
  436.  
  437. #if INTERACTIVE
  438. int
  439. #if ANSI_C
  440. bwb_interact( void )
  441. #else
  442. bwb_interact()
  443. #endif
  444.    {
  445.  
  446. #if INTENSIVE_DEBUG
  447.    sprintf( bwb_ebuf, "in bwb_interact(): ready to read from keyboard" );
  448.    bwb_debug( bwb_ebuf );
  449. #endif
  450.  
  451.    /* take input from keyboard */
  452.  
  453.    bwb_gets( read_line );
  454.  
  455.    /* If there is no line number, execute the line as received */
  456.  
  457.    if ( is_ln( read_line ) == FALSE )
  458.       {
  459.       bwb_xtxtline( read_line );
  460.       }
  461.  
  462.    /* If there is a line number, add the line to the file in memory */
  463.  
  464.    else
  465.       {
  466.       bwb_ladd( read_line, TRUE );
  467. #if INTENSIVE_DEBUG
  468.       bwb_debug( "Return from bwb_ladd()" );
  469. #endif
  470.       }
  471.  
  472.    return TRUE;
  473.  
  474.    }
  475.  
  476. #endif                /* INTERACTIVE == TRUE */
  477.  
  478. /***************************************************************
  479.  
  480.         FUNCTION:       bwb_fload()
  481.  
  482.         DESCRIPTION:     This function loads a BASIC program
  483.             file into memory given a FILE pointer.
  484.  
  485. ***************************************************************/
  486.  
  487. int
  488. #if ANSI_C
  489. bwb_fload( FILE *file )
  490. #else
  491. bwb_fload( file )
  492.    FILE *file;
  493. #endif
  494.    {
  495.  
  496.    while ( feof( file ) == FALSE )
  497.       {
  498.       read_line[ 0 ] = '¥0';
  499.       fgets( read_line, MAXREADLINESIZE, file );
  500.       if ( file == stdin )
  501.          {
  502.          * prn_getcol( stdout ) = 1;        /* reset column */
  503.          }
  504.       bwb_stripcr( read_line );
  505.  
  506.       /* be sure that this is not EOF with a NULL line */
  507.  
  508.       if (( feof( file ) == FALSE ) || ( strlen( read_line ) > 0 ))
  509.      {
  510.      bwb_ladd( read_line, FALSE );
  511.      }
  512.       }
  513.  
  514.    /* close file stream */
  515.  
  516.    fclose( file );
  517.  
  518.    return TRUE;
  519.    }
  520.  
  521. /***************************************************************
  522.  
  523.         FUNCTION:       bwb_ladd()
  524.  
  525.         DESCRIPTION:    This function adds a new line (in the
  526.                         buffer) to the program in memory.
  527.  
  528. ***************************************************************/
  529.  
  530. int
  531. #if ANSI_C
  532. bwb_ladd( char *buffer, int replace )
  533. #else
  534. bwb_ladd( buffer, replace )
  535.    char *buffer;
  536.    int replace;
  537. #endif
  538.    {
  539.    struct bwb_line *l, *previous, *p;
  540.    static char *s_buffer;
  541.    static int init = FALSE;
  542.    static int prev_num = 0;
  543.    char *newbuffer;
  544.  
  545. #if INTENSIVE_DEBUG
  546.    sprintf( bwb_ebuf, "in bwb_ladd(): add line <%s>",
  547.       buffer );
  548.    bwb_debug( bwb_ebuf );
  549. #endif
  550.  
  551.    /* get memory for temporary buffer if necessary */
  552.  
  553.    if ( init == FALSE )
  554.       {
  555.       init = TRUE;
  556.       if ( ( s_buffer = calloc( (size_t) MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  557.      {
  558. #if PROG_ERRORS
  559.      bwb_error( "in bwb_ladd(): failed to find memory for s_buffer" );
  560. #else
  561.      bwb_error( err_getmem );
  562. #endif
  563.      return FALSE;
  564.          }
  565.       }
  566.  
  567. #if INTENSIVE_DEBUG
  568.    sprintf( bwb_ebuf, "in bwb_ladd(): s_buffer initialized " );
  569.    bwb_debug( bwb_ebuf );
  570. #endif
  571.  
  572.    /* get memory for this line */
  573.  
  574.    if ( ( l = (struct bwb_line *) calloc( (size_t) 1, sizeof( struct bwb_line ) )) == NULL )
  575.       {
  576. #if PROG_ERRORS
  577.       bwb_error( "in bwb_ladd(): failed to find memory for new line" );
  578. #else
  579.       bwb_error( err_getmem );
  580. #endif
  581.       return FALSE;
  582.       }
  583.  
  584. #if INTENSIVE_DEBUG
  585.    sprintf( bwb_ebuf, "in bwb_ladd(): got memory." );
  586.    bwb_debug( bwb_ebuf );
  587. #endif
  588.  
  589.    /* note that line is not yet marked and the program must be rescanned */
  590.  
  591.    l->marked = FALSE;
  592.    CURTASK rescan = TRUE;        /* program needs to be scanned again */
  593.    l->xnum = FALSE;
  594.  
  595.    /* get the first element and test for a line number */
  596.  
  597.    adv_element( buffer, &( l->position ), s_buffer );
  598.  
  599.    /* set line number in line structure */
  600.  
  601.    if ( is_numconst( s_buffer ) == TRUE )
  602.       {
  603.  
  604.       l->number = atoi( s_buffer );
  605.  
  606. #if INTENSIVE_DEBUG
  607.       sprintf( bwb_ebuf, "in bwb_ladd(): line is numbered, number is <%d>",
  608.      l->number );
  609.       bwb_debug( bwb_ebuf );
  610. #endif
  611.  
  612.       prev_num = l->number;
  613.       l->xnum = TRUE;
  614.       ++( l->position );
  615.       newbuffer = &( buffer[ l->position ] );
  616.  
  617.       /* allocate memory and assign buffer to line buffer */
  618.  
  619.       ln_asbuf( l, newbuffer );
  620.  
  621.       }
  622.  
  623.    /* There is not a line number */
  624.  
  625.    else
  626.       {
  627.  
  628. #if INTENSIVE_DEBUG
  629.       sprintf( bwb_ebuf, "in bwb_ladd(): line is not numbered, using prev <%d>",
  630.          prev_num );
  631.       bwb_debug( bwb_ebuf );
  632. #endif
  633.  
  634.       newbuffer = buffer;
  635.  
  636.       /* allocate memory and assign buffer to line buffer */
  637.  
  638.       ln_asbuf( l, newbuffer );
  639.  
  640.       l->xnum = FALSE;
  641.       l->number = prev_num;
  642.       }
  643.  
  644.    /* find the place of the current line */
  645.  
  646.    for ( previous = &CURTASK bwb_start; previous != &CURTASK bwb_end; previous = previous->next )
  647.       {
  648.  
  649.       /* replace a previously existing line */
  650.  
  651.       if ( ( l->xnum == TRUE )
  652.          && ( previous->number == l->number )
  653.      && ( replace == TRUE )
  654.      )
  655.          {
  656.  
  657. #if INTENSIVE_DEBUG
  658.          sprintf( bwb_ebuf, "in bwb_ladd(): writing to previous number <%d>",
  659.             l->number );
  660.          bwb_debug( bwb_ebuf );
  661. #endif
  662.  
  663.          /* allocate memory and assign buffer to line buffer */
  664.  
  665.      ln_asbuf( previous, newbuffer );
  666.  
  667.          /* free the current line */
  668.  
  669.          free( l );
  670.  
  671.          /* and return */
  672.  
  673.          return TRUE;
  674.  
  675.          }
  676.  
  677.       /* add after previously existing line: this is to allow unnumbered
  678.          lines that follow in sequence after a previously numbered line */
  679.  
  680.       else if (( previous->number == l->number )
  681.      && ( replace == FALSE )
  682.      )
  683.          {
  684. #if INTENSIVE_DEBUG
  685.      sprintf( bwb_ebuf, "in bwb_ladd(): adding doubled number <%d>",
  686.         l->number );
  687.      bwb_debug( bwb_ebuf);
  688. #endif
  689.  
  690.          /* if there are multiple instances of this particular line number,
  691.             then it is incumbent upon us to find the very last one */
  692.  
  693.          for ( p = previous; p->number == l->number; p = p->next )
  694.             {
  695. #if INTENSIVE_DEBUG
  696.         bwb_debug( "in bwb_ladd(): advancing..." );
  697. #endif
  698.             previous = p;
  699.             }
  700.  
  701.          l->next = previous->next;
  702.          previous->next = l;
  703.          return TRUE;
  704.          }
  705.  
  706.       /* add a new line */
  707.  
  708.       else if ( ( previous->number < l->number )
  709.          && ( previous->next->number > l->number ))
  710.          {
  711.          l->next = previous->next;
  712.          previous->next = l;
  713.  
  714. #if INTENSIVE_DEBUG
  715.      sprintf( bwb_ebuf, "in bwb_ladd(): added new line <%d> buffer <%s>",
  716.         l->number, l->buffer );
  717.      bwb_debug( bwb_ebuf );
  718. #endif
  719.  
  720.          return TRUE;
  721.          }
  722.  
  723.       }
  724.  
  725.    /* attempt to link line number has failed; free memory */
  726.  
  727.    free( l->buffer );
  728.    free( l );
  729.  
  730.    sprintf( bwb_ebuf, ERR_LINENO );
  731.    bwb_error( bwb_ebuf );
  732.  
  733. #if INTENSIVE_DEBUG
  734.    sprintf( bwb_ebuf, "in bwb_ladd(): attempt to add line has failed" );
  735.    bwb_debug( bwb_ebuf );
  736. #endif
  737.  
  738.    return FALSE;
  739.  
  740.    }
  741.  
  742. /***************************************************************
  743.  
  744.         FUNCTION:       bwb_xtxtline()
  745.  
  746.         DESCRIPTION:    This function executes a text line, i.e.,
  747.                         places it in memory and then relinquishes
  748.                         control.
  749.  
  750. ***************************************************************/
  751.  
  752. struct bwb_line *
  753. #if ANSI_C
  754. bwb_xtxtline( char *buffer )
  755. #else
  756. bwb_xtxtline( buffer )
  757.    char *buffer;
  758. #endif
  759.    {
  760.    struct bwb_line *c;
  761.    char *p;
  762.    int loop;
  763.  
  764. #if INTENSIVE_DEBUG
  765.    sprintf( bwb_ebuf, "in bwb_xtxtline(): received <%s>", buffer );
  766.    bwb_debug( bwb_ebuf );
  767. #endif
  768.  
  769.    /* increment xtxt stack counter */
  770.  
  771.    if ( CURTASK xtxtsc >= XTXTSTACKSIZE )
  772.       {
  773.       sprintf( bwb_ebuf, "Exceeded maximum xtxt stack <%d>",
  774.          CURTASK xtxtsc );
  775.       return &CURTASK bwb_end;
  776.       }
  777.  
  778.    ++CURTASK xtxtsc;
  779.  
  780.    /* advance past whitespace */
  781.  
  782.    p = buffer;
  783.    loop = TRUE;
  784.    while( loop == TRUE )
  785.       {
  786.  
  787.       switch( *p )
  788.          {
  789.          case '¥0':                     /* end of string */
  790.  
  791. #if INTENSIVE_DEBUG
  792.             sprintf( bwb_ebuf, "Null command line received." );
  793.             bwb_debug( bwb_ebuf );
  794. #endif
  795.             --CURTASK xtxtsc;
  796.             return &CURTASK bwb_end;
  797.          case ' ':                      /* whitespace */
  798.          case '¥t':
  799.             ++p;
  800.             break;
  801.          default:
  802.             loop = FALSE;
  803.             break;
  804.          }
  805.  
  806.       }
  807.  
  808. #if INTENSIVE_DEBUG
  809.    sprintf( bwb_ebuf, "in bwb_xtxtline(): ready to get memory" );
  810.    bwb_debug( bwb_ebuf );
  811. #endif
  812.  
  813.    if ( CURTASK xtxts[ CURTASK xtxtsc ].l.buffer != NULL )
  814.       {
  815. #if INTENSIVE_DEBUG
  816.       sprintf( bwb_ebuf, "in bwb_xtxtline(): freeing buffer memory" );
  817.       bwb_debug( bwb_ebuf );
  818. #endif
  819.       free( CURTASK xtxts[ CURTASK xtxtsc ].l.buffer );
  820.       }
  821.  
  822.    /* copy the whole line to the line structure buffer */
  823.  
  824.    ln_asbuf( &( CURTASK xtxts[ CURTASK xtxtsc ].l ), buffer );
  825.  
  826. #if INTENSIVE_DEBUG
  827.    sprintf( bwb_ebuf, "in bwb_xtxtline(): copied to line buffer <%s>.",
  828.       CURTASK xtxts[ CURTASK xtxtsc ].l.buffer );
  829.    bwb_debug( bwb_ebuf );
  830. #endif
  831.  
  832.    /* set line number in line structure */
  833.  
  834.    CURTASK xtxts[ CURTASK xtxtsc ].l.number = 0;
  835.    CURTASK xtxts[ CURTASK xtxtsc ].l.marked = FALSE;
  836.  
  837.    /* execute the line as BASIC command line */
  838.  
  839.    CURTASK xtxts[ CURTASK xtxtsc ].l.next = &CURTASK bwb_end;
  840.    c = &( CURTASK xtxts[ CURTASK xtxtsc ].l );
  841.    c->position = 0;
  842.  
  843. #if THEOLDWAY
  844.    do
  845.       {
  846.       c = bwb_xline( c );
  847.       }
  848.  
  849.    while( c != &CURTASK bwb_end );
  850. #endif
  851.  
  852.    bwb_incexec();        /* increment EXEC stack */
  853.    bwb_setexec( c, 0, EXEC_NORM );        /* and set current line in it */
  854.  
  855.    /* decrement xtxt stack counter ??? */
  856.  
  857.    --CURTASK xtxtsc;
  858.  
  859.    return c;
  860.  
  861.    }
  862.  
  863. /***************************************************************
  864.  
  865.         FUNCTION:       bwb_incexec()
  866.  
  867.         DESCRIPTION:    This function increments the EXEC
  868.             stack counter.
  869.  
  870. ***************************************************************/
  871.  
  872. #if ANSI_C
  873. extern void
  874. bwb_incexec( void )
  875.    {
  876. #else
  877. void
  878. bwb_incexec()
  879.    {
  880. #endif
  881.    ++CURTASK exsc;
  882.  
  883.    if ( CURTASK exsc >= EXECLEVELS )
  884.       {
  885.       --CURTASK exsc;
  886. #if PROG_ERRORS
  887.       sprintf( bwb_ebuf, "in bwb_incexec(): incremented EXEC stack past max <%d>",
  888.          EXECLEVELS );
  889.       bwb_error( bwb_ebuf );
  890. #else
  891.       bwb_error( err_overflow );
  892. #endif
  893.       }
  894.  
  895.    CURTASK excs[ CURTASK exsc ].while_line = NULL;
  896.    CURTASK excs[ CURTASK exsc ].wend_line  = NULL;
  897.    CURTASK excs[ CURTASK exsc ].n_cvs = 0;
  898.    CURTASK excs[ CURTASK exsc ].local_variable = NULL;
  899.  
  900.    }
  901.  
  902. /***************************************************************
  903.  
  904.         FUNCTION:       bwb_decexec()
  905.  
  906.         DESCRIPTION:    This function decrements the EXEC
  907.             stack counter.
  908.  
  909. ***************************************************************/
  910.  
  911. #if ANSI_C
  912. extern void
  913. bwb_decexec( void )
  914.    {
  915. #else
  916. void
  917. bwb_decexec()
  918.    {
  919. #endif
  920.  
  921.    /* decrement the exec stack counter */
  922.  
  923.    --CURTASK exsc;
  924.  
  925.    if ( CURTASK exsc < -1 )
  926.       {
  927.       CURTASK exsc = -1;
  928. #if PROG_ERRORS
  929.       sprintf( bwb_ebuf, "in bwb_decexec(): decremented EXEC stack past min <-1>" );
  930.       bwb_error( bwb_ebuf );
  931. #else
  932.       bwb_error( err_overflow );
  933. #endif
  934.       }
  935.  
  936.    /* check for EXEC_ON and decrement recursively */
  937.  
  938.    if ( CURTASK excs[ CURTASK exsc ].code == EXEC_ON )
  939.       {
  940.  
  941.       free( CURTASK excs[ CURTASK exsc ].while_line->buffer );
  942.       free( CURTASK excs[ CURTASK exsc ].while_line );
  943.  
  944.       bwb_decexec();
  945.       }
  946.  
  947.    }
  948.  
  949. /***************************************************************
  950.  
  951.         FUNCTION:       bwb_setexec()
  952.  
  953.         DESCRIPTION:    This function sets the line and position
  954.             for the next call to bwb_execline();
  955.  
  956. ***************************************************************/
  957.  
  958. #if ANSI_C
  959. extern int
  960. bwb_setexec( struct bwb_line *l, int position, int code )
  961.    {
  962. #else
  963. int
  964. bwb_setexec( l, position, code )
  965.    struct bwb_line *l;
  966.    int position;
  967.    int code;
  968.    {
  969. #endif
  970.  
  971.    CURTASK excs[ CURTASK exsc ].line = l;
  972.    CURTASK excs[ CURTASK exsc ].position = position;
  973.    CURTASK excs[ CURTASK exsc ].code = code;
  974.  
  975.    return TRUE;
  976.  
  977.    }
  978.  
  979. /***************************************************************
  980.  
  981.         FUNCTION:       bwb_mainloop()
  982.  
  983.         DESCRIPTION:    This C function performs one iteration
  984.                         of the interpreter. In a non-preemptive
  985.                         scheduler, this function should be called
  986.                         by the scheduler, not by bwBASIC code.
  987.  
  988. ***************************************************************/
  989.  
  990. void
  991. #if ANSI_C
  992. bwb_mainloop( void )
  993. #else
  994. bwb_mainloop()
  995. #endif
  996.    {
  997.    if ( CURTASK exsc > -1 )
  998.       {
  999.       bwb_execline();            /* execute one line of program */
  1000.       }
  1001. #if INTERACTIVE
  1002.    else
  1003.       {
  1004.       bwb_interact();            /* get user interaction */
  1005.       }
  1006. #endif
  1007.    }
  1008.  
  1009. /***************************************************************
  1010.  
  1011.         FUNCTION:       bwb_execline()
  1012.  
  1013.         DESCRIPTION:    This function executes a single line of
  1014.                         a program in memory. This function is
  1015.             called by bwb_mainloop().
  1016.  
  1017. ***************************************************************/
  1018.  
  1019. void
  1020. #if ANSI_C
  1021. bwb_execline( void )
  1022. #else
  1023. bwb_execline()
  1024. #endif
  1025.    {
  1026.    struct bwb_line *r, *l;
  1027.  
  1028.    l = CURTASK excs[ CURTASK exsc ].line;
  1029.  
  1030.    /* if the line is &CURTASK bwb_end, then break out of EXEC loops */
  1031.  
  1032.    if ( l == &CURTASK bwb_end )
  1033.       {
  1034.       CURTASK exsc = -1;
  1035.       return;
  1036.       }
  1037.  
  1038.    /* Check for wacko line numbers  */
  1039.  
  1040. #if INTENSIVE_DEBUG
  1041.    if ( l->number < -1 )
  1042.       {
  1043. #if PROG_ERRORS
  1044.       sprintf( bwb_ebuf, "in bwb_execline(): received line number <%d> < -1",
  1045.          l->number );
  1046.       bwb_error( bwb_ebuf );
  1047. #else
  1048.       bwb_error( err_syntax );
  1049. #endif
  1050.       return;
  1051.       }
  1052.  
  1053.    if ( l->number > MAXLINENO )
  1054.       {
  1055. #if PROG_ERRORS
  1056.       sprintf( bwb_ebuf, "in bwb_execline(): received line number <%d> > MAX <%d>",
  1057.          l->number, MAXLINENO );
  1058.       bwb_error( bwb_ebuf );
  1059. #else
  1060.       bwb_error( err_syntax );
  1061. #endif
  1062.       return;
  1063.       }
  1064. #endif
  1065.  
  1066. #if INTENSIVE_DEBUG
  1067.    sprintf( bwb_ebuf, "in bwb_execline(): buffer <%s>",
  1068.       &( l->buffer[ l->position ] ) );
  1069.    bwb_debug( bwb_ebuf );
  1070. #endif
  1071.  
  1072.    /* Print line number if trace is on */
  1073.  
  1074.    if ( bwb_trace == TRUE )
  1075.       {
  1076. #if INTENSIVE_DEBUG
  1077.       sprintf( bwb_ebuf, "[ %d ]", l->number );
  1078.       prn_xprintf( errfdevice, bwb_ebuf );
  1079. #else
  1080.       if ( l->number > 0 )
  1081.          {
  1082.          sprintf( bwb_ebuf, "[ %d ]", l->number );
  1083.      prn_xprintf( errfdevice, bwb_ebuf );
  1084.          }
  1085. #endif
  1086.       }
  1087.  
  1088.    /* Set current line for error/break handling */
  1089.  
  1090.    CURTASK number = l->number;
  1091.    CURTASK bwb_l = l;
  1092.  
  1093.    /* advance beyond whitespace */
  1094.  
  1095.    adv_ws( l->buffer, &( l->position ) );
  1096.  
  1097.    /*  advance past segment delimiter and warn */
  1098.  
  1099. #if MULTISEG_LINES
  1100.    if ( l->buffer[ l->position ] == ':' )
  1101.       {
  1102.       ++( l->position );
  1103.       adv_ws( l->buffer, &( l->position ) );
  1104.       }
  1105.    l->marked = FALSE;
  1106. #else
  1107. #if PROG_ERRORS
  1108.    if ( l->buffer[ l->position ] == ':' )
  1109.       {
  1110.       ++( l->position );
  1111.       adv_ws( l->buffer, &( l->position ) );
  1112.       sprintf( bwb_ebuf, "Enable MULTISEG_LINES for multi-segmented lines",
  1113.          VERSION );
  1114.       bwb_error( bwb_ebuf );
  1115.       }
  1116. #endif
  1117. #endif
  1118.  
  1119.    /* set positions in buffer */
  1120.  
  1121. #if MULTISEG_LINES
  1122.    if ( ( l->marked != TRUE ) || ( l->position > l->startpos ))
  1123.       {
  1124.       line_start( l->buffer, &( l->position ), &( l->lnpos ), &( l->lnum ),
  1125.          &( l->cmdpos ), &( l->cmdnum ), &( l->startpos ) );
  1126.       l->marked = TRUE;
  1127.       }
  1128.    else
  1129.       {
  1130. #if INTENSIVE_DEBUG
  1131.       sprintf( bwb_ebuf, "in bwb_execline(): line <%d> is already marked",
  1132.           l->number );
  1133.       bwb_debug( bwb_ebuf );
  1134. #endif
  1135.       }
  1136.    l->position = l->startpos;
  1137. #else                /* not MULTISEG_LINES */
  1138.    line_start( l->buffer, &( l->position ), &( l->lnpos ), &( l->lnum ),
  1139.       &( l->cmdpos ), &( l->cmdnum ), &( l->startpos ) );
  1140.    if ( l->position < l->startpos )
  1141.       {
  1142.       l->position = l->startpos;
  1143.       }
  1144. #endif
  1145.  
  1146.    /* if there is a BASIC command in the line, execute it here */
  1147.  
  1148.    if ( l->cmdnum > -1 )
  1149.       {
  1150.  
  1151. #if INTENSIVE_DEBUG
  1152.       sprintf( bwb_ebuf, "in bwb_execline(): executing <%s>", l->buffer );
  1153.       bwb_debug( bwb_ebuf );
  1154. #endif
  1155.  
  1156.       /* execute the command vector */
  1157.  
  1158.       r = bwb_cmdtable[ l->cmdnum ].vector ( l );
  1159.  
  1160.       }
  1161.  
  1162.    /* No BASIC command; try to execute it as a shell command */
  1163.  
  1164. #if COMMAND_SHELL
  1165.    else
  1166.       {
  1167.  
  1168. #if INTENSIVE_DEBUG
  1169.       sprintf( bwb_ebuf, "Breaking out to shell, line num <%d> buf <%s> cmd <%d> pos <%d>",
  1170.          l->number, &( l->buffer[ l->position ] ), l->cmdnum, l->position );
  1171.       bwb_debug( bwb_ebuf );
  1172.       getchar();
  1173. #endif
  1174.  
  1175.       bwx_shell( l );
  1176.       bwb_setexec( l->next, 0, CURTASK excs[ CURTASK exsc ].code );
  1177.       return;
  1178.       }
  1179.  
  1180. #else                /* COMMAND_SHELL == FALSE */
  1181.  
  1182.    else
  1183.      {
  1184.      bwb_error( err_uc );
  1185.      }
  1186.  
  1187. #endif
  1188.  
  1189.    /* check for end of line: if so, advance to next line and return */
  1190.  
  1191.    adv_ws( r->buffer, &( r->position ) );
  1192.    switch( r->buffer[ r->position ] )
  1193.       {
  1194.       case '¥n':
  1195.       case '¥r':
  1196.       case '¥0':
  1197.  
  1198. #if INTENSIVE_DEBUG
  1199.      sprintf( bwb_ebuf, "in bwb_execline(): detected end of line" );
  1200.      bwb_debug( bwb_ebuf );
  1201. #endif
  1202.  
  1203.      r->next->position = 0;
  1204.          bwb_setexec( r->next, 0, CURTASK excs[ CURTASK exsc ].code );
  1205.          return;            /* and return */
  1206.       }
  1207.  
  1208.    /* else reset with the value in r */
  1209.  
  1210.    bwb_setexec( r, r->position, CURTASK excs[ CURTASK exsc ].code );
  1211.  
  1212. #if INTENSIVE_DEBUG
  1213.    sprintf( bwb_ebuf, "in bwb_execline(): exit setting line number <%d>",
  1214.       r->number );
  1215.    bwb_debug( bwb_ebuf );
  1216. #endif
  1217.  
  1218.    }
  1219.  
  1220. /***************************************************************
  1221.  
  1222.         FUNCTION:       ln_asbuf()
  1223.  
  1224.         DESCRIPTION:    This function allocates memory and copies
  1225.             a null-terminated string to a line buffer.
  1226.  
  1227. ***************************************************************/
  1228.  
  1229. int
  1230. #if ANSI_C
  1231. ln_asbuf( struct bwb_line *l, char *s )
  1232. #else
  1233. ln_asbuf( l, s )
  1234.    struct bwb_line *l;
  1235.    char *s;
  1236. #endif
  1237.    {
  1238.  
  1239. #if DONTDOTHIS            /* but why not? */
  1240.    if ( l->buffer != NULL )
  1241.       {
  1242.       free( l->buffer );
  1243.       }
  1244. #endif
  1245.  
  1246.    if ( ( l->buffer = calloc( strlen( s ) + 2, sizeof( char ) ) )
  1247.       == NULL )
  1248.       {
  1249. #if PROG_ERRORS
  1250.       bwb_error( "in ln_asbuf(): failed to find memory for new line" );
  1251. #else
  1252.       bwb_error( err_getmem );
  1253. #endif
  1254.       return FALSE;
  1255.       }
  1256.  
  1257.    /* copy the whole line to the line structure buffer */
  1258.  
  1259.    strcpy( l->buffer, s );
  1260.  
  1261. #if INTENSIVE_DEBUG
  1262.    sprintf( bwb_ebuf, "in ln_asbuf(): allocated buffer <%s>", l->buffer );
  1263.    bwb_debug( bwb_ebuf );
  1264. #endif
  1265.  
  1266.    /* strip CR from the buffer */
  1267.  
  1268.    bwb_stripcr( l->buffer );
  1269.  
  1270. #if INTENSIVE_DEBUG
  1271.    sprintf( bwb_ebuf, "in ln_asbuf(): stripped CRs" );
  1272.    bwb_debug( bwb_ebuf );
  1273. #endif
  1274.  
  1275.    return TRUE;
  1276.  
  1277.    }
  1278.  
  1279. /***************************************************************
  1280.  
  1281.         FUNCTION:       bwb_gets()
  1282.  
  1283.         DESCRIPTION:    This function reads a single line from
  1284.                         the specified buffer.
  1285.  
  1286. ***************************************************************/
  1287.  
  1288. int
  1289. #if ANSI_C
  1290. bwb_gets( char *buffer )
  1291. #else
  1292. bwb_gets( buffer )
  1293.    char *buffer;
  1294. #endif
  1295.    {
  1296.    struct bwb_variable *v;
  1297.    char tbuf[ MAXSTRINGSIZE + 1 ];
  1298. #if PARACT
  1299.    char ubuf[ MAXSTRINGSIZE + 1 ];
  1300. #endif
  1301.  
  1302.    CURTASK number = 0;
  1303.  
  1304.    v = var_find( DEFVNAME_PROMPT );
  1305.    str_btoc( tbuf, var_getsval( v ) );
  1306. #if PARACT
  1307.    sprintf( ubuf, "TASK %d %s", bwb_curtask, tbuf );
  1308.    strcpy( tbuf, ubuf );
  1309. #endif
  1310.  
  1311.    bwx_input( tbuf, buffer );
  1312.  
  1313.    return TRUE;
  1314.    }
  1315.  
  1316. /***************************************************************
  1317.  
  1318.         FUNCTION:       break_mes()
  1319.  
  1320.         DESCRIPTION:    This function is called (a) by a SIGINT
  1321.             signal or (b) by error-handling routines.
  1322.             It prints an error message then calls
  1323.             break_handler() to handle the program
  1324.             interruption.
  1325.  
  1326. ***************************************************************/
  1327.  
  1328. void
  1329. #if ANSI_C
  1330. break_mes( int x )
  1331. #else
  1332. break_mes( x )
  1333.    int x;
  1334. #endif
  1335.    {
  1336.    static char *tmp_buffer;
  1337.    static int init = FALSE;
  1338.  
  1339.    /* get memory for temporary buffer if necessary */
  1340.  
  1341.    if ( init == FALSE )
  1342.       {
  1343.       init = TRUE;
  1344.       if ( ( tmp_buffer = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  1345.          {
  1346. #if PROG_ERRORS
  1347.      bwb_error( "in break_mes(): failed to find memory for tmp_buffer" );
  1348. #else
  1349.      bwb_error( err_getmem );
  1350. #endif
  1351.      }
  1352.       }
  1353.  
  1354.    CURTASK expsc = 0;
  1355.  
  1356.    sprintf( tmp_buffer, "¥r%s %d¥n", MES_BREAK, CURTASK number );
  1357.    prn_xprintf( errfdevice, tmp_buffer );
  1358.  
  1359.    break_handler();
  1360.  
  1361.    }
  1362.  
  1363. /***************************************************************
  1364.  
  1365.     FUNCTION:       break_handler()
  1366.  
  1367.     DESCRIPTION:    This function is called by break_mes()
  1368.             and handles program interruption by break
  1369.             (or by the STOP command).
  1370.  
  1371. ***************************************************************/
  1372.  
  1373. void
  1374. #if ANSI_C
  1375. break_handler( void )
  1376. #else
  1377. break_handler()
  1378. #endif
  1379.    {
  1380.  
  1381. #if INTERACTIVE        /* INTERACTIVE: reset counters and jump back to mark */
  1382.  
  1383.    /* reset all stack counters */
  1384.  
  1385.    CURTASK exsc = -1;
  1386.    CURTASK expsc = 0;
  1387.    CURTASK xtxtsc = 0;
  1388.    err_gosubl[ 0 ] = '¥0';
  1389.  
  1390.    /* reset the break handler */
  1391.  
  1392. #if HAVE_SIGNAL
  1393.    signal( SIGINT, break_mes );
  1394. #endif
  1395.  
  1396. #if HAVE_LONGJUMP
  1397.    longjmp( mark, -1 );
  1398. #else        /* HAVE_LONGJUMP = FALSE; no jump available; terminate */   
  1399.    bwx_terminate();
  1400. #endif   
  1401.  
  1402. #else        /* nonINTERACTIVE:  terminate immediately */
  1403.  
  1404.    bwx_terminate();
  1405.  
  1406. #endif
  1407.  
  1408.    }
  1409.  
  1410.  
  1411. /***************************************************************
  1412.  
  1413.     FUNCTION:       is_ln()
  1414.  
  1415.     DESCRIPTION:    This function determines whether a program
  1416.             line (in buffer) begins with a line number.
  1417.  
  1418. ***************************************************************/
  1419.  
  1420. int
  1421. #if ANSI_C
  1422. is_ln( char *buffer )
  1423. #else
  1424. is_ln( buffer )
  1425.    char *buffer;
  1426. #endif
  1427.    {
  1428.    static int position;
  1429.  
  1430.    position = 0;
  1431.    adv_ws( buffer, &position );
  1432.    switch( buffer[ position ] )
  1433.       {
  1434.       case '0':
  1435.       case '1':
  1436.       case '2':
  1437.       case '3':
  1438.       case '4':
  1439.       case '5':
  1440.       case '6':
  1441.       case '7':
  1442.       case '8':
  1443.       case '9':
  1444.          return TRUE;
  1445.       default:
  1446.          return FALSE;
  1447.       }
  1448.    }
  1449.  
  1450.  
  1451.