📄 bwb_prn.c
字号:
/*************************************************************** bwb_prn.c Print and Error-Handling Commands for Bywater BASIC Interpreter Copyright (c) 1993, Ted A. Campbell Bywater Software email: tcamp@delphi.com Copyright and Permissions Information: All U.S. and international rights are claimed by the author, Ted A. Campbell. This software is released under the terms of the GNU General Public License (GPL), which is distributed with this software in the file "COPYING". The GPL specifies the terms under which users may copy and use the software in this distribution. A separate license is available for commercial distribution, for information on which you should contact the author.***************************************************************//*---------------------------------------------------------------*//* NOTE: Modifications marked "JBV" were made by Jon B. Volkoff, *//* 11/1995 (eidetics@cerf.net). *//*---------------------------------------------------------------*/#include <stdio.h>#include <ctype.h>#include <math.h>#include "bwbasic.h"#include "bwb_mes.h"/* Prototypes for functions visible only to this file */int prn_col = 1;static int prn_width = 80; /* default width for stdout */struct prn_fmt { int type; /* STRING, NUMBER, SINGLE, or NUMBER */ int exponential; /* TRUE = use exponential notation */ int right_justified; /* TRUE = right justified else left justified */ int width; /* width of main section */ int precision; /* width after decimal point */ int commas; /* use commas every three steps */ int sign; /* prefix sign to number */ int money; /* prefix money sign to number */ int fill; /* ASCII value for fill character, normally ' ' */ int minus; /* postfix minus sign to number */ };#if ANSI_Cstatic int prn_cr( char *buffer, FILE *f );static struct prn_fmt *get_prnfmt( char *buffer, int *position, FILE *f );static int bwb_xerror( char *message );static int xxputc( FILE *f, char c );static int xxxputc( FILE *f, char c );static struct bwb_variable * bwb_esetovar( struct exp_ese *e );#elsestatic int prn_cr();static struct prn_fmt *get_prnfmt();static int bwb_xerror();static int xxputc();static int xxxputc();static struct bwb_variable * bwb_esetovar();#endif/*************************************************************** FUNCTION: bwb_print() DESCRIPTION: This function implements the BASIC PRINT command. SYNTAX: PRINT [# device-number,][USING format-string$;] expressions...***************************************************************/#if ANSI_Cstruct bwb_line *bwb_print( struct bwb_line *l )#elsestruct bwb_line *bwb_print( l ) struct bwb_line *l;#endif { FILE *fp; static int pos; int req_devnumber; struct exp_ese *v; static char *s_buffer; /* small, temporary buffer */ static int init = FALSE;#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_print(): enter function" ); bwb_debug( bwb_ebuf );#endif /* initialize buffers if necessary */ if ( init == FALSE ) { init = TRUE; /* Revised to CALLOC pass-thru call by JBV */ if ( ( s_buffer = CALLOC( MAXSTRINGSIZE + 1, sizeof(char), "bwb_print") ) == NULL ) {#if PROG_ERRORS bwb_error( "in bwb_print(): failed to get memory for s_buffer" );#else bwb_error( err_getmem );#endif } } /* advance beyond whitespace and check for the '#' sign */ adv_ws( l->buffer, &( l->position ) );#if COMMON_CMDS if ( l->buffer[ l->position ] == '#' ) { ++( l->position ); adv_element( l->buffer, &( l->position ), s_buffer ); pos = 0; v = bwb_exp( s_buffer, FALSE, &pos ); adv_ws( l->buffer, &( l->position ) ); if ( l->buffer[ l->position ] == ',' ) { ++( l->position ); } else {#if PROG_ERRORS bwb_error( "in bwb_print(): no comma after #n" );#else bwb_error( err_syntax );#endif return bwb_zline( l ); } req_devnumber = (int) exp_getnval( v ); /* check the requested device number */ if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES )) {#if PROG_ERRORS bwb_error( "in bwb_input(): Requested device number is out of range." );#else bwb_error( err_devnum );#endif return bwb_zline( l ); } if (( dev_table[ req_devnumber ].mode == DEVMODE_CLOSED ) || ( dev_table[ req_devnumber ].mode == DEVMODE_AVAILABLE )) {#if PROG_ERRORS bwb_error( "in bwb_input(): Requested device number is not open." );#else bwb_error( err_devnum );#endif return bwb_zline( l ); } if ( dev_table[ req_devnumber ].mode != DEVMODE_OUTPUT ) {#if PROG_ERRORS bwb_error( "in bwb_print(): Requested device is not open for OUTPUT." );#else bwb_error( err_devnum );#endif return bwb_zline( l ); }#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_print(): device number is <%d>", req_devnumber ); bwb_debug( bwb_ebuf );#endif /* look up the requested device in the device table */ fp = dev_table[ req_devnumber ].cfp; } else { fp = stdout; }#else fp = stdout;#endif /* COMMON_CMDS */ bwb_xprint( l, fp ); return bwb_zline( l ); }/*************************************************************** FUNCTION: bwb_xprint() DESCRIPTION: This function implements the BASIC PRINT command, utilizing a specified file our output device.***************************************************************/#if ANSI_Cintbwb_xprint( struct bwb_line *l, FILE *f )#elseintbwb_xprint( l, f ) struct bwb_line *l; FILE *f;#endif { struct exp_ese *e; int loop; static int p; static int fs_pos; struct prn_fmt *format; static char *format_string; static char *output_string; static char *element; static char *prnbuf; static int init = FALSE; register int i, j; /* JBV */ int dig_pos, dec_pos; /* JBV */ char tbuf[ MAXSTRINGSIZE + 1 ]; /* JBV */#if INTENSIVE_DEBUG || TEST_BSTRING bstring *b;#endif /* initialize buffers if necessary */ if ( init == FALSE ) { init = TRUE; /* Revised to CALLOC pass-thru call by JBV */ if ( ( format_string = CALLOC( MAXSTRINGSIZE + 1, sizeof(char), "bwb_xprint") ) == NULL ) {#if PROG_ERRORS bwb_error( "in bwb_xprint(): failed to get memory for format_string" );#else bwb_error( err_getmem );#endif } /* Revised to CALLOC pass-thru call by JBV */ if ( ( output_string = CALLOC( MAXSTRINGSIZE + 1, sizeof(char), "bwb_xprint") ) == NULL ) {#if PROG_ERRORS bwb_error( "in bwb_xprint(): failed to get memory for output_string" );#else bwb_error( err_getmem );#endif } /* Revised to CALLOC pass-thru call by JBV */ if ( ( element = CALLOC( MAXSTRINGSIZE + 1, sizeof(char), "bwb_xprint") ) == NULL ) {#if PROG_ERRORS bwb_error( "in bwb_xprint(): failed to get memory for element buffer" );#else bwb_error( err_getmem );#endif } /* Revised to CALLOC pass-thru call by JBV */ if ( ( prnbuf = CALLOC( MAXSTRINGSIZE + 1, sizeof(char), "bwb_xprint") ) == NULL ) {#if PROG_ERRORS bwb_error( "in bwb_xprint(): failed to get memory for prnbuf" );#else bwb_error( err_getmem );#endif } } /* Detect USING Here */ fs_pos = -1; /* get "USING" in format_string */ p = l->position; adv_element( l->buffer, &p, format_string ); bwb_strtoupper( format_string );#if COMMON_CMDS /* check to be sure */ if ( strcmp( format_string, CMD_XUSING ) == 0 ) { l->position = p; adv_ws( l->buffer, &( l->position ) ); /* now get the format string in format_string */ e = bwb_exp( l->buffer, FALSE, &( l->position ) ); if ( e->type == STRING ) { /* copy the format string to buffer */ str_btoc( format_string, exp_getsval( e ) ); /* look for ';' after format string */ fs_pos = 0; adv_ws( l->buffer, &( l->position ) ); if ( l->buffer[ l->position ] == ';' ) { ++l->position; adv_ws( l->buffer, &( l->position ) ); } else {#if PROG_ERRORS bwb_error( "Failed to find \";\" after format string in PRINT USING" );#else bwb_error( err_syntax );#endif return FALSE; }#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_xprint(): Found USING, format string <%s>", format_string ); bwb_debug( bwb_ebuf );#endif } else {#if PROG_ERRORS bwb_error( "Failed to find format string after PRINT USING" );#else bwb_error( err_syntax );#endif return FALSE; } }#endif /* COMMON_CMDS */ /* if no arguments, simply print CR and return */ adv_ws( l->buffer, &( l->position ) ); switch( l->buffer[ l->position ] ) { case '\0': case '\n': case '\r': case ':': prn_xprintf( f, "\n" ); return TRUE; default: break; } /* LOOP THROUGH PRINT ELEMENTS */ loop = TRUE; while( loop == TRUE ) { /* resolve the string */ e = bwb_exp( l->buffer, FALSE, &( l->position ) );#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_xprint(): op <%d> type <%d>", e->operation, e->type ); bwb_debug( bwb_ebuf );#endif /* an OP_NULL probably indicates a terminating ';', but this will be detected later, so we can ignore it for now */ if ( e->operation != OP_NULL ) {#if TEST_BSTRING b = exp_getsval( e ); sprintf( bwb_ebuf, "in bwb_xprint(): bstring name is <%s>", b->name ); bwb_debug( bwb_ebuf );#endif str_btoc( element, exp_getsval( e ) ); } else { element[ 0 ] = '\0'; }#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_xprint(): element <%s>", element ); bwb_debug( bwb_ebuf );#endif /* print with format if there is one */ if (( fs_pos > -1 ) && ( strlen( element ) > 0 )) {#if COMMON_CMDS format = get_prnfmt( format_string, &fs_pos, f );#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_xprint(): format type <%d> width <%d>", format->type, format->width ); bwb_debug( bwb_ebuf );#endif switch( format->type ) { case STRING: if ( e->type != STRING ) {#if PROG_ERRORS bwb_error( "Type mismatch in PRINT USING" );#else bwb_error( err_mismatch );#endif } if ( format->width == -1 ) /* JBV */ sprintf( output_string, "%s", element ); else sprintf( output_string, "%.*s", format->width, element );#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_xprint(): output string <%s>", output_string ); bwb_debug( bwb_ebuf );#endif prn_xxprintf( f, output_string ); /* Was prn_xprintf (JBV) */ break; case NUMBER: if ( e->type == STRING ) {#if PROG_ERRORS bwb_error( "Type mismatch in PRINT USING" );#else bwb_error( err_mismatch );#endif } if ( format->exponential == TRUE ) { /*------------------------------------------------------*/ /* NOTE: Width and fill have no effect on C exponential */ /* format (JBV) */ /*------------------------------------------------------*/ if ( format->sign == TRUE ) /* Added by JBV */ sprintf( output_string, "%+e", exp_getnval( e ) ); else sprintf( output_string, "%e", exp_getnval( e ) ); } else { /*---------------------------------------------------*/ /* NOTE: Minus, commas, and money are only valid for */ /* floating point format (JBV) */ /*---------------------------------------------------*/ if ( format->sign == TRUE ) /* Added by JBV */ sprintf( output_string, "%+*.*f", format->width, format->precision, exp_getnval( e ) ); else if ( format->minus == TRUE ) /* Added by JBV */ { sprintf( output_string, "%*.*f", format->width, format->precision, exp_getnval( e ) ); for (i = 0; i < strlen( output_string ); ++i ) { if ( output_string[ i ] != ' ' ) { if ( output_string[ i ] == '-' ) { output_string[ i ] = ' '; strcat( output_string, "-" ); } else strcat( output_string, " " ); break; } } } else sprintf( output_string, "%*.*f", format->width, format->precision, exp_getnval( e ) ); if ( format->commas == TRUE ) /* Added by JBV */ { dig_pos = -1; dec_pos = -1; for ( i = 0; i < strlen( output_string ); ++i ) { if ( ( isdigit( output_string[ i ] ) != 0 ) && ( dig_pos == -1 ) ) dig_pos = i; if ( ( output_string[ i ] == '.' ) && ( dec_pos == -1 ) ) dec_pos = i; if ( ( dig_pos != -1 ) && ( dec_pos != -1 ) ) break; } if ( dec_pos == -1 ) dec_pos = strlen( output_string ); j = 0; for ( i = 0; i < strlen( output_string ); ++i ) { if ( ( ( dec_pos - i ) % 3 == 0 ) && ( i > dig_pos ) && ( i < dec_pos ) ) { tbuf[ j ] = ','; ++j; tbuf[ j ] = '\0'; } tbuf[ j ] = output_string[ i ]; ++j; tbuf[ j ] = '\0'; } strcpy( output_string, &tbuf[ strlen( tbuf ) - strlen( output_string ) ] ); } if ( format->money == TRUE ) /* Added by JBV */ { for ( i = 0; i < strlen( output_string ); ++i ) { if ( output_string[ i ] != ' ' ) { if ( i > 0 ) { if ( isdigit( output_string[ i ] ) == 0 ) { output_string[ i - 1 ] = output_string[ i ]; output_string[ i ] = '$'; } else output_string[ i - 1 ] = '$'; } break; } } } } if ( format->fill == '*' ) /* Added by JBV */ for ( i = 0; i < strlen( output_string ); ++i ) { if ( output_string[ i ] != ' ' ) break; output_string[ i ] = '*'; }#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_xprint(): output number <%f> string <%s>", exp_getnval( e ), output_string ); bwb_debug( bwb_ebuf );#endif prn_xxprintf( f, output_string ); /* Was prn_xprintf (JBV) */ break; default:#if PROG_ERRORS sprintf( bwb_ebuf, "in bwb_xprint(): get_prnfmt() returns unknown type <%c>", format->type ); bwb_error( bwb_ebuf );#else bwb_error( err_mismatch );#endif break; }#endif /* COMMON_CMDS */ } /* not a format string: use defaults */ else if ( strlen( element ) > 0 ) { switch( e->type ) { case STRING: prn_xprintf( f, element ); break; default:#if NUMBER_DOUBLE sprintf( prnbuf, " %.*lf", prn_precision( bwb_esetovar( e )), exp_getnval( e ) );#else sprintf( prnbuf, " %.*f", prn_precision( bwb_esetovar( e )), exp_getnval( e ) );#endif prn_xprintf( f, prnbuf ); break; } } /* check the position to see if the loop should continue */ adv_ws( l->buffer, &( l->position ) ); switch( l->buffer[ l->position ] ) {#if OLDSTUFF case ':': /* end of line segment */ loop = FALSE; break; case '\0': /* end of buffer */ case '\n':
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -