|
- /***************************************************************
-
- 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). */
- /* */
- /* Those additionally marked with "DD" were at the suggestion of */
- /* Dale DePriest (daled@cadence.com). */
- /* */
- /* Version 3.00 by Howard Wulf, AF5NE */
- /* */
- /* Version 3.10 by Howard Wulf, AF5NE */
- /* */
- /*---------------------------------------------------------------*/
-
-
-
- #include "bwbasic.h"
-
- /*
- We try to allow as many legacy PRINT USING formats as reasonable.
- Many legacy PRINT USING formats are incompatible with one another.
- For example:
- 1) some use '%' for strings, others use '%' for numbers, others consider '%' as a lieral.
- 2) some count a leading or traling signs in the width, while others do not.
- 3) when a value requires more digits than the assigned width:
- a) some truncate the displayed value to the width,
- b) some expand the width,
- c) some print a number of '%' or '*', and
- d) some halt processing.
- There is no perfect solution that will work for all possible dialects.
- */
-
-
- #define PrintUsingNumberDigit My->CurrentVersion->UsingDigit /* Digit placeholder, usually '#' */
- #define PrintUsingNumberComma My->CurrentVersion->UsingComma /* Comma, such as thousands, usually ',' */
- #define PrintUsingNumberPeriod My->CurrentVersion->UsingPeriod /* Period, such as dollars and cents, usually '.' */
- #define PrintUsingNumberPlus My->CurrentVersion->UsingPlus /* Plus sign, positive value, usually '+' */
- #define PrintUsingNumberMinus My->CurrentVersion->UsingMinus /* Minus sign, negative value, usually '-' */
- #define PrintUsingNumberExponent My->CurrentVersion->UsingExrad /* Exponential format, usually '^' */
- #define PrintUsingNumberDollar My->CurrentVersion->UsingDollar /* Currency symbol, usually '$' */
- #define PrintUsingNumberFiller My->CurrentVersion->UsingFiller /* Print filler, such as checks, usually '*' */
- #define PrintUsingLiteral My->CurrentVersion->UsingLiteral /* The next char is a literal, usually '_' */
- #define PrintUsingStringFirst My->CurrentVersion->UsingFirst /* The first character of the string, usually '!' */
- #define PrintUsingStringAll My->CurrentVersion->UsingAll /* Print the entire string, usually '&' */
- #define PrintUsingStringLength My->CurrentVersion->UsingLength /* Print a substring, usually '%' */
-
-
-
-
-
- /* Prototypes for functions visible only to this file */
-
-
- static int get_prnfmt(char *buffer, int *position, VariantType *e);
- static int xputc(char c);
- static int xxputc(char c);
- static int xxxputc(char c);
- static int bwb_xprint(LineType * l);
- static int prn_xxprintf(char *buffer);
-
-
- int is_empty_filename( char * Buffer )
- {
- while( *Buffer == ' ' )
- {
- Buffer++;
- }
- if( *Buffer == BasicNulChar )
- {
- return TRUE;
- }
- return FALSE;
- }
-
-
- FileType * find_file_by_name( char * FileName )
- {
- FileType * F;
-
- if( is_empty_filename( FileName ) )
- {
- /* the rules for Console and Printer vary by command */
- return NULL;
- }
- /* search the list of OPEN files */
- for( F = My->file_head; F != NULL; F = F->next )
- {
- if( F->mode != DEVMODE_CLOSED )
- {
- if( bwb_stricmp( F->filename, FileName ) == 0 )
- {
- /* FOUND */
- return F;
- }
- }
- }
- /* NOT FOUND */
- return NULL;
- }
-
-
- FileType * find_file_by_number( int FileNumber )
- {
- FileType * F;
- /* handle MAGIC file numbers */
- if( FileNumber <= 0 )
- {
- /* the rules for Console and Printer vary by command */
- return NULL;
- }
- /* search the list of OPEN files */
- for( F = My->file_head; F != NULL; F = F->next )
- {
- if( F->mode != DEVMODE_CLOSED )
- {
- if( F->FileNumber == FileNumber )
- {
- /* FOUND */
- return F;
- }
- }
- }
- /* NOT FOUND */
- return NULL;
- }
-
-
- FileType * file_new( void )
- {
- /* search for an empty slot. If not found, add a new slot. */
- FileType * F;
-
- for( F = My->file_head; F != NULL; F = F->next )
- {
- if( F->mode == DEVMODE_CLOSED )
- {
- /* FOUND */
- return F;
- }
- }
- /* NOT FOUND */
- F = calloc( 1, sizeof( FileType ) );
- F->next = My->file_head;
- My->file_head = F;
- return F;
- }
-
-
- void file_clear( FileType * F )
- {
- /* clean up a file slot that is no longer needed */
-
- #if NEW_VIRTUAL
- clear_virtual_by_file( F->FileNumber );
- #endif /* NEW_VIRTUAL */
- F->FileNumber = 0;
- F->mode = DEVMODE_CLOSED; /* DEVMODE_ item */
- F->width = 0; /* width for OUTPUT and APPEND; reclen for RANDOM; not used for INPUT or BINARY */
- F->col = 0; /* current column for OUTPUT and APPEND */
- F->row = 0; /* current row for OUTPUT and APPEND */
- F->EOF_LineNumber = 0; /* CBASIC-II: IF END # filenumber THEN linenumber */
- F->delimit = BasicNulChar; /* DELIMIT for READ and WRITE */
- F->filename[0] = BasicNulChar; /* filename */
- if( F->cfp != NULL )
- {
- fclose( F->cfp ); /* F->cfp != NULL */
- F->cfp = NULL;
- }
- if( F->buffer != NULL ) /* pointer to character buffer for RANDOM */
- {
- free( F->buffer );
- F->buffer = NULL;
- }
-
- }
-
- int file_next_number( void )
- {
- int FileNumber;
- FileType * F;
- FileNumber = 0;
- for (F = My->file_head; F != NULL; F = F->next)
- {
- if (F->mode != DEVMODE_CLOSED)
- {
- if( F->FileNumber > FileNumber )
- {
- FileNumber = F->FileNumber;
- }
- }
- }
- /* 'FileNumber' is the highest FileNumber that is currently open */
- FileNumber++;
- return FileNumber;
- }
-
-
-
- /***************************************************************
-
- FUNCTION: bwx_putc()
-
- DESCRIPTION: This function outputs a single character
- to the default output device.
-
- ***************************************************************/
-
- int
- bwx_PRINT(char c)
- {
- bwx_DEBUG(__FUNCTION__);
-
- /* send character to console */
- return fputc(c, My->SYSOUT->cfp);
- }
-
- int
- bwx_LPRINT(char c)
- {
- bwx_DEBUG(__FUNCTION__);
-
- /* send character to printer */
- return fputc(c, My->SYSPRN->cfp);
- }
-
- int
- prn_lprintf(char *buffer)
- {
- bwx_DEBUG(__FUNCTION__);
-
- while (*buffer != BasicNulChar)
- {
- bwx_LPRINT(*buffer);
- buffer++;
- }
- return 0;
- }
-
- int
- prn_xprintf(char *buffer)
- {
- /* Catch-22: an error has occurred before the devicce table is loaded */
- int n;
- bwx_DEBUG(__FUNCTION__);
-
-
- n = My->SYSOUT->width;
-
- if (n > 0)
- {
- int i;
- i = 0;
- while (*buffer)
- {
- fputc(*buffer, My->SYSOUT->cfp);
- buffer++;
- if (*buffer == '\n')
- {
- i = 0;
- }
- i++;
- if (i >= n)
- {
- fputc('\n', My->SYSOUT->cfp);
- i = 0;
- }
- }
- }
- else
- {
- /* raw */
- while (*buffer)
- {
- fputc(*buffer, My->SYSOUT->cfp);
- buffer++;
- }
- }
- fflush(My->SYSOUT->cfp);
- return 0;
- }
-
- static void CleanNumericString(char *prnbuf, int RemoveDot)
- {
- /* remove trailing zeroes */
- char *E;
- char *D;
-
- bwx_DEBUG(__FUNCTION__);
-
- E = bwb_strchr(prnbuf, 'E');
- if (E == NULL)
- {
- E = bwb_strchr(prnbuf, 'e');
- }
- if (E)
- {
- /* SCIENTIFIC == SCALED notation */
- /* trim leading zeroes in exponent */
- char *F;
- char *G;
- F = E;
- while (bwb_isalpha(*F))
- {
- F++;
- }
- while (*F == '+' || *F == '-')
- {
- /* skip sign */
- F++;
- }
- G = F;
- while (*G == '0' || *G == ' ')
- {
- /* skip leading zeroes or spaces */
- G++;
- }
- if (G > F)
- {
- bwb_strcpy(F, G);
- }
- G = NULL; /* no longer valid */
- *E = BasicNulChar; /* for bwb_strlen() */
- }
- D = bwb_strchr(prnbuf, '.');
- if (D)
- {
- int N = bwb_strlen(D);
- if (N > 1)
- {
- int M;
- N--;
- M = N;
- while (D[N] == '0')
- {
- /* remove trailing zeroes */
- D[N] = '_';
- N--;
- }
- if (RemoveDot)
- {
- if (E)
- {
- /* SCIENTIFIC == SCALED notation */
- /* do NOT remove '.' */
- }
- else
- {
- /* NORMAL == UNSCALED notation */
- /* remove trailing '.' */
- /* this will only occur for integer
- * values */
- while (D[N] == '.')
- {
- /* _###. POSITIVE INTEGER */
- /* -###. NEGATIVE INTEGER */
- D[N] = '_';
- N--;
- }
- }
- }
- if (N < M)
- {
- if (E)
- {
- /* SCIENTIFIC == SCALED notation */
- *E = 'E';
- E = NULL;
- }
- N++;
- /* if INTEGER, then N == 0, else N > 0 */
- M++;
- /* if SCIENTIFIC, then *M == 'E' else *M == BasicNulChar */
- bwb_strcpy(&(D[N]), &(D[M]));
- }
- }
- }
- if (E)
- {
- /* SCIENTIFIC == SCALED notation */
- *E = 'E';
- E = NULL;
- }
- if (prnbuf[1] == '0' && prnbuf[2] == '.')
- {
- /* _0.### POSITIVE FRACTION ==> _.### */
- /* -0.### NEGATIVE FRACTION ==> -.### */
- bwb_strcpy(&(prnbuf[1]), &(prnbuf[2]));
- }
- if (prnbuf[1] == '.' && prnbuf[2] == 'E')
- {
- /* _.E POSITIVE ZERO ==> _0 */
- /* -.E NEGATIVE ZERO ==> _0 */
- bwb_strcpy(prnbuf, " 0");
- }
- }
-
- static int SignificantDigits(char *Buffer)
- {
- int NumDigits;
- char *P;
-
- bwx_DEBUG(__FUNCTION__);
-
-
- /* determine the number of significant digits */
- NumDigits = 0;
- P = Buffer;
- while (*P)
- {
- if (bwb_isalpha(*P))
- {
- /* 'E', 'e', and so on. */
- break;
- }
- if (bwb_isdigit(*P))
- {
- NumDigits++;
- }
- P++;
- }
- return NumDigits;
- }
-
- void
- BasicNumerc(BasicNumberType Input, char *Output)
- {
- /*
- ********************************************************************************
-
- This is essentially sprintf( Output, "%g", Input ),
- except the rules for selecting between "%e", "%f", and "%d" are different.
-
- The C rules depend upon the value of the exponent.
- The BASIC rules depend upon the number of significant digits.
-
- The results of this routine have been verified by the NBS2 test suite, so
- THINK VERY CAREFULLY BEFORE MAKING ANY CHANGES TO THIS ROUTINE.
-
- ********************************************************************************
- */
-
- char *E;
-
- bwx_DEBUG(__FUNCTION__);
-
- /* print in scientific form first, to determine exponent and significant digits */
- sprintf(Output, "% 1.*E", SIGNIFICANT_DIGITS - 1, Input);
- E = bwb_strchr(Output, 'E');
- if (E == NULL)
- {
- E = bwb_strchr(Output, 'e');
- }
- if (E)
- {
- /* valid */
- int Exponent;
- int NumDigits;
- int DisplayDigits;
- int zz;
- char *F; /* pointer to the exponent's value */
- F = E;
- while (bwb_isalpha(*F))
- {
- F++;
- }
- Exponent = atoi(F);
- CleanNumericString(Output, 0);
- NumDigits = SignificantDigits(Output);
- DisplayDigits = MIN( NumDigits, SIGNIFICANT_DIGITS );
- zz = MAX(Exponent,DisplayDigits - Exponent - 2);
- if (zz >= SIGNIFICANT_DIGITS)
- {
- /* SCIENTIFIC */
- sprintf(Output, "%# 1.*E", DisplayDigits - 1, Input);
- }
- else
- if (Input == (int) Input)
- {
- /* INTEGER */
- sprintf(Output, "% *d", DisplayDigits, (int) Input);
- }
- else
- {
- /* FLOAT */
- int N;
- /* number of digits before the '.' */
- int M;
- /* number of digits after the '.' */
- N = Exponent + 1;
- if (N < 0)
- {
- N = 0;
- }
- M = SIGNIFICANT_DIGITS - N;
- if (M < 0)
- {
- M = 0;
- }
-
- sprintf(Output, "%# *.*f", N, M, Input);
- }
- CleanNumericString(Output, 0);
- }
- else
- {
- /* ERROR, NAN, INFINITY, ETC. */
- }
- return;
- }
-
-
-
- LineType *
- bwb_LPRINT(LineType * l)
- {
- bwx_DEBUG(__FUNCTION__);
- My->CurrentFile = My->SYSPRN;
- bwb_xprint(l);
- return bwb_zline(l);
- }
-
-
- /***************************************************************
-
- FUNCTION: bwb_print()
-
- DESCRIPTION: This function implements the BASIC PRINT
- command.
-
- SYNTAX: PRINT [# device-number,][USING format-string$;] expressions...
-
- ***************************************************************/
-
- LineType *
- bwb_QUEST(LineType * l)
- {
- bwx_DEBUG(__FUNCTION__);
-
- return bwb_PRINT(l);
- }
-
- static int bwb_print_at(LineType * l)
- {
- int position;
- int r;
- int c;
-
-
- position = 0;
- r = 0;
- c = 0;
-
- if( line_read_integer_expression(l, &position) == FALSE )
- {
- WARN_SYNTAX_ERROR;
- return FALSE;
- }
-
-
- if ( line_skip_comma(l))
- {
- /* OK */
- }
- else
- {
- WARN_SYNTAX_ERROR;
- return FALSE;
- }
-
- if( position < 0 )
- {
- WARN_SYNTAX_ERROR;
- return FALSE;
- }
- if( My->CurrentFile->width <= 0 )
- {
- WARN_SYNTAX_ERROR;
- return FALSE;
- }
- if( My->SCREEN_ROWS <= 0 )
- {
- WARN_SYNTAX_ERROR;
- return FALSE;
- }
- r = position / My->CurrentFile->width;
- c = position - r * My->CurrentFile->width;
- while( r >= My->SCREEN_ROWS )
- {
- r -= My->SCREEN_ROWS;
- }
- r++;
- c++;
-
- switch (My->OptionTerminalType)
- {
- case C_OPTION_TERMINAL_NONE:
- break;
- case C_OPTION_TERMINAL_ADM:
- fprintf(My->CurrentFile->cfp, "%c=%c%c", 27, r + 32, c + 32);
- break;
- case C_OPTION_TERMINAL_ANSI:
- fprintf(My->CurrentFile->cfp, "%c[%d;%dH", 27, r, c);
- break;
- default:
- WARN_SYNTAX_ERROR;
- return FALSE;
- /* break; */
- }
- My->CurrentFile->row = r;
- My->CurrentFile->col = c;
- return TRUE;
- }
-
- static int bwb_print_num(LineType * l)
- {
- int UserFileNumber;
-
-
- if( line_read_integer_expression(l, &UserFileNumber) == FALSE )
- {
- WARN_SYNTAX_ERROR;
- return FALSE;
- }
-
- if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) )
- {
- /*
- CBASIC-II: SERIAL & RANDOM file writes
- PRINT # file_number ; expression [, expression] ' SERIAL write
- PRINT # file_number , record_number ; expression [, expression] ' RANDOM write
- */
-
- if( UserFileNumber <= 0 )
- {
- WARN_BAD_FILE_NUMBER;
- return FALSE;
- }
- /* normal file */
- My->CurrentFile = find_file_by_number( UserFileNumber );
- if( My->CurrentFile == NULL )
- {
- WARN_BAD_FILE_NUMBER;
- return FALSE;
- }
-
-
- if( line_skip_char( l, ',' ) )
- {
- /*
- PRINT # file_number , record_number ; expression [, expression] ' RANDOM write
- */
- /* get the RecordNumber */
- int RecordNumber;
-
- if( (My->CurrentFile->mode & DEVMODE_RANDOM) == 0 )
- {
- WARN_BAD_FILE_MODE;
- return FALSE;
- }
- if( My->CurrentFile->width <= 0 )
- {
- WARN_FIELD_OVERFLOW;
- return FALSE;
- }
- if( line_read_integer_expression( l, &RecordNumber ) == FALSE )
- {
- WARN_SYNTAX_ERROR;
- return FALSE;
- }
- if( RecordNumber <= 0 )
- {
- WARN_BAD_RECORD_NUMBER;
- return FALSE;
- }
- RecordNumber--; /* BASIC to C */
- /* if( TRUE ) */
- {
- long offset;
- offset = RecordNumber;
- offset *= My->CurrentFile->width;
- fseek( My->CurrentFile->cfp, offset, SEEK_SET );
- }
- }
- if( line_is_eol( l ) )
- {
- /* PRINT # filenum */
- /* PRINT # filenum , recnum */
- }
- else
- if( line_skip_char( l, ';' ) )
- {
- /* PRINT # filenum ; */
- /* PRINT # filenum , recnum ; */
- }
- else
- {
- WARN_SYNTAX_ERROR;
- return FALSE;
- }
- return TRUE;
- }
- /*
- SERIAL file writes:
- PRINT # file_number
- PRINT # file_number [, expression]
- */
- if( UserFileNumber < 0 )
- {
- My->CurrentFile = My->SYSPRN;
- }
- else
- if( UserFileNumber == 0 )
- {
- My->CurrentFile = My->SYSOUT;
- }
- else
- {
- /* normal file */
- My->CurrentFile = find_file_by_number( UserFileNumber );
- }
- if( My->CurrentFile == NULL )
- {
- WARN_BAD_FILE_NUMBER;
- return FALSE;
- }
- if( ( My->CurrentFile->mode & DEVMODE_WRITE ) == 0 )
- {
- WARN_BAD_FILE_NUMBER;
- return FALSE;
- }
- if( line_is_eol( l ) )
- {
- /* PRINT # 2 */
- }
- else
- if( line_skip_comma( l ) )
- {
- /* PRINT # 2 , ... */
- }
- else
- {
- WARN_SYNTAX_ERROR;
- return FALSE;
- }
- return TRUE;
- }
-
- LineType *
- bwb_PRINT(LineType * l)
- {
- bwx_DEBUG(__FUNCTION__);
-
- My->CurrentFile = My->SYSOUT;
- line_skip_spaces(l);
- if ( line_skip_char(l,'@'))
- {
- /* PRINT @ position, ... */
- if( bwb_print_at(l) == FALSE )
- {
- return bwb_zline(l);
- }
- }
- else
- if ( line_skip_word( l, "AT") )
- {
- /* PRINT AT position, ... */
- if( bwb_print_at(l) == FALSE )
- {
- return bwb_zline(l);
- }
- }
- else
- if ( line_skip_char(l,BasicFileNumberPrefix))
- {
- /* PRINT # file, ... */
- if( bwb_print_num(l) == FALSE )
- {
- return bwb_zline(l);
- }
- }
- bwb_xprint(l);
- if( My->CurrentFile == My->SYSOUT )
- {
- /* FOR I = 1 TO 1000: PRINT "."; : NEXT I : PRINT */
- fflush(My->SYSOUT->cfp);
- }
- return bwb_zline(l);
- }
-
- /***************************************************************
-
- FUNCTION: bwb_xprint()
-
- DESCRIPTION: This function implements the PRINT
- command, utilizing a specified file our
- output device.
-
- ***************************************************************/
-
- static int buff_read_using( char * buffer, int * position, char * format_string )
- {
- int p;
-
- p = *position;
-
- buff_skip_spaces( buffer, &p );
- if( buff_skip_word( buffer, &p, "USING" ) )
- {
- buff_skip_spaces( buffer, &p );
- if( bwb_isdigit( buffer[p] ) )
- {
- /* PRINT USING ### */
- int LineNumber;
- LineType *x = NULL;
- char *C;
- char *F;
-
- if( buff_read_line_number(buffer, &p, &LineNumber) == FALSE )
- {
- WARN_SYNTAX_ERROR;
- return FALSE;
- }
- /* check for target label */
- x = find_line_number( LineNumber, TRUE );
- if (x == NULL)
- {
- WARN_UNDEFINED_LINE;
- return FALSE;
- }
- /* line exists */
- if( x->cmdnum != C_IMAGE )
- {
- WARN_UNDEFINED_LINE;
- return FALSE;
- }
- /* line contains IMAGE command */
- C = x->buffer;
- C += x->Startpos;
- F = format_string;
- /* look for leading quote in IMAGE "..." */
- while( *C == ' ' )
- {
- C++;
- }
- if( *C == BasicQuoteChar )
- {
- /* QUOTED */
- /* skip leading quote */
- C++;
- while( *C != BasicQuoteChar && *C != BasicNulChar )
- {
- /* copy format string, but not the trailing quote */
- *F = *C;
- C++;
- F++;
- }
- /* skip trailing quote */
- }
- else
- {
- /* UNQUOTED */
- while( *C != BasicNulChar )
- {
- /* copy format string verbatim */
- *F = *C;
- C++;
- F++;
- }
- }
- /* terminate format string */
- *F = BasicNulChar;
-
- buff_skip_spaces(buffer, &p);
- if ( buff_skip_comma(buffer, &p ) == FALSE)
- {
- WARN_SYNTAX_ERROR;
- return FALSE;
- }
- buff_skip_spaces(buffer, &p);
- }
- else
- {
- {
- char * Value = NULL;
-
- if( buff_read_string_expression( buffer, &p, &Value ) == FALSE )
- {
- WARN_SYNTAX_ERROR; /* HERE-Here-here BUG? */
- return FALSE;
- }
- if( Value == NULL )
- {
- WARN_SYNTAX_ERROR;
- return FALSE;
- }
- bwb_strcpy( format_string, Value );
- free( Value );
- }
- buff_skip_spaces(buffer, &p);
- if ( buff_skip_comma(buffer, &p) == FALSE)
- {
- WARN_SYNTAX_ERROR;
- return FALSE;
- }
- buff_skip_spaces(buffer, &p);
- }
- *position = p;
- return TRUE;
- }
- return FALSE;
- }
-
- static int bwb_xprint(LineType * l)
- {
- int Success = FALSE;
- VariantType e; /* no leaks */
- VariantType *E = &e; /* no leaks */
- static int fs_pos;
- int OutputCR;
- char format_string[BasicStringLengthMax + 1];
-
- bwx_DEBUG(__FUNCTION__);
- CLEAR_VARIANT( E );
-
-
- /* Detect USING Here */
-
- format_string[0] = BasicNulChar;
- fs_pos = 0;
-
- /* get "USING" in format_string */
- if( buff_read_using( l->buffer, &(l->position), format_string ) == TRUE )
- {
- fs_pos = 0;
- }
-
- /* if no arguments, simply print CR and return */
-
-
- /* LOOP THROUGH PRINT ELEMENTS */
-
- OutputCR = TRUE;
-
- /* 1980 PRINT , , ,"A" */
- line_skip_spaces(l);
- while( line_is_eol(l) == FALSE )
- {
- /* 1980 PRINT , , ,"A" */
- if ( line_skip_char( l, ',' /* comma-specific */ ) )
- {
- /* tab over */
- OutputCR = FALSE;
- if( format_string[0] == BasicNulChar )
- {
- /* Tab only if there's no format specification! (JBV) */
-
- if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) && My->CurrentFile->FileNumber > 0 )
- {
- /* CBASIC-II: files use commas between values */
- xputc(',');
- }
- else
- {
- xputc('\t');
- }
- }
- if( buff_read_using( l->buffer, &(l->position), format_string ) == TRUE )
- {
- fs_pos = 0;
- OutputCR = TRUE;
- }
- }
- else
- if ( line_skip_char( l, ';' /* semicolon-specific */ ) )
- {
- /* concatenate strings */
- OutputCR = FALSE;
- if( buff_read_using( l->buffer, &(l->position), format_string ) == TRUE )
- {
- fs_pos = 0;
- OutputCR = TRUE;
- }
- if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) && My->CurrentFile->FileNumber > 0 )
- {
- /* CBASIC-II: files cannot use semicolon */
- WARN_SYNTAX_ERROR;
- goto EXIT;
- }
- }
- else
- {
- /* resolve the string */
- OutputCR = TRUE;
- if( line_read_expression( l, E ) == FALSE )
- {
- WARN_SYNTAX_ERROR;
- goto EXIT;
- }
- if( bwb_Warning_Pending() /* Keep This */ )
- {
- /*
- this might look odd...
- but we want to abort printing on the first warning.
- The expression list could include a function with side-effects,
- so any warning should immediately halt further evaluation.
- */
- goto EXIT;
- }
- if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) && My->CurrentFile->FileNumber > 0 )
- {
- /* CBASIC-II: files have quoted strings */
- if( E->TypeChar == BasicStringSuffix )
- {
- xputc('\"');
- }
- }
- if( get_prnfmt(format_string, &fs_pos, E ) == FALSE )
- {
- WARN_SYNTAX_ERROR;
- goto EXIT;
- }
- if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) && My->CurrentFile->FileNumber > 0 )
- {
- /* CBASIC-II: files have quoted strings */
- if( E->TypeChar == BasicStringSuffix )
- {
- xputc('\"');
- }
- }
- RELEASE( E );
- }
- line_skip_spaces(l);
- } /* end of loop through print elements */
-
- if (OutputCR == TRUE)
- {
- /* did not end with ',' or ';' */
- xputc('\n');
- }
- Success = TRUE;
- EXIT:
- RELEASE( E );
- return Success;
- }
-
-
- /***************************************************************
-
- FUNCTION: get_prnfmt()
-
- DESCRIPTION: This function gets the PRINT USING
- format string, returning a structure
- to the format.
-
- ***************************************************************/
- static int num_prnfmt(char *buffer, int *position, VariantType *e)
- {
- /*
- Format a NUMBER.
- 'buffer' points to the beginning of a PRINT USING format string, such as "###.##".
- 'position' is the current offset in 'buffer'.
- 'e' is the current expression to print.
- */
- int width = 0;
- int precision = 0;
- int exponent = 0;
- char HeadChar = ' ';
- char FillChar = ' ';
- char CurrChar = ' ';
- char ComaChar = ' ';
- char TailChar = ' ';
- int p;
- char tbuf[BasicStringLengthMax + 1];
-
- p = *position;
-
- while( IS_CHAR(buffer[p], PrintUsingNumberPlus) || IS_CHAR( buffer[p], PrintUsingNumberMinus ) )
- {
- HeadChar = buffer[p];
- width++;
- p++;
- }
- while( IS_CHAR(buffer[p], PrintUsingNumberFiller) || IS_CHAR(buffer[p], PrintUsingNumberDollar ) )
- {
- if( IS_CHAR( buffer[p], PrintUsingNumberFiller ) )
- {
- FillChar = PrintUsingNumberFiller;
- }
- else
- if( IS_CHAR( buffer[p], PrintUsingNumberDollar ) )
- {
- CurrChar = PrintUsingNumberDollar;
- }
- width++;
- p++;
- }
- while( IS_CHAR(buffer[p], PrintUsingNumberDigit) || IS_CHAR(buffer[p], PrintUsingNumberComma ) )
- {
- if( IS_CHAR( buffer[p], PrintUsingNumberComma ) )
- {
- ComaChar = PrintUsingNumberComma;
- }
- width++;
- p++;
- }
- if( IS_CHAR( buffer[p], PrintUsingNumberPeriod ) )
- {
- while( IS_CHAR( buffer[p], PrintUsingNumberPeriod ) )
- {
- width++;
- p++;
- }
- while( IS_CHAR( buffer[p], PrintUsingNumberDigit ) )
- {
- precision++;
- width++;
- p++;
- }
- }
- while( IS_CHAR( buffer[p], PrintUsingNumberExponent ) )
- {
- exponent++;
- precision++;
- width++;
- p++;
- }
- while( IS_CHAR( buffer[p], PrintUsingNumberPlus ) || IS_CHAR( buffer[p], PrintUsingNumberMinus ) )
- {
- TailChar = buffer[p];
- width++;
- p++;
- }
- /* format the number */
-
-
- /* displaying both a Heading and a Trailing sign is NOT supported */
- if( TailChar == ' ' )
- {
- /* do nothing */
- }
- else
- if( IS_CHAR( TailChar, PrintUsingNumberPlus ) || IS_CHAR( TailChar, PrintUsingNumberMinus ) )
- {
- /* force the sign to be printed, so we can move it */
- HeadChar = TailChar;
- }
- else
- {
- WARN_INTERNAL_ERROR;
- return FALSE;
- }
-
-
- if( HeadChar == ' ' )
- {
- /* only display a '-' sign */
- if( exponent > 0 )
- {
- sprintf(tbuf, "%*.*e", width, precision, e->Number);
- }
- else
- {
- sprintf(tbuf, "%*.*f", width, precision, e->Number);
- }
- }
- else
- if( IS_CHAR( HeadChar, PrintUsingNumberPlus ) || IS_CHAR( HeadChar, PrintUsingNumberMinus ) )
- {
- /* force a leading sign '+' or '-' */
- if( exponent > 0 )
- {
- sprintf(tbuf, "%+*.*e", width, precision, e->Number);
- }
- else
- {
- sprintf(tbuf, "%+*.*f", width, precision, e->Number);
- }
- }
- else
- {
- WARN_INTERNAL_ERROR;
- return FALSE;
- }
-
- if( TailChar == ' ' )
- {
- /* do nothing */
- }
- else
- if( IS_CHAR( TailChar, PrintUsingNumberPlus ) || IS_CHAR( TailChar, PrintUsingNumberMinus ) )
- {
- /* move sign '+' or '-' to end */
- int i;
- int n;
-
- n = bwb_strlen(tbuf);
-
- for (i = 0; i < n; i++)
- {
- if( tbuf[i] != ' ' )
- {
- if( IS_CHAR( tbuf[i], PrintUsingNumberPlus ) )
- {
- tbuf[i] = ' ';
- if( IS_CHAR( TailChar, PrintUsingNumberPlus ) )
- {
- /* TailChar of '+' does print a '+' */
- bwb_strcat(tbuf,"+");
- }
- else
- if( IS_CHAR( TailChar, PrintUsingNumberMinus ) )
- {
- /* TailChar of '-' does NOT print a '+' */
- bwb_strcat(tbuf," ");
- }
- }
- else
- if( IS_CHAR( tbuf[i], PrintUsingNumberMinus ) )
- {
- tbuf[i] = ' ';
- bwb_strcat(tbuf,"-");
- }
- break;
- }
- }
- if( tbuf[0] == ' ' )
- {
- n = bwb_strlen(tbuf);
- /* n > 0 */
- for( i = 1; i < n; i++ )
- {
- tbuf[i-1] = tbuf[i];
- }
- tbuf[n-1] = BasicNulChar;
- }
- }
- else
- {
- WARN_INTERNAL_ERROR;
- return FALSE;
- }
-
-
- if( CurrChar == ' ' )
- {
- /* do nothing */
- }
- else
- if( IS_CHAR( CurrChar, PrintUsingNumberDollar ) )
- {
- int i;
- int n;
-
- n = bwb_strlen(tbuf);
-
- for (i = 0; i < n; i++)
- {
- if (tbuf[i] != ' ')
- {
- if (i > 0)
- {
- if (bwb_isdigit(tbuf[i]))
- {
- tbuf[i - 1] = CurrChar;
- }
- else
- {
- /* sign char */
- tbuf[i - 1] = tbuf[i];
- tbuf[i] = CurrChar;
- }
- }
- break;
- }
- }
- }
- else
- {
- WARN_INTERNAL_ERROR;
- return FALSE;
- }
-
- if( FillChar == ' ' )
- {
- /* do nothing */
- }
- else
- if( IS_CHAR( FillChar, PrintUsingNumberFiller ) )
- {
- int i;
- int n;
-
- n = bwb_strlen(tbuf);
-
- for (i = 0; i < n; i++)
- {
- if (tbuf[i] != ' ')
- {
- break;
- }
- tbuf[i] = PrintUsingNumberFiller;
- }
- }
- else
- {
- WARN_INTERNAL_ERROR;
- return FALSE;
- }
-
- if( ComaChar == ' ' )
- {
- prn_xxprintf(tbuf);
- }
- else
- if( IS_CHAR( ComaChar, PrintUsingNumberComma ) )
- {
- int dig_pos = -1;
- int dec_pos = -1;
- int i;
- int n;
- int commas;
-
- n = bwb_strlen(tbuf);
-
- for (i = 0; i < n; i++)
- {
- if ((bwb_isdigit(tbuf[i]) != 0) && (dig_pos == -1))
- {
- dig_pos = i;
- }
- if ((tbuf[i] == PrintUsingNumberPeriod) && (dec_pos == -1))
- {
- dec_pos = i;
- }
- if ((dig_pos != -1) && (dec_pos != -1))
- {
- break;
- }
- }
- if (dig_pos == -1)
- {
- dec_pos = n;
- }
- if (dec_pos == -1)
- {
- dec_pos = n;
- }
- /* count the number of commas */
- commas = 0;
- for (i = 0; i < n; ++i)
- {
- if (((dec_pos - i) % 3 == 0) && (i > dig_pos) && (i < dec_pos))
- {
- commas++;
- }
- }
- /* now, actually print */
- for( i = 0; i < n; i++ )
- {
- if( i < commas && IS_CHAR( tbuf[i], FillChar ) )
- {
- /*
- Ignore the same number of leading spaces as there are commas.
- While not perfect for all possible cases,
- it is usually good enough for practical purposes.
- */
- }
- else
- {
- if (((dec_pos - i) % 3 == 0) && (i > dig_pos) && (i < dec_pos))
- {
- xxputc(PrintUsingNumberComma);
- }
- xxputc(tbuf[i]);
- }
- }
- }
- else
- {
- WARN_INTERNAL_ERROR;
- return FALSE;
- }
- *position = p;
- return TRUE;
- }
-
- static int str_prnfmt(char *buffer, int *position, VariantType *e)
- {
- /*
- Format a STRING.
- 'buffer' points to the beginning of a PRINT USING format string, such as "###.##".
- 'position' is the current offset in 'buffer'.
- 'e' is the current expression to print.
- */
- int p;
- char tbuf[BasicStringLengthMax + 1];
-
- p = *position;
-
- if( e->TypeChar == BasicStringSuffix )
- {
- bwb_strcpy( tbuf, e->Buffer );
- }
- else
- {
- BasicNumerc( e->Number, tbuf );
- }
-
- if( IS_CHAR( buffer[ p ], PrintUsingStringFirst ) )
- {
- /* print first character only */
- int i = 0;
-
- if( tbuf[i] == BasicNulChar )
- {
- xxputc(' ');
- }
- else
- {
- xxputc(tbuf[i]);
- i++;
- }
- p++;
- }
- else
- if( IS_CHAR( buffer[ p ], PrintUsingStringAll ) )
- {
- /* print entire string */
- p++;
- prn_xxprintf(tbuf);
- }
- else
- if( IS_CHAR( buffer[ p ], PrintUsingStringLength ) )
- {
- /* print N characters or spaces */
- int i = 0;
-
- if( tbuf[i] == BasicNulChar )
- {
- xxputc(' ');
- }
- else
- {
- xxputc(tbuf[i]);
- i++;
- }
- p++;
-
- while( buffer[p] != BasicNulChar && buffer[p] != PrintUsingStringLength )
- {
- if( tbuf[i] == BasicNulChar )
- {
- xxputc(' ');
- }
- else
- {
- xxputc(tbuf[i]);
- i++;
- }
- p++;
- }
- if( buffer[p] == PrintUsingStringLength )
- {
- if( tbuf[i] == BasicNulChar )
- {
- xxputc(' ');
- }
- else
- {
- xxputc(tbuf[i]);
- i++;
- }
- p++;
- }
- }
- *position = p;
- return TRUE;
- }
-
- static int is_magic_string( char * buffer )
- {
- /*
- for the character string pointed to 'buffer':
- return TRUE if it is a MagicString sequence,
- return FALSE otherwise.
- */
- char *P;
-
- /* "!" */
- P = buffer;
- if( IS_CHAR( *P, PrintUsingStringFirst ) )
- {
- return TRUE;
- }
-
- /* "&" */
- P = buffer;
- if( IS_CHAR( *P, PrintUsingStringAll ) )
- {
- return TRUE;
- }
-
- /* "%...%" */
- P = buffer;
- if( IS_CHAR( *P, PrintUsingStringLength ) )
- {
- return TRUE;
- }
-
- return FALSE;
- }
-
- static int is_magic_number( char * buffer )
- {
- /*
- for the character string pointed to 'buffer':
- return TRUE if it is a MagicNumber sequence,
- return FALSE otherwise.
- */
- char *P;
-
- /* "+**" */
- P = buffer;
- if( IS_CHAR( *P, PrintUsingNumberPlus ) )
- {
- P++;
- if( IS_CHAR( *P, PrintUsingNumberFiller ) )
- {
- P++;
- if( IS_CHAR( *P, PrintUsingNumberFiller ) )
- {
- /* "+**" */
- return TRUE;
- }
- }
- }
-
- /* "+$$" */
- P = buffer;
- if( IS_CHAR( *P, PrintUsingNumberPlus ) )
- {
- P++;
- if( IS_CHAR( *P, PrintUsingNumberDollar ) )
- {
- P++;
- if( IS_CHAR( *P, PrintUsingNumberDollar ) )
- {
- /* "+$$" */
- return TRUE;
- }
- }
- }
-
- /* "+#" */
- P = buffer;
- if( IS_CHAR( *P, PrintUsingNumberPlus ) )
- {
- P++;
- if( IS_CHAR( *P, PrintUsingNumberDigit ) )
- {
- /* "+#" */
- return TRUE;
- }
- }
-
- /* "-**" */
- P = buffer;
- if( IS_CHAR( *P, PrintUsingNumberMinus ) )
- {
- P++;
- if( IS_CHAR( *P, PrintUsingNumberFiller ) )
- {
- P++;
- if( IS_CHAR( *P, PrintUsingNumberFiller ) )
- {
- /* "-**" */
- return TRUE;
- }
- }
- }
-
- /* "-$$" */
- P = buffer;
- if( IS_CHAR( *P, PrintUsingNumberMinus ) )
- {
- P++;
- if( IS_CHAR( *P, PrintUsingNumberDollar ) )
- {
- P++;
- if( IS_CHAR( *P, PrintUsingNumberDollar ) )
- {
- /* "-$$" */
- return TRUE;
- }
- }
- }
-
- /* "-#" */
- P = buffer;
- if( IS_CHAR( *P, PrintUsingNumberMinus ) )
- {
- P++;
- if( IS_CHAR( *P, PrintUsingNumberDigit ) )
- {
- /* "-#" */
- return TRUE;
- }
- }
-
- /* "**" */
- P = buffer;
- if( IS_CHAR( *P, PrintUsingNumberFiller ) )
- {
- P++;
- if( IS_CHAR( *P, PrintUsingNumberFiller ) )
- {
- /* "**" */
- return TRUE;
- }
- }
-
- /* "$$" */
- P = buffer;
- if( IS_CHAR( *P, PrintUsingNumberDollar ) )
- {
- P++;
- if( IS_CHAR( *P, PrintUsingNumberDollar ) )
- {
- /* "$$" */
- return TRUE;
- }
- }
-
- /* "#" */
- P = buffer;
- if( IS_CHAR( *P, PrintUsingNumberDigit ) )
- {
- /* "#" */
- return TRUE;
- }
-
- return FALSE;
- }
-
- static int get_prnfmt(char *buffer, int *position, VariantType *e)
- {
- /*
- Format an EXPRESSION.
- 'buffer' points to the beginning of a PRINT USING format string, such as "###.##".
- 'position' is the current offset in 'buffer'.
- 'e' is the current expression to print.
- */
-
-
-
- int p;
- int IsLoop = TRUE;
- int IsUsed = FALSE;
-
- bwx_DEBUG(__FUNCTION__);
-
-
- p = *position;
- if( p < 0 )
- {
- p = 0;
- }
- else
- if( p > 0 )
- {
- if( buffer[p] == BasicNulChar )
- {
- p = 0;
- }
- }
- while( IsLoop == TRUE )
- {
- if( buffer[p] == BasicNulChar )
- {
- IsLoop = FALSE;
- }
- else
- {
- int IsLiteral = TRUE;
-
-
- if( IsLiteral == TRUE )
- {
- char * S;
-
- S = buffer;
- S += p;
-
- if( is_magic_string( S ) )
- {
- /* MagicString Value */
- if( IsUsed == TRUE )
- {
- IsLoop = FALSE;
- }
- else
- if( e->TypeChar == BasicStringSuffix )
- {
- str_prnfmt( buffer, &p, e );
- IsUsed = TRUE;
- }
- else
- {
- IsLoop = FALSE;
- }
- IsLiteral = FALSE;
- }
- }
- if( IsLiteral == TRUE )
- {
- char * S;
-
- S = buffer;
- S += p;
-
- if( is_magic_number( S ) )
- {
- /* MagicNumber Value */
- if( IsUsed == TRUE )
- {
- IsLoop = FALSE;
- }
- else
- if( e->TypeChar == BasicStringSuffix )
- {
- IsLoop = FALSE;
- }
- else
- {
- num_prnfmt( buffer, &p, e );
- IsUsed = TRUE;
- }
- IsLiteral = FALSE;
- }
- }
- if( IsLiteral == TRUE )
- {
- if( PrintUsingLiteral != BasicNulChar && buffer[p] == PrintUsingLiteral )
- {
- /* print next character as literal */
- p++;
- if( buffer[p] == BasicNulChar )
- {
- /* PRINT USING "_" */
- xxputc(' ');
- }
- else
- {
- xxputc(buffer[p]);
- p++;
- }
- }
- else
- {
- xxputc(buffer[p]);
- p++;
- }
- }
-
- }
- }
-
- if( IsUsed == FALSE )
- {
-
- if( e->TypeChar == BasicStringSuffix )
- {
- /* PRINT USING "";A$ */
- /* PRINT USING "ABC";A$ */
- prn_iprintf(e->Buffer);
- }
- else
- {
- /* PRINT USING "";X */
- /* PRINT USING "ABC";X */
- /* [space]number[space] POSITIVE or ZERO
- * [minus]number[space] NEGATIVE */
- char tbuf[ 32 ];
-
- BasicNumerc(e->Number, tbuf);
-
- if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) && My->CurrentFile->FileNumber > 0 )
- {
- /* CBASIC-II: numbers in files do NOT have leading or trailing spaces */
- char * P;
- P = tbuf;
- while( *P == ' ' )
- {
- P++;
- }
- prn_iprintf( P );
- }
- else
- {
- prn_iprintf(tbuf);
- xputc(' ');
- }
- }
- }
- *position = p;
- return TRUE;
- }
-
- /***************************************************************
-
- FUNCTION: prn_iprintf()
-
- DESCRIPTION: This function outputs a null-terminated
- string to a specified file or output
- device.
-
- ***************************************************************/
-
- int
- prn_iprintf(char *buffer)
- {
- int n;
-
- bwx_DEBUG(__FUNCTION__);
-
- if (My->CurrentFile->width == 0)
- {
- /* ignore when WIDTH == 0 -- BINARY output */
- while (*buffer)
- {
- xxxputc(*buffer);
- buffer++;
- }
- return 0;
- }
- /* check to see if width will be exceeded */
- n = My->CurrentFile->col + bwb_strlen(buffer) - 1;
- if (n > My->CurrentFile->width)
- {
- xputc('\n');
- }
- /* output the string */
- while (*buffer)
- {
- xputc(*buffer);
- buffer++;
- }
- return 0;
- }
-
- /***************************************************************
-
- FUNCTION: prn_xxprintf()
-
- DESCRIPTION: This function outputs a null-terminated
- string to a specified file or output
- device without expanding tabs.
- Added by JBV 10/95
-
- ***************************************************************/
-
- static int prn_xxprintf(char *buffer)
- {
- int n;
-
- bwx_DEBUG(__FUNCTION__);
-
- if (My->CurrentFile->width == 0)
- {
- /* ignore when WIDTH == 0 -- BINARY output */
- while (*buffer)
- {
- xxxputc(*buffer);
- buffer++;
- }
- return 0;
- }
- /* check to see if width will be exceeded */
- n = My->CurrentFile->col + bwb_strlen(buffer) - 1;
- if (n > My->CurrentFile->width)
- {
- xxputc('\n');
- }
- /* output the string */
- while (*buffer)
- {
- xxputc(*buffer);
- buffer++;
- }
- return 0;
- }
-
- /***************************************************************
-
- FUNCTION: xputc()
-
- DESCRIPTION: This function outputs a character to a
- specified file or output device, expanding
- TABbed output approriately.
-
- ***************************************************************/
-
- static int xputc(char c)
- {
- static char CHR_pending = FALSE;
-
- bwx_DEBUG(__FUNCTION__);
-
- if (My->CurrentFile->width == 0)
- {
- /* ignore when WIDTH == 0 -- BINARY output */
- xxxputc(c);
- return 0;
- }
- /* check for pending SPC */
- if (CHR_pending == PRN_SPC)
- {
- /* 190 PRINT SPC(A);"X" ' A = 0...255 */
- int i;
- for (i = 0; i < c; i++)
- {
- xxputc(' ');
- }
- CHR_pending = FALSE;
- return TRUE;
- }
- /* check for pending TAB */
- if (CHR_pending == PRN_TAB)
- {
- /* WIDTH 80 */
- while (c > My->CurrentFile->width)
- {
- /* If n is greater than the margin m, then n is
- * reduced by an integral multiple of m so that it is
- * in the range 1 <= n <= m; */
- c -= My->CurrentFile->width;
- }
- /* 190 PRINT TAB(A);"X" ' A = 0 */
- if (c == 0)
- {
- /* use the value of one */
- c = 1;
- /* continue processing */
- }
- if ((int) c < My->CurrentFile->col)
- {
- xxputc('\n');
- }
- while (My->CurrentFile->col < (int) c)
- {
- xxputc(' ');
- }
- CHR_pending = FALSE;
- return TRUE;
- }
- /* check for specific output options */
- switch (c)
- {
- case PRN_SPC:
- case PRN_TAB:
- CHR_pending = c;
- break;
- case '\t':
- {
- int LastZoneColumn;
- LastZoneColumn = 1;
- while (LastZoneColumn < My->CurrentFile->width)
- {
- LastZoneColumn += ZONE_WIDTH;
- }
- LastZoneColumn -= ZONE_WIDTH;
-
- if (My->CurrentFile->col >= LastZoneColumn)
- {
- /* advance to a new line */
- xxputc('\n');
- }
- else
- {
- /* advance to the next print zone */
- if ((My->CurrentFile->col % ZONE_WIDTH) == 1)
- {
- xxputc(' ');
- }
- while ((My->CurrentFile->col % ZONE_WIDTH) != 1)
- {
- xxputc(' ');
- }
- }
- }
- break;
- default:
- xxputc(c);
- break;
- }
- return 0;
- }
-
- /***************************************************************
-
- FUNCTION: xxputc()
-
- DESCRIPTION: This function outputs a character to a
- specified file or output device, checking
- to be sure the PRINT width is within
- the bounds specified for that device.
-
- ***************************************************************/
-
- static int xxputc(char c)
- {
- bwx_DEBUG(__FUNCTION__);
-
- if (My->CurrentFile->width == 0)
- {
- /* ignore when WIDTH == 0 -- BINARY output */
- xxxputc(c);
- return 0;
- }
- /* check to see if width has been exceeded */
- if (c != '\n')
- {
- /* REM this should print one line, not two lines WIDTH 80
- * PRINT SPACE$( 80 ) */
- if (My->CurrentFile->col > My->CurrentFile->width)
- {
- xxxputc('\n'); /* output LF */
- }
- }
- /* output the character */
- xxxputc(c);
-
- return 0;
- }
-
- /***************************************************************
-
- FUNCTION: xxxputc()
-
- DESCRIPTION: This function sends a character to a
- specified file or output device.
-
- ***************************************************************/
-
-
- static int xxxputc(char c)
- {
- bwx_DEBUG(__FUNCTION__);
-
- if (My->CurrentFile == My->SYSPRN)
- {
- bwx_LPRINT(c);
- if (c == '\n' && My->SYSPRN->width > 0 && My->LPRINT_NULLS > 0)
- {
- int i;
- for (i = 0; i < My->LPRINT_NULLS; i++)
- {
- bwx_LPRINT(0);
- }
- }
- }
- else
- {
- if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) && c == '\n' )
- {
- if( My->CurrentFile->mode & DEVMODE_RANDOM && My->CurrentFile->width > 0 )
- {
- /* CBASIC-II: RANDOM files are padded on the right with spaces */
- while( My->CurrentFile->col < My->CurrentFile->width )
- {
- fputc(' ', My->CurrentFile->cfp);
- My->CurrentFile->col++;
- }
- }
- }
- fputc(c, My->CurrentFile->cfp);
- }
- /* update current column position */
- if (My->CurrentFile->width == 0)
- {
- /* ignore when WIDTH == 0 -- BINARY output */
- My->CurrentFile->col = 1;
- My->CurrentFile->row = 1;
- }
- else
- if (c == '\n')
- {
- My->CurrentFile->col = 1;
- My->CurrentFile->row ++;
- }
- else
- {
- My->CurrentFile->col ++;
- }
- return 0;
- }
-
-
- void
- ResetConsoleColumn( void )
- {
- bwx_DEBUG(__FUNCTION__);
-
- My->SYSOUT->col = 1;
- }
-
-
- LineType *
- bwb_PUT(LineType * l)
- {
- bwx_DEBUG(__FUNCTION__);
-
- if( My->CurrentVersion->OptionVersionBitmask & ( I70 | I73 ) )
- {
- /* PUT filename$ , value [, ...] */
- VariantType e; /* no leaks */
- VariantType *E = &e; /* no leaks */
-
- CLEAR_VARIANT( E );
- line_skip_spaces(l);
- if( line_read_expression( l, E ) == FALSE )
- {
- goto EXIT;
- }
- if( E->TypeChar == BasicStringSuffix )
- {
- /* STRING */
- /* PUT filename$ ... */
- if( is_empty_filename( E->Buffer ) )
- {
- /* "PUT # 0" is an error */
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- My->CurrentFile = find_file_by_name( E->Buffer );
- if( My->CurrentFile == NULL )
- {
- /* implicitly OPEN for writing */
- My->CurrentFile = file_new();
- My->CurrentFile->cfp = fopen(E->Buffer, "w");
- if( My->CurrentFile->cfp == NULL )
- {
- /* bad file name */
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- My->CurrentFile->FileNumber = file_next_number();
- My->CurrentFile->mode = DEVMODE_OUTPUT;
- My->CurrentFile->width = 0;
- /* WIDTH == RECLEN */
- My->CurrentFile->col = 1;
- My->CurrentFile->row = 1;
- My->CurrentFile->delimit = ',';
- My->CurrentFile->buffer = NULL;
- bwb_strcpy(My->CurrentFile->filename, E->Buffer);
- }
- }
- else
- {
- /* NUMBER -- file must already be OPEN */
- /* PUT filenumber ... */
- if( E->Number < 0 )
- {
- /* "PUT # -1" is an error */
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- if( E->Number == 0 )
- {
- /* "PUT # 0" is an error */
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- /* normal file */
- My->CurrentFile = find_file_by_number( (int) bwb_rint( E->Number ) );
- if( My->CurrentFile == NULL )
- {
- /* file not OPEN */
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- }
- RELEASE( E );
- if( My->CurrentFile == NULL )
- {
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- if (( My->CurrentFile->mode & DEVMODE_WRITE) == 0)
- {
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- if( line_is_eol(l) )
- {
- /* PUT F$ */
- /* PUT #1 */
- xputc('\n');
- goto EXIT;
- }
- else
- if (line_skip_comma(l))
- {
- /* OK */
- }
- else
- {
- WARN_SYNTAX_ERROR;
- goto EXIT;
- }
-
- /* loop through elements */
-
- while( ! line_is_eol(l) )
- {
- while (line_skip_comma(l))
- {
- /* PUT F$, ,,,A,,,B,,, */
- /* PUT #1, ,,,A,,,B,,, */
- xputc( My->CurrentFile->delimit );
- }
-
- if ( ! line_is_eol(l) )
- {
- /* print this item */
-
- /* get the next element */
- line_skip_spaces(l);
- if( line_read_expression( l, E ) == FALSE )
- {
- goto EXIT;
- }
- if( E->TypeChar == BasicStringSuffix )
- {
- /* STRING */
- xputc(BasicQuoteChar);
- prn_iprintf(E->Buffer);
- xputc(BasicQuoteChar);
- }
- else
- {
- /* NUMBER */
- char tbuf[ 32 ];
- BasicNumerc(E->Number, tbuf);
- prn_iprintf(tbuf);
- }
- RELEASE( E );
- }
- }
- /* print LF */
- xputc('\n');
- /* OK */
- EXIT:
- RELEASE( E );
- return bwb_zline(l);
- }
- else
- if( My->CurrentVersion->OptionVersionBitmask & ( D71 ) )
- {
- /* PUT # file_number [ , RECORD record_number ] */
- int file_number = 0;
- if( line_skip_char( l, BasicFileNumberPrefix ) == FALSE )
- {
- /* OPTIONAL */
- }
- if( line_read_integer_expression( l, &file_number ) == FALSE )
- {
- WARN_BAD_FILE_NUMBER;
- return bwb_zline( l );
- }
- if( file_number < 1 )
- {
- WARN_BAD_FILE_NUMBER;
- return bwb_zline( l );
- }
- My->CurrentFile = find_file_by_number( file_number );
- if( My->CurrentFile == NULL )
- {
- WARN_BAD_FILE_NUMBER;
- return bwb_zline( l );
- }
- if( My->CurrentFile->mode != DEVMODE_RANDOM )
- {
- WARN_BAD_FILE_NUMBER;
- return bwb_zline( l );
- }
- if( My->CurrentFile->width <= 0 )
- {
- WARN_BAD_FILE_NUMBER;
- return bwb_zline( l );
- }
- if( line_is_eol( l ) )
- {
- /* PUT # file_number */
- }
- else
- {
- /* PUT # file_number , RECORD record_number */
- int record_number = 0;
- long offset = 0;
- if( line_skip_comma( l ) == FALSE )
- {
- WARN_SYNTAX_ERROR;
- return bwb_zline( l );
- }
- if( line_skip_word( l, "RECORD" ) == FALSE )
- {
- WARN_SYNTAX_ERROR;
- return bwb_zline( l );
- }
- if( line_read_integer_expression( l, &record_number ) == FALSE )
- {
- WARN_BAD_RECORD_NUMBER;
- return bwb_zline( l );
- }
- if( record_number <= 0 )
- {
- WARN_BAD_RECORD_NUMBER;
- return bwb_zline( l );
- }
- record_number--; /* BASIC to C */
- offset = record_number;
- offset *= My->CurrentFile->width;
- if (fseek(My->CurrentFile->cfp, offset, SEEK_SET) != 0)
- {
- WARN_BAD_RECORD_NUMBER;
- return bwb_zline( l );
- }
- }
- field_put( My->CurrentFile );
- /* if( TRUE ) */
- {
- int i;
- for (i = 0; i < My->CurrentFile->width; i++)
- {
- char c;
- c = My->CurrentFile->buffer[i];
- fputc(c, My->CurrentFile->cfp);
- }
- }
- /* OK */
- return bwb_zline( l );
- }
- WARN_SYNTAX_ERROR;
- return bwb_zline(l);
- }
-
-
- /***************************************************************
-
- FUNCTION: bwb_write()
-
- DESCRIPTION: This C function implements the BASIC WRITE
- command.
-
- SYNTAX: WRITE [# device-number,] element [, element ]....
-
- ***************************************************************/
-
-
- LineType *
- bwb_WRITE(LineType * l)
- {
- int OutputCR;
- VariantType x; /* no leaks */
- VariantType *X = &x; /* no leaks */
-
- bwx_DEBUG(__FUNCTION__);
- CLEAR_VARIANT( X );
- My->CurrentFile = My->SYSOUT;
- if ( line_skip_char( l, BasicFileNumberPrefix ) )
- {
- int UserFileNumber;
-
- if( line_read_integer_expression(l, &UserFileNumber) == FALSE )
- {
- WARN_SYNTAX_ERROR;
- return bwb_zline(l);
- }
-
- /* check the requested device number */
- if( UserFileNumber < 0 )
- {
- My->CurrentFile = My->SYSPRN;
- }
- else
- if( UserFileNumber == 0 )
- {
- My->CurrentFile = My->SYSOUT;
- }
- else
- {
- /* normal file */
- My->CurrentFile = find_file_by_number( UserFileNumber );
- }
- if( My->CurrentFile == NULL )
- {
- WARN_BAD_FILE_NUMBER;
- return bwb_zline(l);
- }
- if (( My->CurrentFile->mode & DEVMODE_WRITE) == 0)
- {
- WARN_BAD_FILE_NUMBER;
- return bwb_zline(l);
- }
- if( line_is_eol(l) )
- {
- /* WRITE #1 */
- xputc('\n');
- return bwb_zline(l);
- }
- else
- if (line_skip_comma(l))
- {
- /* OK */
- }
- else
- {
- WARN_SYNTAX_ERROR;
- return bwb_zline(l);
- }
- }
-
-
- /* loop through elements */
- OutputCR = TRUE;
- line_skip_spaces( l );
- while( line_is_eol(l) == FALSE )
- {
- if( line_skip_comma(l) )
- {
- /* WRITE ,,,A,,,B,,, */
- /* WRITE #1, ,,,A,,,B,,, */
- OutputCR = FALSE;
- xputc( My->CurrentFile->delimit );
- }
- else
- {
- /* print the expression */
- OutputCR = TRUE;
- if( line_read_expression( l, X ) == FALSE )
- {
- goto EXIT;
- }
- if( bwb_Warning_Pending() /* Keep This */ )
- {
- /*
- this might look odd...
- but we want to abort printing on the first error.
- The expression list could include a function with side-effects,
- so any kind of error should immediately halt further evaluation.
- */
- goto EXIT;
- }
- if( X->TypeChar == BasicStringSuffix )
- {
- /* STRING */
- xputc(BasicQuoteChar);
- prn_iprintf(X->Buffer);
- xputc(BasicQuoteChar);
- }
- else
- {
- /* NUMBER */
- char tbuf[ 32 ];
- BasicNumerc(X->Number, tbuf);
- prn_iprintf(tbuf);
- }
- RELEASE( X );
- }
- line_skip_spaces( l );
- }
- /* print LF */
- if( OutputCR == TRUE )
- {
- xputc('\n');
- }
- EXIT:
- RELEASE( X );
- return bwb_zline(l);
- }
-
- static LineType * file_write_matrix( LineType * l, char delimit )
- {
- /* MAT PRINT arrayname [;|,] */
- /* Array must be 1, 2 or 3 dimensions */
- /* Array may be either NUMBER or STRING */
- VariableType *v;
- char ItemSeperator[2];
-
- bwx_DEBUG(__FUNCTION__);
-
- /* get the variable name */
- line_skip_spaces(l);
- while( bwb_isalpha( l->buffer[l->position] ) )
- {
- /* get matrix name */
- if((v = line_read_matrix( l )) == NULL)
- {
- WARN_SUBSCRIPT_OUT_OF_RANGE;
- return bwb_zline(l);
- }
-
- /* variable MUST be an array of 1, 2 or 3 dimensions */
- if (v->dimensions < 1)
- {
- WARN_SUBSCRIPT_OUT_OF_RANGE;
- return bwb_zline(l);
- }
- if(v->dimensions > 3)
- {
- WARN_SUBSCRIPT_OUT_OF_RANGE;
- return bwb_zline(l);
- }
-
-
- /*
- This may look odd, but MAT PRINT is special.
- The variable seperator AFTER the variable determines how
- the variable's values are printed.
- The number of dimension determines:
- a) the meaning of comma (,) and semicolon (;)
- b) the default of row-by-row or col-by-col
- */
- /* default the item seperator based upon variable's dimensions */
- ItemSeperator[0] = BasicNulChar;
- ItemSeperator[1] = BasicNulChar;
- switch( v->dimensions )
- {
- case 1:
- /* by default, a one dimension array is printed row-by-row */
- ItemSeperator[0] = '\n';
- break;
- case 2:
- /* by default, a two dimension array is printed col-by-col */
- ItemSeperator[0] = delimit;
- break;
- case 3:
- /* by default, a three dimension array is printed col-by-col */
- ItemSeperator[0] = delimit;
- break;
- }
- /* allow user to assign the item seperator */
- if( line_skip_char(l, ',' /* comma-specific */ ))
- {
- /* force printing col-by-col */
- ItemSeperator[0] = delimit;
- }
- else
- if( line_skip_char(l, ';' /* semicolon-specific */ ))
- {
- /* force concatenating the columns */
- ItemSeperator[0] = BasicNulChar;
- }
- /* print array */
- switch( v->dimensions )
- {
- case 1:
- {
- /*
- OPTION BASE 0
- DIM A(5)
- ...
- MAT PRINT A
- ...
- FOR I = 0 TO 5
- PRINT A(I)
- NEXT I
- ...
- */
- for( v->array_pos[0] = v->LBOUND[0]; v->array_pos[0] <= v->UBOUND[0]; v->array_pos[0]++ )
- {
- char tbuf[BasicStringLengthMax + 1];
-
- if( ItemSeperator[0] != BasicNulChar && v->array_pos[0] > v->LBOUND[0] )
- {
- prn_iprintf(ItemSeperator);
- }
- /* if( TRUE ) */
- {
- VariantType variant;
- if( var_get( v, &variant) == FALSE )
- {
- WARN_VARIABLE_NOT_DECLARED;
- return bwb_zline(l);
- }
- if( variant.TypeChar == '$' )
- {
- bwb_strcpy( tbuf, variant.Buffer );
- }
- else
- {
- BasicNumerc( variant.Number, tbuf );
- }
- }
- prn_iprintf(tbuf);
- }
- prn_iprintf("\n");
- }
- break;
- case 2:
- {
- /*
- OPTION BASE 0
- DIM B(2,3)
- ...
- MAT PRINT B
- ...
- FOR I = 0 TO 2
- FOR J = 0 TO 3
- PRINT B(I,J),
- NEXT J
- PRINT
- NEXT I
- ...
- */
- for( v->array_pos[0] = v->LBOUND[0]; v->array_pos[0] <= v->UBOUND[0]; v->array_pos[0]++ )
- {
- for( v->array_pos[1] = v->LBOUND[1]; v->array_pos[1] <= v->UBOUND[1]; v->array_pos[1]++ )
- {
- char tbuf[BasicStringLengthMax + 1];
-
- if( ItemSeperator[0] != BasicNulChar && v->array_pos[1] > v->LBOUND[1] )
- {
- prn_iprintf(ItemSeperator);
- }
- /* if( TRUE ) */
- {
- VariantType variant;
- if( var_get( v, &variant) == FALSE )
- {
- WARN_VARIABLE_NOT_DECLARED;
- return bwb_zline(l);
- }
- if( variant.TypeChar == '$' )
- {
- bwb_strcpy( tbuf, variant.Buffer );
- }
- else
- {
- BasicNumerc( variant.Number, tbuf );
- }
- }
- prn_iprintf(tbuf);
- }
- prn_iprintf("\n");
- }
- }
- break;
- case 3:
- {
- /*
- OPTION BASE 0
- DIM C(2,3,4)
- ...
- MAT PRINT C
- ...
- FOR I = 0 TO 2
- FOR J = 0 TO 3
- FOR K = 0 TO 4
- PRINT C(I,J,K),
- NEXT K
- PRINT
- NEXT J
- PRINT
- NEXT I
- ...
- */
- for( v->array_pos[0] = v->LBOUND[0]; v->array_pos[0] <= v->UBOUND[0]; v->array_pos[0]++ )
- {
- for( v->array_pos[1] = v->LBOUND[1]; v->array_pos[1] <= v->UBOUND[1]; v->array_pos[1]++ )
- {
- for( v->array_pos[2] = v->LBOUND[2]; v->array_pos[2] <= v->UBOUND[2]; v->array_pos[2]++ )
- {
- char tbuf[BasicStringLengthMax + 1];
-
- if( ItemSeperator[0] != BasicNulChar && v->array_pos[2] > v->LBOUND[2] )
- {
- prn_iprintf(ItemSeperator);
- }
- /* if( TRUE ) */
- {
- VariantType variant;
- if( var_get( v, &variant) == FALSE )
- {
- WARN_VARIABLE_NOT_DECLARED;
- return bwb_zline(l);
- }
- if( variant.TypeChar == '$' )
- {
- bwb_strcpy( tbuf, variant.Buffer );
- }
- else
- {
- BasicNumerc( variant.Number, tbuf );
- }
- }
- prn_iprintf(tbuf);
- }
- prn_iprintf("\n");
- }
- prn_iprintf("\n");
- }
- }
- break;
- }
- /* skip spaces */
- line_skip_spaces(l);
- /* process the next variable, if any */
- }
- return bwb_zline(l);
- }
-
-
- static LineType * bwb_mat_dump(LineType * l, int IsWrite )
- {
- /* MAT PRINT arrayname [;|,] */
- /* Array must be 1, 2 or 3 dimensions */
- /* Array may be either NUMBER or STRING */
- char delimit;
-
- bwx_DEBUG(__FUNCTION__);
-
- My->CurrentFile = My->SYSOUT;
- if ( line_skip_char( l, BasicFileNumberPrefix ) )
- {
- int UserFileNumber;
-
- if( line_read_integer_expression(l, &UserFileNumber) == FALSE )
- {
- WARN_SYNTAX_ERROR;
- return bwb_zline(l);
- }
-
- /* check the requested device number */
- if( UserFileNumber < 0 )
- {
- My->CurrentFile = My->SYSPRN;
- }
- else
- if( UserFileNumber == 0 )
- {
- My->CurrentFile = My->SYSOUT;
- }
- else
- {
- /* normal file */
- My->CurrentFile = find_file_by_number( UserFileNumber );
- }
- if( My->CurrentFile == NULL )
- {
- WARN_BAD_FILE_NUMBER;
- return bwb_zline(l);
- }
- if ((My->CurrentFile->mode & DEVMODE_WRITE) == 0)
- {
- WARN_BAD_FILE_NUMBER;
- return bwb_zline(l);
- }
- if (line_skip_comma(l))
- {
- /* OK */
- }
- else
- {
- WARN_SYNTAX_ERROR;
- return bwb_zline(l);
- }
- }
-
- if( IsWrite )
- {
- /* MAT WRITE */
- delimit = My->CurrentFile->delimit;
- }
- else
- {
- /* MAT PRINT */
- delimit = '\t';
- }
- return file_write_matrix( l, delimit );
- }
-
-
- LineType *
- bwb_MAT_PUT(LineType * l)
- {
- /* MAT PUT filename$ , matrix [, ...] */
-
- VariantType x; /* no leaks */
- VariantType *X = &x; /* no leaks */
-
- bwx_DEBUG(__FUNCTION__);
- CLEAR_VARIANT( X );
-
- My->CurrentFile = My->SYSOUT;
-
- line_skip_spaces(l);
- if( line_read_expression( l, X ) == FALSE )
- {
- goto EXIT;
- }
- if( X->TypeChar == BasicStringSuffix )
- {
- /* STRING */
- /* MAT PUT filename$ ... */
- if( is_empty_filename( X->Buffer ) )
- {
- /* "MAT PUT # 0" is an error */
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- My->CurrentFile = find_file_by_name( X->Buffer );
- if( My->CurrentFile == NULL )
- {
- /* implicitly OPEN for writing */
- My->CurrentFile = file_new();
- My->CurrentFile->cfp = fopen( X->Buffer, "w" );
- if( My->CurrentFile->cfp == NULL )
- {
- /* bad file name */
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- My->CurrentFile->FileNumber = file_next_number();
- My->CurrentFile->mode = DEVMODE_OUTPUT;
- My->CurrentFile->width = 0;
- /* WIDTH == RECLEN */
- My->CurrentFile->col = 1;
- My->CurrentFile->row = 1;
- My->CurrentFile->delimit = ',';
- My->CurrentFile->buffer = NULL;
- bwb_strcpy( My->CurrentFile->filename, X->Buffer );
- }
- }
- else
- {
- /* NUMBER -- file must already be OPEN */
- /* PUT filenumber ... */
- if( X->Number < 0 )
- {
- /* "MAT PUT # -1" is an error */
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- if( X->Number == 0 )
- {
- /* "MAT PUT # 0" is an error */
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- /* normal file */
- My->CurrentFile = find_file_by_number( (int) bwb_rint( X->Number ) );
- if( My->CurrentFile == NULL )
- {
- /* file not OPEN */
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- }
- RELEASE( X );
- if( My->CurrentFile == NULL )
- {
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- if (( My->CurrentFile->mode & DEVMODE_WRITE) == 0)
- {
- WARN_BAD_FILE_NUMBER;
- goto EXIT;
- }
- if ( line_skip_comma(l) )
- {
- /* OK */
- }
- else
- {
- WARN_SYNTAX_ERROR;
- goto EXIT;
- }
- return file_write_matrix( l, My->CurrentFile->delimit );
- EXIT:
- RELEASE( X );
- return bwb_zline(l);
- }
-
-
- LineType *
- bwb_MAT_WRITE(LineType * l)
- {
- return bwb_mat_dump( l, TRUE );
- }
-
- LineType *
- bwb_MAT_PRINT(LineType * l)
- {
- return bwb_mat_dump( l, FALSE );
- }
-
-
-
- /* EOF */
|