home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume33 / bwbasic / part05 < prev    next >
Encoding:
Text File  |  1992-11-03  |  56.4 KB  |  2,020 lines

  1. Newsgroups: comp.sources.misc
  2. From: tcamp@acpub.duke.edu (Ted A. Campbell)
  3. Subject:  v33i041:  bwbasic - Bywater BASIC interpreter version 1.10, Part05/11
  4. Message-ID: <1992Nov5.035806.17166@sparky.imd.sterling.com>
  5. X-Md4-Signature: f99323cadfaaa7cfdddaf982226689da
  6. Date: Thu, 5 Nov 1992 03:58:06 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: tcamp@acpub.duke.edu (Ted A. Campbell)
  10. Posting-number: Volume 33, Issue 41
  11. Archive-name: bwbasic/part05
  12. Environment: ANSI-C
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  bwb_mes.h bwb_prn.c
  19. # Wrapped by kent@sparky on Wed Nov  4 21:34:24 1992
  20. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  21. echo If this archive is complete, you will see the following message:
  22. echo '          "shar: End of archive 5 (of 11)."'
  23. if test -f 'bwb_mes.h' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'bwb_mes.h'\"
  25. else
  26.   echo shar: Extracting \"'bwb_mes.h'\" \(12471 characters\)
  27.   sed "s/^X//" >'bwb_mes.h' <<'END_OF_FILE'
  28. X/***************************************************************
  29. X
  30. X        bwb_mes.h       Header File for Natural-Language-Specific
  31. X                        Text Messages for Bywater BASIC Interpreter
  32. X
  33. X                        Copyright (c) 1992, Ted A. Campbell
  34. X
  35. X                        Bywater Software
  36. X                        P. O. Box 4023
  37. X                        Duke Station
  38. X                        Durham, NC  27706
  39. X
  40. X                        email: tcamp@acpub.duke.edu
  41. X
  42. X        Copyright and Permissions Information:
  43. X
  44. X        All U.S. and international copyrights are claimed by the
  45. X        author. The author grants permission to use this code
  46. X        and software based on it under the following conditions:
  47. X        (a) in general, the code and software based upon it may be
  48. X        used by individuals and by non-profit organizations; (b) it
  49. X        may also be utilized by governmental agencies in any country,
  50. X        with the exception of military agencies; (c) the code and/or
  51. X        software based upon it may not be sold for a profit without
  52. X        an explicit and specific permission from the author, except
  53. X        that a minimal fee may be charged for media on which it is
  54. X        copied, and for copying and handling; (d) the code must be
  55. X        distributed in the form in which it has been released by the
  56. X        author; and (e) the code and software based upon it may not
  57. X        be used for illegal activities.
  58. X
  59. X***************************************************************/
  60. X
  61. X
  62. X#ifndef TRUE
  63. X#define TRUE    1
  64. X#define FALSE   0
  65. X#endif
  66. X
  67. X/* Define only one of the following as TRUE: if none is defined,
  68. X   standard ENGLISH will be taken as the default */
  69. X
  70. X#define ENGLISH         TRUE        /* standard English */
  71. X#define POL_ENGLISH     FALSE        /* polite English messages */
  72. X#define IMP_ENGLISH    FALSE        /* impolite English messages */
  73. X#define LATIN        FALSE        /* Latin language messages */
  74. X
  75. X/****************************************************************
  76. X
  77. X    The following Latin conventions are used:
  78. X
  79. X    LATIN            ENGLISH
  80. X
  81. X    acies datorum        array (of data)
  82. X        crusta            shell
  83. X    litteras        (character) string
  84. X    memoria mutabilis    RAM
  85. X    organum            device
  86. X    ordo            line
  87. X    praeceptum        command
  88. X      praecepta          program (commands)
  89. X      praecepta interna      operating system
  90. X      praeceptellum          function
  91. X    tabula            file
  92. X
  93. X****************************************************************/
  94. X
  95. X#if LATIN
  96. X#define MES_SIGNON      "Interpres et Crusta <Super Flumina> ad linguam BASIC, versionis"
  97. X#define MES_COPYRIGHT   "Iure proprio scriptoris (c) 1992, Eduardi de Campobello"
  98. X#define MES_LANGUAGE    "Cum nuntiis latinis ab ipso E. de C."
  99. X#define PROMPT          "bwBASIC:"
  100. X#define ERROR_HEADER    "ERRANT praecepta in ordine"
  101. X#define MATHERR_HEADER  "ERRANT praecepta"
  102. X#define MES_BREAK       "Intermittuntur praecepta in ordine"
  103. X#define ERR_OPENFILE    "Non patet tabula quod <%s> vocatur"
  104. X#define ERR_GETMEM      "Deest memoria mutabilis"
  105. X#define ERR_LINENO      "Non adicitur novus ordo praeceptorum"
  106. X#define ERR_LNNOTFOUND  "Non invenitur ordo praeceptorum <%d>"
  107. X#define ERR_LOADNOFN    "LOAD requirit nomen ad tabulam"
  108. X#define ERR_NOLN        "Non invenitur ordo praeceptorum"
  109. X#define ERR_NOFN        "Non invenitur nomen ad tabulam"
  110. X#define ERR_RETNOGOSUB  "RETURN sine GOSUB"
  111. X#define ERR_INCOMPLETE  "Praeceptum imcompletum"
  112. X#define ERR_ONNOGOTO    "ON sine GOTO sive GOSUB"
  113. X#define ERR_VALOORANGE  "Numerus in praeceptis excedit fines"
  114. X#define ERR_SYNTAX      "Non sequunter praecepta"
  115. X#define ERR_DEVNUM      "Numerus ad organum invalidum est"
  116. X#define ERR_DEV         "Errat organum"
  117. X#define ERR_OPSYS    "Errant praecepta interna"
  118. X#define ERR_ARGSTR    "Praeceptum requirit litteras"
  119. X#define ERR_DEFCHAR    "ad varium definiendum"
  120. X#define ERR_MISMATCH    "Non congruunt typus"
  121. X#define ERR_DIMNOTARRAY    "Praeceptum requirit nomen ad aciem datorum"
  122. X#define ERR_OD        "Desunt data"
  123. X#define ERR_OVERFLOW    "Data excedunt fines"
  124. X#define ERR_NF        "NEXT sine FOR"
  125. X#define ERR_UF        "Non definitur praeceptellum"
  126. X#define ERR_DBZ        "Non licet divisio ab nihilo"
  127. X#define ERR_REDIM    "Non licet varium iterum definiendum"
  128. X#define ERR_OBDIM    "Debet OPTION BASE procedere DIM"
  129. X#define ERR_UC        "Praeceptum incognitum est"
  130. X#endif
  131. X
  132. X#if POL_ENGLISH
  133. X#define MES_SIGNON      "Bywater BASIC Interpreter/Shell, version"
  134. X#define MES_COPYRIGHT   "Copyright (c) 1992, Ted A. Campbell"
  135. X#define MES_LANGUAGE    "Polite English messages courtesy of t.a.c."
  136. X#define PROMPT          "How may we help you?"
  137. X#define ERROR_HEADER    "Very sorry. There is a problem in line"
  138. X#define MATHERR_HEADER  "We have a small problem"
  139. X#define MES_BREAK       "At your request, the program has been interrupted at line"
  140. X#define ERR_OPENFILE    "I'm afraid we have failed \nto open file %s."
  141. X#define ERR_GETMEM      "I'm afraid we have failed \nto find sufficient memory."
  142. X#define ERR_LINENO      "I'm afraid we have failed \nto link line number."
  143. X#define ERR_LNNOTFOUND  "I'm afraid that we \ncannot find line number %d."
  144. X#define ERR_LOADNOFN    "Could you perhaps specify \nwhich file you wish to be loaded?"
  145. X#define ERR_NOLN        "It would help greatly \nif there were a line number here."
  146. X#define ERR_NOFN        "It would help greatly \nif there were a file name here."
  147. X#define ERR_RETNOGOSUB  "Is it possible \nthat there is a RETURN without a GOSUB here?"
  148. X#define ERR_INCOMPLETE  "I'm afraid that the statement\nappears to be incomplete."
  149. X#define ERR_ONNOGOTO    "It appears that there is an ON \nwithout a corresponding GOTO or GOSUB statement."
  150. X#define ERR_VALOORANGE  "A value given here \nseems to be out of range."
  151. X#define ERR_SYNTAX      "Could it be \nthat there is a syntax error at this point?"
  152. X#define ERR_DEVNUM      "The device or file \nnumber here does not seem to be correct."
  153. X#define ERR_DEV         "There appears \nto have been an error addressing the file or device \nwhich you requested."
  154. X#define ERR_OPSYS    "A most unfortunate error \nseems to have been generated by the computer's operating system."
  155. X#define ERR_ARGSTR    "Could you perhaps \nsupply a string argument at this point?"
  156. X#define ERR_DEFCHAR    "The variable definition \nat this point appears to have an improper argument."
  157. X#define ERR_MISMATCH    "It would appear \nthat something in this statement is rather seriously mismatched."
  158. X#define ERR_DIMNOTARRAY    "Could you perhaps \nsupply an array name for the argument at this point?"
  159. X#define ERR_OD        "Oh dear, we seem to have no more data to read now."
  160. X#define ERR_OVERFLOW    "Subhuman devices \ndo have their limits, and we're afraid that at this point \nthe limits of Bywater BASIC have been exceeded."
  161. X#define ERR_NF        "There seems to be \na NEXT statement without a corresponding FOR statement. Could you check on it?"
  162. X#define ERR_UF        "It would appear \nthat the function named at this point has not been defined."
  163. X#define ERR_DBZ        "Unfortunately, \ndivision by zero can cause dreadful problems in a computer."
  164. X#define ERR_REDIM    "We're very sorry \nto say that a variable such as this cannot be redimensioned."
  165. X#define ERR_OBDIM    "It would be ever so helpful \nif the OPTION BASE statement were to be called prior to the DIM statement."
  166. X#define ERR_UC        "I'm afraid that \nwe are unable to recognize the command you have given here."
  167. X#endif
  168. X
  169. X#if IMP_ENGLISH
  170. X#define MES_SIGNON      "Bywater BASIC Interpreter/Shell, version"
  171. X#define MES_COPYRIGHT   "Watch it: Copyright (c) 1992, Ted A. Campbell"
  172. X#define MES_LANGUAGE    "Impolite English messages courtesy of Oscar the Grouch"
  173. X#define PROMPT          "(*sigh) What now?"
  174. X#define ERROR_HEADER    "YOU SCREWED UP at line"
  175. X#define MATHERR_HEADER  "ANOTHER SCREWUP!"
  176. X#define MES_BREAK       "Only a geek like you would interrupt this program at line"
  177. X#define ERR_OPENFILE    "Ha ha! I can't open file %s. Too bad, sucker."
  178. X#define ERR_GETMEM      "There isn't near enough memory \nfor this lunacy."
  179. X#define ERR_LINENO      "You jerk: \nyou entered a non-existent line number."
  180. X#define ERR_LNNOTFOUND  "You total idiot.  \nLine number %d isn't there. HA!"
  181. X#define ERR_LOADNOFN    "Get out of here. \nNo way to load that file."
  182. X#define ERR_NOLN        "Dumb bozo: you need to put \na LINE NUMBER here. Hint: Can you count?"
  183. X#define ERR_NOFN        "Nerd of the year. \nYou forgot to enter a file name. \nWhy don't you learn BASIC and come back in a year?"
  184. X#define ERR_RETNOGOSUB  "Oh come on, total amateur. \nYou've got a RETURN without a GOSUB"
  185. X#define ERR_INCOMPLETE  "Dimwit. Why don't you \ncomplete the statement here for a change."
  186. X#define ERR_ONNOGOTO    "You failed again: \nON without a GOTO or GOSUB."
  187. X#define ERR_VALOORANGE  "Go home, beginner. \nThe value here is way out of range."
  188. X#define ERR_SYNTAX      "Sure sign of a fourth-rate programmer: \nThis makes no sense at all."
  189. X#define ERR_DEVNUM      "Way to go, space cadet. \nThe device (or file) number here is totally in orbit."
  190. X#define ERR_DEV         "HO! The file or device \n you requested says: DROP DEAD."
  191. X#define ERR_OPSYS    "You obviously don't know \nwhat this computer can or can't do."
  192. X#define ERR_ARGSTR    "Do you have big ears? \n(Like Dumbo?) You obviously need a string argument at this point."
  193. X#define ERR_DEFCHAR    "Amazing. Surely children \nknow how to form a corrent argument here."
  194. X#define ERR_MISMATCH    "No way, turkey. \nThe statement here is TOTALLY mismatched."
  195. X#define ERR_DIMNOTARRAY    "Incredible. Why don't you \nsuppy an ARRAY NAME where the prograqm calls for an ARRAY NAME? (Or just go home.)"
  196. X#define ERR_OD        "Have you ever studied BASIC before? \nYou've run out of data."
  197. X#define ERR_OVERFLOW    "Congratulations on writing a program \nthat totally exceeds all limits."
  198. X#define ERR_NF        "Go back to kindergarten: \nYou have a NEXT statement FOR."
  199. X#define ERR_UF        "Trash. Total trash. \nDefine your stupid functions before calling them."
  200. X#define ERR_DBZ        "Obviously, you'll never be a programmer. \nYou've tried division by zero here."
  201. X#define ERR_REDIM    "You just don't understand: \nyou cannot redimension this variable."
  202. X#define ERR_OBDIM    "Dork. You called OPTION BASE after DIM. \nLeave me alone."
  203. X#define ERR_UC        "What do you think this is? \nTry entering a BASIC command here."
  204. X#endif
  205. X
  206. X/* Standard English is taken as a default: if MES_SIGNON is not defined by
  207. X   this time (i.e., by some other language definition), then
  208. X   the following standard English definitions are utilized. */
  209. X
  210. X#ifndef MES_SIGNON
  211. X#define MES_SIGNON      "Bywater BASIC Interpreter/Shell, version"
  212. X#define MES_COPYRIGHT   "Copyright (c) 1992, Ted A. Campbell"
  213. X#define MES_LANGUAGE    "Default English-Language Messages"
  214. X#define PROMPT          "bwBASIC:"
  215. X#define ERROR_HEADER    "ERROR in line"
  216. X#define MATHERR_HEADER  "ERROR"
  217. X#define MES_BREAK       "Program interrupted at line"
  218. X#define ERR_OPENFILE    "Failed to open file %s"
  219. X#define ERR_GETMEM      "Failed to find memory"
  220. X#define ERR_LINENO      "Failed to link line number"
  221. X#define ERR_LNNOTFOUND  "Line number %d not found"
  222. X#define ERR_LOADNOFN    "LOAD: no filename specified"
  223. X#define ERR_NOLN        "No line number"
  224. X#define ERR_NOFN        "No file name"
  225. X#define ERR_RETNOGOSUB  "RETURN without GOSUB"
  226. X#define ERR_INCOMPLETE  "Incomplete statement"
  227. X#define ERR_ONNOGOTO    "ON without GOTO or GOSUB"
  228. X#define ERR_VALOORANGE  "Value is out of range"
  229. X#define ERR_SYNTAX      "Syntax error"
  230. X#define ERR_DEVNUM      "Invalid device number"
  231. X#define ERR_DEV         "Device error"
  232. X#define ERR_OPSYS    "Error in operating system command"
  233. X#define ERR_ARGSTR    "Argument must be a string"
  234. X#define ERR_DEFCHAR    "Incorrect argument for variable definition"
  235. X#define ERR_MISMATCH    "Type mismatch"
  236. X#define ERR_DIMNOTARRAY    "Argument is not an array name"
  237. X#define ERR_OD        "Out of data"
  238. X#define ERR_OVERFLOW    "Overflow"
  239. X#define ERR_NF        "NEXT without FOR"
  240. X#define ERR_UF        "Undefined function"
  241. X#define ERR_DBZ        "Divide by zero"
  242. X#define ERR_REDIM    "Variable cannot be redimensioned"
  243. X#define ERR_OBDIM    "OPTION BASE must be called prior to DIM"
  244. X#define ERR_UC        "Unknown command"
  245. X#endif
  246. X
  247. Xextern char err_openfile[];
  248. Xextern char err_getmem[];
  249. Xextern char err_noln[];
  250. Xextern char err_nofn[];
  251. Xextern char err_lnnotfound[];
  252. Xextern char err_incomplete[];
  253. Xextern char err_valoorange[];
  254. Xextern char err_syntax[];
  255. Xextern char err_devnum[];
  256. Xextern char err_dev[];
  257. Xextern char err_opsys[]; 
  258. Xextern char err_argstr[];
  259. Xextern char err_defchar[];
  260. Xextern char err_mismatch[];
  261. Xextern char err_dimnotarray[];
  262. Xextern char err_od[];
  263. Xextern char err_overflow[];
  264. Xextern char err_nf[];
  265. Xextern char err_uf[];
  266. Xextern char err_dbz[];
  267. Xextern char err_redim[];
  268. Xextern char err_obdim[];
  269. Xextern char err_uc[];
  270. END_OF_FILE
  271.   if test 12471 -ne `wc -c <'bwb_mes.h'`; then
  272.     echo shar: \"'bwb_mes.h'\" unpacked with wrong size!
  273.   fi
  274.   # end of 'bwb_mes.h'
  275. fi
  276. if test -f 'bwb_prn.c' -a "${1}" != "-c" ; then 
  277.   echo shar: Will not clobber existing file \"'bwb_prn.c'\"
  278. else
  279.   echo shar: Extracting \"'bwb_prn.c'\" \(41227 characters\)
  280.   sed "s/^X//" >'bwb_prn.c' <<'END_OF_FILE'
  281. X/***************************************************************
  282. X
  283. X        bwb_prn.c       Print Commands
  284. X                        for Bywater BASIC Interpreter
  285. X
  286. X                        Copyright (c) 1992, Ted A. Campbell
  287. X
  288. X                        Bywater Software
  289. X                        P. O. Box 4023
  290. X                        Duke Station
  291. X                        Durham, NC  27706
  292. X
  293. X                        email: tcamp@acpub.duke.edu
  294. X
  295. X        Copyright and Permissions Information:
  296. X
  297. X        All U.S. and international copyrights are claimed by the
  298. X        author. The author grants permission to use this code
  299. X        and software based on it under the following conditions:
  300. X        (a) in general, the code and software based upon it may be
  301. X        used by individuals and by non-profit organizations; (b) it
  302. X        may also be utilized by governmental agencies in any country,
  303. X        with the exception of military agencies; (c) the code and/or
  304. X        software based upon it may not be sold for a profit without
  305. X        an explicit and specific permission from the author, except
  306. X        that a minimal fee may be charged for media on which it is
  307. X        copied, and for copying and handling; (d) the code must be
  308. X        distributed in the form in which it has been released by the
  309. X        author; and (e) the code and software based upon it may not
  310. X        be used for illegal activities.
  311. X
  312. X***************************************************************/
  313. X
  314. X#include <stdio.h>
  315. X#include <stdlib.h>
  316. X#include <ctype.h>
  317. X#include <string.h>
  318. X#include <math.h>
  319. X
  320. X#include "bwbasic.h"
  321. X#include "bwb_mes.h"
  322. X
  323. X/* Prototypes for functions visible only to this file */
  324. X
  325. Xstatic int prn_cr( char *buffer, FILE *f );
  326. Xstatic int prn_col = 1;
  327. Xstatic int prn_width = 80;    /* default width for stdout */
  328. Xstatic struct bwb_variable * bwb_esetovar( struct exp_ese *e );
  329. X
  330. Xstruct prn_fmt
  331. X   {
  332. X   int type;            /* STRING, DOUBLE, SINGLE, or INTEGER */
  333. X   int exponential;        /* TRUE = use exponential notation */
  334. X   int right_justified;        /* TRUE = right justified else left justified */
  335. X   int width;            /* width of main section */
  336. X   int precision;        /* width after decimal point */
  337. X   int commas;            /* use commas every three steps */
  338. X   int sign;            /* prefix sign to number */
  339. X   int money;            /* prefix money sign to number */
  340. X   int fill;            /* ASCII value for fill character, normally ' ' */
  341. X   int minus;            /* postfix minus sign to number */
  342. X   };
  343. X
  344. Xstatic struct prn_fmt *get_prnfmt( char *buffer, int *position, FILE *f );
  345. Xstatic int bwb_xerror( char *message );
  346. Xstatic int xxputc( FILE *f, char c );
  347. X
  348. X/***************************************************************
  349. X
  350. X        FUNCTION:       bwb_print()
  351. X
  352. X        DESCRIPTION:    This function implements the BASIC PRINT
  353. X                        command.
  354. X
  355. X***************************************************************/
  356. X
  357. Xstruct bwb_line *
  358. Xbwb_print( struct bwb_line *l )
  359. X   {
  360. X   FILE *fp;
  361. X   static int pos;
  362. X   int req_devnumber;
  363. X   struct exp_ese *v;
  364. X   static char *s_buffer;              /* small, temporary buffer */
  365. X   static int init = FALSE;
  366. X
  367. X   #if INTENSIVE_DEBUG
  368. X   sprintf( bwb_ebuf, "in bwb_print(): enter function" );
  369. X   bwb_debug( bwb_ebuf );
  370. X   #endif
  371. X
  372. X   /* initialize buffers if necessary */
  373. X
  374. X   if ( init == FALSE )
  375. X      {
  376. X      init = TRUE;
  377. X      if ( ( s_buffer = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  378. X         {
  379. X         bwb_error( err_getmem );
  380. X         }
  381. X      }
  382. X
  383. X   /* advance beyond whitespace and check for the '#' sign */
  384. X   
  385. X   adv_ws( l->buffer, &( l->position ) );
  386. X   
  387. X   if ( l->buffer[ l->position ] == '#' )
  388. X      {
  389. X      ++( l->position );
  390. X      adv_element( l->buffer, &( l->position ), s_buffer );
  391. X      pos = 0;
  392. X      v = bwb_exp( s_buffer, FALSE, &pos );
  393. X      adv_ws( l->buffer, &( l->position ) );
  394. X      if ( l->buffer[ l->position ] == ',' )
  395. X         {
  396. X         ++( l->position );
  397. X         }
  398. X      else
  399. X         {
  400. X     #if PROG_ERRORS
  401. X         bwb_error( "in bwb_print(): no comma after #n" );
  402. X         #else
  403. X         bwb_error( err_syntax );
  404. X         #endif
  405. X         l->next->position = 0;
  406. X         return l->next;
  407. X         }
  408. X
  409. X      req_devnumber = exp_getival( v );
  410. X
  411. X      /* check the requested device number */
  412. X      
  413. X      if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  414. X         {
  415. X         #if PROG_ERRORS
  416. X         bwb_error( "in bwb_input(): Requested device number is out of range." );
  417. X         #else
  418. X         bwb_error( err_devnum );
  419. X         #endif
  420. X         l->next->position = 0;
  421. X         return l->next;
  422. X         }
  423. X
  424. X      if (( dev_table[ req_devnumber ].mode == DEVMODE_CLOSED ) ||
  425. X         ( dev_table[ req_devnumber ].mode == DEVMODE_AVAILABLE ))
  426. X         {
  427. X         #if PROG_ERRORS
  428. X         bwb_error( "in bwb_input(): Requested device number is not open." );
  429. X         #else
  430. X         bwb_error( err_devnum );
  431. X         #endif
  432. X
  433. X         l->next->position = 0;
  434. X         return l->next;
  435. X         }
  436. X
  437. X      if ( dev_table[ req_devnumber ].mode != DEVMODE_OUTPUT )
  438. X         {
  439. X         #if PROG_ERRORS
  440. X         bwb_error( "in bwb_print(): Requested device is not open for OUTPUT." );
  441. X         #else
  442. X         bwb_error( err_devnum );
  443. X         #endif
  444. X
  445. X         l->next->position = 0;
  446. X         return l->next;
  447. X         }
  448. X
  449. X      #if INTENSIVE_DEBUG
  450. X      sprintf( bwb_ebuf, "in bwb_print(): device number is <%d>",
  451. X         req_devnumber );
  452. X      bwb_debug( bwb_ebuf );
  453. X      #endif
  454. X
  455. X      /* look up the requested device in the device table */
  456. X
  457. X      fp = dev_table[ req_devnumber ].cfp;
  458. X
  459. X      }
  460. X
  461. X   else
  462. X      {
  463. X      fp = stdout;
  464. X      }
  465. X
  466. X   bwb_xprint( l, fp );
  467. X
  468. X   l->next->position = 0;
  469. X   return l->next;
  470. X   }
  471. X
  472. X/***************************************************************
  473. X
  474. X        FUNCTION:       bwb_xprint()
  475. X
  476. X        DESCRIPTION:
  477. X
  478. X***************************************************************/
  479. X
  480. Xint
  481. Xbwb_xprint( struct bwb_line *l, FILE *f )
  482. X   {
  483. X   struct exp_ese *e;
  484. X   int loop;
  485. X   static int p;
  486. X   static int fs_pos;
  487. X   struct prn_fmt *format;
  488. X   static char *format_string;
  489. X   static char *output_string;
  490. X   static char *element;
  491. X   static char *prnbuf;
  492. X   static int init = FALSE;
  493. X   #if INTENSIVE_DEBUG || TEST_BSTRING
  494. X   bstring *b;
  495. X   #endif
  496. X
  497. X   /* initialize buffers if necessary */
  498. X
  499. X   if ( init == FALSE )
  500. X      {
  501. X      init = TRUE;
  502. X      if ( ( format_string = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  503. X         {
  504. X         bwb_error( err_getmem );
  505. X         }
  506. X      if ( ( output_string = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  507. X         {
  508. X         bwb_error( err_getmem );
  509. X         }      
  510. X      if ( ( element = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  511. X         {
  512. X         bwb_error( err_getmem );
  513. X         }      
  514. X      if ( ( prnbuf = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  515. X         {
  516. X         bwb_error( err_getmem );
  517. X         }      
  518. X      }
  519. X
  520. X   /* Detect USING Here */
  521. X
  522. X   fs_pos = -1;
  523. X
  524. X   /* get "USING" in format_string */
  525. X
  526. X   p = l->position;
  527. X   adv_element( l->buffer, &p, format_string );
  528. X   bwb_strtoupper( format_string );
  529. X
  530. X   /* check to be sure */
  531. X
  532. X   if ( strcmp( format_string, "USING" ) == 0 )
  533. X      {
  534. X      l->position = p;
  535. X      adv_ws( l->buffer, &( l->position ) );
  536. X
  537. X      /* now get the format string in format_string */
  538. X
  539. X      e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  540. X      if ( e->type == STRING )
  541. X         {
  542. X
  543. X         /* copy the format string to buffer */
  544. X
  545. X         str_btoc( format_string, exp_getsval( e ) );
  546. X
  547. X         /* look for ';' after format string */
  548. X
  549. X         fs_pos = 0;
  550. X         adv_ws( l->buffer, &( l->position ) );
  551. X         if ( l->buffer[ l->position ] == ';' )
  552. X            {
  553. X            ++l->position;
  554. X            adv_ws( l->buffer, &( l->position ) );
  555. X            }
  556. X         else
  557. X            {
  558. X            #if PROG_ERRORS
  559. X            bwb_error( "Failed to find \";\" after format string in PRINT USING" );
  560. X            #else
  561. X            bwb_error( err_syntax );
  562. X            #endif
  563. X            return FALSE;
  564. X            }
  565. X
  566. X         #if INTENSIVE_DEBUG
  567. X         sprintf( bwb_ebuf, "in bwb_xprint(): Found USING, format string <%s>",
  568. X            format_string );
  569. X         bwb_debug( bwb_ebuf );
  570. X         #endif
  571. X
  572. X         }
  573. X
  574. X      else
  575. X         {
  576. X         #if PROG_ERRORS
  577. X         bwb_error( "Failed to find format string after PRINT USING" );
  578. X         #else
  579. X         bwb_error( err_syntax );
  580. X         #endif
  581. X         return FALSE;
  582. X         }
  583. X      }
  584. X
  585. X   /* if no arguments, simply print CR and return */
  586. X
  587. X   adv_ws( l->buffer, &( l->position ) );
  588. X   switch( l->buffer[ l->position ] )
  589. X      {
  590. X      case '\0':
  591. X      case '\n':
  592. X      case '\r':
  593. X      case ':':
  594. X         xprintf( f, "\n" );
  595. X         return TRUE;
  596. X      default:
  597. X         break;
  598. X      }
  599. X
  600. X   /* LOOP THROUGH PRINT ELEMENTS */
  601. X
  602. X   loop = TRUE;
  603. X   while( loop == TRUE )
  604. X      {
  605. X
  606. X      /* resolve the string */
  607. X
  608. X      e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  609. X
  610. X      #if INTENSIVE_DEBUG
  611. X      sprintf( bwb_ebuf, "in bwb_xprint(): op <%d> type <%c>",
  612. X         e->operation, e->type );
  613. X      bwb_debug( bwb_ebuf );
  614. X      #endif
  615. X
  616. X      /* an OP_NULL probably indicates a terminating ';', but this
  617. X         will be detected later, so we can ignore it for now */
  618. X
  619. X      if ( e->operation != OP_NULL )
  620. X         {
  621. X         #if TEST_BSTRING
  622. X         b = exp_getsval( e );
  623. X         sprintf( bwb_ebuf, "in bwb_xprint(): bstring name is <%s>",
  624. X            b->name );
  625. X         bwb_debug( bwb_ebuf );
  626. X         #endif
  627. X         str_btoc( element, exp_getsval( e ) );
  628. X         }
  629. X      else
  630. X         {
  631. X         element[ 0 ] = '\0';
  632. X         }
  633. X
  634. X      #if INTENSIVE_DEBUG
  635. X      sprintf( bwb_ebuf, "in bwb_xprint(): element <%s>",
  636. X         element );
  637. X      bwb_debug( bwb_ebuf );
  638. X      #endif
  639. X
  640. X      /* print with format if there is one */
  641. X
  642. X      if (( fs_pos > -1 ) && ( strlen( element ) > 0 ))
  643. X         {
  644. X         format = get_prnfmt( format_string, &fs_pos, f );
  645. X
  646. X         #if INTENSIVE_DEBUG
  647. X         sprintf( bwb_ebuf, "in bwb_xprint(): format type <%c> width <%d>",
  648. X            format->type, format->width );
  649. X         bwb_debug( bwb_ebuf );
  650. X         #endif
  651. X
  652. X         switch( format->type )
  653. X            {
  654. X            case STRING:
  655. X               if ( e->type != STRING )
  656. X                  {
  657. X                  #if PROG_ERRORS
  658. X                  bwb_error( "Type mismatch in PRINT USING" );
  659. X                  #else
  660. X                  bwb_error( err_mismatch );
  661. X                  #endif
  662. X                  }
  663. X               sprintf( output_string, "%.*s", format->width,
  664. X                  element );
  665. X
  666. X               #if INTENSIVE_DEBUG
  667. X               sprintf( bwb_ebuf, "in bwb_xprint(): output string <%s>",
  668. X                  output_string );
  669. X               bwb_debug( bwb_ebuf );
  670. X               #endif
  671. X
  672. X               xprintf( f, output_string );
  673. X               break;
  674. X            case INTEGER:
  675. X               if ( e->type == STRING )
  676. X                  {
  677. X                  #if PROG_ERRORS
  678. X                  bwb_error( "Type mismatch in PRINT USING" );
  679. X                  #else
  680. X                  bwb_error( err_mismatch );
  681. X                  #endif
  682. X                  }
  683. X               sprintf( output_string, "%.*d", format->width,
  684. X                  exp_getival( e ) );
  685. X               xprintf( f, output_string );
  686. X               break;
  687. X            case SINGLE:
  688. X            case DOUBLE:
  689. X               if ( e->type == STRING )
  690. X                  {
  691. X                  #if PROG_ERRORS
  692. X                  bwb_error( "Type mismatch in PRINT USING" );
  693. X                  #else
  694. X                  bwb_error( err_mismatch );
  695. X                  #endif
  696. X                  }
  697. X               if ( format->exponential == TRUE )
  698. X                  {
  699. X                  sprintf( output_string, "%.le", 
  700. X                     e->dval );
  701. X                  xprintf( f, output_string );
  702. X                  }
  703. X               else
  704. X                  {
  705. X                  sprintf( output_string, "%*.*lf", 
  706. X                     format->width + 1 + format->precision,
  707. X                     format->precision, e->dval );
  708. X                  xprintf( f, output_string );
  709. X                  }
  710. X               break;
  711. X            default:
  712. X               #if PROG_ERRORS
  713. X               sprintf( bwb_ebuf, "in bwb_xprint(): get_prnfmt() returns unknown type <%c>",
  714. X                  format->type );
  715. X               bwb_error( bwb_ebuf );
  716. X               #else
  717. X               bwb_error( err_mismatch );
  718. X               #endif
  719. X               break;
  720. X            }
  721. X         }
  722. X
  723. X      /* not a format string: use defaults */
  724. X
  725. X      else if ( strlen( element ) > 0 )
  726. X         {
  727. X
  728. X         switch( e->type )
  729. X            {
  730. X            case STRING:
  731. X               xprintf( f, element );
  732. X               break;
  733. X            case INTEGER:
  734. X               sprintf( prnbuf, " %d", exp_getival( e ) );
  735. X               xprintf( f, prnbuf );
  736. X               break;
  737. X            case DOUBLE:
  738. X               sprintf( prnbuf, " %.*f", prn_precision( bwb_esetovar( e )), 
  739. X                  exp_getdval( e ) );
  740. X               xprintf( f, prnbuf );
  741. X               break;
  742. X            default:
  743. X               sprintf( prnbuf, " %.*f", prn_precision( bwb_esetovar( e )), 
  744. X                  exp_getfval( e ) );
  745. X               xprintf( f, prnbuf );
  746. X               break;
  747. X            }
  748. X         }
  749. X
  750. X      /* check the position to see if the loop should continue */
  751. X
  752. X      adv_ws( l->buffer, &( l->position ) );
  753. X      switch( l->buffer[ l->position ] )
  754. X         {
  755. X         case ':':        /* end of line segment */
  756. X        loop = FALSE;
  757. X/*        ++( l->position ); */
  758. X        break;
  759. X         case '\0':        /* end of buffer */
  760. X         case '\n':
  761. X         case '\r':
  762. X        loop = FALSE;
  763. X            break;
  764. X         case ',':        /* tab over */
  765. X            xputc( f, '\t' );
  766. X            ++l->position;
  767. X            adv_ws( l->buffer, &( l->position ) );
  768. X            break;
  769. X         case ';':        /* concatenate strings */
  770. X            ++l->position;
  771. X            adv_ws( l->buffer, &( l->position ) );
  772. X            break;
  773. X         }
  774. X
  775. X      }                /* end of loop through print elements */
  776. X
  777. X   /* call prn_cr() to print a CR if it is not overridden by a
  778. X      concluding ';' mark */
  779. X
  780. X   prn_cr( l->buffer, f ); 
  781. X
  782. X   return TRUE;
  783. X
  784. X   }                            /* end of function bwb_xprint() */
  785. X
  786. X/***************************************************************
  787. X
  788. X        FUNCTION:       get_prnfmt()
  789. X
  790. X        DESCRIPTION:
  791. X
  792. X***************************************************************/
  793. X
  794. Xstruct prn_fmt *
  795. Xget_prnfmt( char *buffer, int *position, FILE *f )
  796. X   {
  797. X   static struct prn_fmt retstruct;
  798. X   register int c;
  799. X   int loop;
  800. X
  801. X   /* set some defaults */
  802. X
  803. X   retstruct.type = FALSE;
  804. X   retstruct.exponential = FALSE;
  805. X   retstruct.right_justified = FALSE;
  806. X   retstruct.commas = FALSE;
  807. X   retstruct.sign = FALSE;
  808. X   retstruct.money = FALSE;
  809. X   retstruct.fill = ' ';
  810. X   retstruct.minus = FALSE;
  811. X
  812. X   /* check for negative position */
  813. X
  814. X   if ( *position < 0 )
  815. X      {
  816. X      return &retstruct;
  817. X      }
  818. X
  819. X   /* advance past whitespace */
  820. X
  821. X   adv_ws( buffer, position );
  822. X
  823. X   /* check first character: a lost can be decided right here */
  824. X
  825. X   loop = TRUE;
  826. X   while( loop == TRUE )
  827. X      {
  828. X
  829. X      #if INTENSIVE_DEBUG
  830. X      sprintf( bwb_ebuf, "in get_prnfmt(): loop, buffer <%s>",
  831. X         &( buffer[ *position ] ) );
  832. X      bwb_debug( bwb_ebuf );
  833. X      #endif
  834. X
  835. X      switch( buffer[ *position ] )
  836. X         {
  837. X         case ' ':        /* end of this format segment */
  838. X            loop = FALSE;
  839. X            break;
  840. X         case '\0':        /* end of format string */
  841. X         case '\n':
  842. X         case '\r':
  843. X            *position = -1;
  844. X            return &retstruct;
  845. X         case '_':        /* print next character as literal */
  846. X            ++( *position );
  847. X            xputc( f, buffer[ *position ] );
  848. X            ++( *position );
  849. X            break;
  850. X         case '!':
  851. X            retstruct.type = STRING;
  852. X            retstruct.width = 1;
  853. X            return &retstruct;
  854. X         case '\\':
  855. X            #if INTENSIVE_DEBUG
  856. X            sprintf( bwb_ebuf, "in get_prnfmt(): found \\" );
  857. X            bwb_debug( bwb_ebuf );
  858. X            #endif
  859. X            retstruct.type = STRING;
  860. X            ++( *position );
  861. X            for ( retstruct.width = 0; buffer[ *position ] == ' '; ++( *position ) )
  862. X               {
  863. X               ++retstruct.width;
  864. X               }
  865. X            if ( buffer[ *position ] == '\\' )
  866. X               {
  867. X               ++( *position );
  868. X               }
  869. X            return &retstruct;
  870. X         case '$':
  871. X            ++( *position );
  872. X            retstruct.money = TRUE;
  873. X            if ( buffer[ *position ] == '$' )
  874. X               {
  875. X               ++( *position );
  876. X               }
  877. X            break;
  878. X         case '*':
  879. X            ++( *position );
  880. X            retstruct.fill = '*';
  881. X            if ( buffer[ *position ] == '*' )
  882. X               {
  883. X               ++( *position );
  884. X               }
  885. X            break;
  886. X         case '+':
  887. X            ++( *position );
  888. X            retstruct.sign = TRUE;
  889. X            break;
  890. X         case '#':
  891. X            retstruct.type = INTEGER;        /* for now */
  892. X            ++( *position );
  893. X            for ( retstruct.width = 1; buffer[ *position ] == '#'; ++( *position ) )
  894. X               {
  895. X               ++retstruct.width;
  896. X               }
  897. X            if ( buffer[ *position ] == ',' )
  898. X               {
  899. X               retstruct.commas = TRUE;
  900. X               }
  901. X            if ( buffer[ *position ] == '.' )
  902. X               {
  903. X               retstruct.type = DOUBLE;
  904. X               ++( *position );
  905. X               for ( retstruct.precision = 0; buffer[ *position ] == '#'; ++( *position ) )
  906. X                  {
  907. X                  ++retstruct.precision;
  908. X                  }
  909. X               }
  910. X            if ( buffer[ *position ] == '-' )
  911. X               {
  912. X               retstruct.minus = TRUE;
  913. X               ++( *position );
  914. X               }
  915. X            return &retstruct;
  916. X         case '^':
  917. X            retstruct.type = DOUBLE;
  918. X            retstruct.exponential = TRUE;
  919. X            for ( retstruct.width = 1; buffer[ *position ] == '^'; ++( *position ) )
  920. X               {
  921. X               ++retstruct.width;
  922. X               }
  923. X            return &retstruct;
  924. X         
  925. X         }
  926. X      }                    /* end of loop */
  927. X      
  928. X   return &retstruct;
  929. X   }
  930. X   
  931. X/***************************************************************
  932. X
  933. X        FUNCTION:       bwb_cr()
  934. X
  935. X        DESCRIPTION:
  936. X
  937. X***************************************************************/
  938. X
  939. Xint
  940. Xprn_cr( char *buffer, FILE *f )
  941. X   {
  942. X   register int c;
  943. X   int loop;
  944. X
  945. X   /* find the end of the buffer */
  946. X
  947. X   for ( c = 0; buffer[ c ] != '\0'; ++c )
  948. X      {
  949. X      }
  950. X
  951. X   #if INTENSIVE_DEBUG
  952. X   sprintf( bwb_ebuf, "in prn_cr(): initial c is <%d>", c );
  953. X   bwb_debug( bwb_ebuf );
  954. X   #endif
  955. X
  956. X   /* back up through any whitespace */
  957. X
  958. X   loop = TRUE;
  959. X   while ( loop == TRUE )
  960. X      {
  961. X      switch( buffer[ c ] )
  962. X         {
  963. X         case ' ':                              /* if whitespace */
  964. X         case '\t':
  965. X         case 0:
  966. X
  967. X            #if INTENSIVE_DEBUG
  968. X            sprintf( bwb_ebuf, "in prn_cr(): backup: c is <%d>, char <%c>[0x%x]",
  969. X               c, buffer[ c ], buffer[ c ] );
  970. X            bwb_debug( bwb_ebuf );
  971. X            #endif
  972. X
  973. X            --c;                                /* back up */
  974. X            if ( c < 0 )                        /* check position */
  975. X               {
  976. X               loop = FALSE;
  977. X               }
  978. X            break;
  979. X
  980. X         default:                               /* else break out */
  981. X            #if INTENSIVE_DEBUG
  982. X            sprintf( bwb_ebuf, "in prn_cr(): breakout: c is <%d>, char <%c>[0x%x]",
  983. X               c, buffer[ c ], buffer[ c ] );
  984. X            bwb_debug( bwb_ebuf );
  985. X            #endif
  986. X            loop = FALSE;
  987. X            break;
  988. X         }
  989. X      }
  990. X
  991. X   if ( buffer[ c ] == ';' )
  992. X      {
  993. X
  994. X      #if INTENSIVE_DEBUG
  995. X      sprintf( bwb_ebuf, "in prn_cr(): concluding <;> detected." );
  996. X      bwb_debug( bwb_ebuf );
  997. X      #endif
  998. X
  999. X      return FALSE;
  1000. X      }
  1001. X
  1002. X   else
  1003. X      {
  1004. X      xprintf( f, "\n" );
  1005. X      return TRUE;
  1006. X      }
  1007. X
  1008. X   }
  1009. X
  1010. X/***************************************************************
  1011. X
  1012. X        FUNCTION:       xprintf()
  1013. X
  1014. X        DESCRIPTION:
  1015. X
  1016. X***************************************************************/
  1017. X
  1018. Xint
  1019. Xxprintf( FILE *f, char *buffer )
  1020. X   {
  1021. X   char *p;
  1022. X
  1023. X   /* DO NOT try anything so stupid as to run bwb_debug() from 
  1024. X      here, because it will create an endless loop. And don't
  1025. X      ask how I know. */
  1026. X
  1027. X   for ( p = buffer; *p != '\0'; ++p )
  1028. X      {
  1029. X      xputc( f, *p );
  1030. X      }
  1031. X
  1032. X   return TRUE;
  1033. X   }
  1034. X
  1035. X/***************************************************************
  1036. X
  1037. X        FUNCTION:       xputc()
  1038. X
  1039. X        DESCRIPTION:
  1040. X
  1041. X***************************************************************/
  1042. X
  1043. Xint
  1044. Xxputc( FILE *f, char c )
  1045. X   {
  1046. X   static int tab_pending = FALSE;
  1047. X   register int i;
  1048. X
  1049. X   /* check for pending TAB */
  1050. X
  1051. X   if ( tab_pending == TRUE )
  1052. X      {
  1053. X      if ( (int) c < ( * prn_getcol( f ) ) )
  1054. X         {
  1055. X         xxputc( f, '\n' );
  1056. X         }
  1057. X      while( ( * prn_getcol( f )) < (int) c )
  1058. X         {
  1059. X         xxputc( f, ' ' );
  1060. X         }
  1061. X      tab_pending = FALSE;
  1062. X      return TRUE;
  1063. X      }
  1064. X
  1065. X   /* check c for specific output options */
  1066. X
  1067. X   switch( c )
  1068. X      {
  1069. X      case PRN_TAB:
  1070. X         tab_pending = TRUE;
  1071. X         break;
  1072. X
  1073. X      case '\t':
  1074. X         while( ( (* prn_getcol( f )) % 14 ) != 0 )
  1075. X            {
  1076. X            xxputc( f, ' ' );
  1077. X            }
  1078. X         break;
  1079. X
  1080. X      default:
  1081. X         xxputc( f, c );
  1082. X         break;
  1083. X      }
  1084. X
  1085. X   return TRUE;
  1086. X
  1087. X   }
  1088. X
  1089. X/***************************************************************
  1090. X
  1091. X        FUNCTION:       xxputc()
  1092. X
  1093. X        DESCRIPTION:
  1094. X
  1095. X***************************************************************/
  1096. X
  1097. Xint
  1098. Xxxputc( FILE *f, char c )
  1099. X   {
  1100. X
  1101. X   /* check to see if width has been exceeded */
  1102. X
  1103. X   if ( * prn_getcol( f ) >= prn_getwidth( f ))
  1104. X      {
  1105. X      fputc( '\n', f );            /* output LF */
  1106. X      * prn_getcol( f ) = 1;        /* and reset */
  1107. X      }
  1108. X
  1109. X   /* adjust the column counter */
  1110. X
  1111. X   if ( c == '\n' )
  1112. X      {
  1113. X      * prn_getcol( f ) = 1;
  1114. X      }
  1115. X   else
  1116. X      {
  1117. X      ++( * prn_getcol( f ));
  1118. X      }
  1119. X      
  1120. X   /* now output the character */
  1121. X
  1122. X   return fputc( c, f );
  1123. X
  1124. X   }
  1125. X
  1126. X/***************************************************************
  1127. X
  1128. X        FUNCTION:       prn_getcol()
  1129. X
  1130. X        DESCRIPTION:
  1131. X
  1132. X***************************************************************/
  1133. X
  1134. Xint *
  1135. Xprn_getcol( FILE *f )
  1136. X   {
  1137. X   register int n;
  1138. X   static int dummy_pos;
  1139. X
  1140. X   if (( f == stdout ) || ( f == stderr ))
  1141. X      {
  1142. X      return &prn_col;
  1143. X      }
  1144. X
  1145. X   for ( n = 0; n < DEF_DEVICES; ++n )
  1146. X      {
  1147. X      if ( dev_table[ n ].cfp == f )
  1148. X         {
  1149. X         return &( dev_table[ n ].col );
  1150. X         }
  1151. X      }
  1152. X
  1153. X   /* search failed */
  1154. X
  1155. X   #if PROG_ERRORS
  1156. X   bwb_error( "in prn_getcol(): failed to find file pointer" );
  1157. X   #else
  1158. X   bwb_error( err_devnum );
  1159. X   #endif
  1160. X
  1161. X   return &dummy_pos;
  1162. X
  1163. X   }
  1164. X
  1165. X/***************************************************************
  1166. X
  1167. X        FUNCTION:       prn_getwidth()
  1168. X
  1169. X        DESCRIPTION:
  1170. X
  1171. X***************************************************************/
  1172. X
  1173. Xint
  1174. Xprn_getwidth( FILE *f )
  1175. X   {
  1176. X   register int n;
  1177. X
  1178. X   if (( f == stdout ) || ( f == stderr ))
  1179. X      {
  1180. X      return prn_width;
  1181. X      }
  1182. X
  1183. X   for ( n = 0; n < DEF_DEVICES; ++n )
  1184. X      {
  1185. X      if ( dev_table[ n ].cfp == f )
  1186. X         {
  1187. X         return dev_table[ n ].width;
  1188. X         }
  1189. X      }
  1190. X
  1191. X   /* search failed */
  1192. X
  1193. X   #if PROG_ERRORS
  1194. X   bwb_error( "in prn_getwidth(): failed to find file pointer" );
  1195. X   #else
  1196. X   bwb_error( err_devnum );
  1197. X   #endif
  1198. X
  1199. X   return 1;
  1200. X
  1201. X   }
  1202. X
  1203. X/***************************************************************
  1204. X
  1205. X        FUNCTION:       prn_precision()
  1206. X
  1207. X        DESCRIPTION:
  1208. X
  1209. X***************************************************************/
  1210. X
  1211. Xint
  1212. Xprn_precision( struct bwb_variable *v )
  1213. X   {
  1214. X   int max_precision = 6;
  1215. X   double dval, d;
  1216. X   int r;
  1217. X
  1218. X   /* check for double value */
  1219. X
  1220. X   if ( v->type == DOUBLE )
  1221. X      {
  1222. X      max_precision = 12;
  1223. X      }
  1224. X
  1225. X   /* get the value in dval */
  1226. X
  1227. X   dval = var_getdval( v );
  1228. X
  1229. X   /* cycle through until precision is found */
  1230. X
  1231. X   d = 1.0;
  1232. X   for ( r = 0; r < max_precision; ++r )
  1233. X      {
  1234. X
  1235. X      #if INTENSIVE_DEBUG
  1236. X      sprintf( bwb_ebuf, "in prn_precision(): fmod( %f, %f ) = %.12f",
  1237. X         dval, d, fmod( dval, d ) );
  1238. X      bwb_debug( bwb_ebuf );
  1239. X      #endif
  1240. X
  1241. X      if ( fmod( dval, d ) < 0.0000001 )
  1242. X         {
  1243. X         return r;
  1244. X         }
  1245. X      d /= 10;
  1246. X      }
  1247. X
  1248. X   /* return */
  1249. X
  1250. X   return r;
  1251. X
  1252. X   }
  1253. X
  1254. X/***************************************************************
  1255. X
  1256. X        FUNCTION:       fnc_tab()
  1257. X
  1258. X        DESCRIPTION:    
  1259. X
  1260. X***************************************************************/
  1261. X
  1262. Xstruct bwb_variable *
  1263. Xfnc_tab( int argc, struct bwb_variable *argv )
  1264. X   {
  1265. X   static struct bwb_variable nvar;
  1266. X   static int init = FALSE;
  1267. X   static char t_string[ 4 ];
  1268. X   static char nvar_name[] = "(tmp)";
  1269. X   bstring *b;
  1270. X   
  1271. X   /* initialize nvar if necessary */
  1272. X
  1273. X   if ( init == FALSE )
  1274. X      {
  1275. X      init = TRUE;
  1276. X      var_make( &nvar, (int) STRING );
  1277. X/*      nvar.name = nvar_name; */
  1278. X      }
  1279. X
  1280. X   /* check for correct number of parameters */
  1281. X
  1282. X   if ( argc < 1 )
  1283. X      {
  1284. X      #if PROG_ERRORS
  1285. X      sprintf( bwb_ebuf, "Not enough parameters (%d) to function TAB().",
  1286. X         argc );
  1287. X      bwb_error( bwb_ebuf );
  1288. X      #else
  1289. X      bwb_error( err_syntax );
  1290. X      #endif
  1291. X      break_handler();
  1292. X      return NULL;
  1293. X      }
  1294. X   else if ( argc > 1 )
  1295. X      {
  1296. X      #if PROG_ERRORS
  1297. X      sprintf( bwb_ebuf, "Too many parameters (%d) to function TAB().",
  1298. X         argc );
  1299. X      bwb_error( bwb_ebuf );
  1300. X      #else
  1301. X      bwb_error( err_syntax );
  1302. X      #endif
  1303. X      break_handler();
  1304. X      return NULL;
  1305. X      }
  1306. X
  1307. X   t_string[ 0 ] = PRN_TAB;
  1308. X   t_string[ 1 ] = (char) var_getival( &( argv[ 0 ] ));
  1309. X   t_string[ 2 ] = '\0';
  1310. X
  1311. X   b = var_getsval( &nvar );
  1312. X   str_ctob( b, t_string );
  1313. X
  1314. X   return &nvar;
  1315. X   }
  1316. X
  1317. X/***************************************************************
  1318. X
  1319. X        FUNCTION:       fnc_spc()
  1320. X
  1321. X        DESCRIPTION:    
  1322. X
  1323. X***************************************************************/
  1324. X
  1325. Xstruct bwb_variable *
  1326. Xfnc_spc( int argc, struct bwb_variable *argv )
  1327. X   {
  1328. X   return fnc_space( argc, argv );
  1329. X   }
  1330. X
  1331. X/***************************************************************
  1332. X
  1333. X        FUNCTION:       fnc_space()
  1334. X
  1335. X        DESCRIPTION:    
  1336. X
  1337. X***************************************************************/
  1338. X
  1339. Xstruct bwb_variable *
  1340. Xfnc_space( int argc, struct bwb_variable *argv )
  1341. X   {
  1342. X   static struct bwb_variable nvar;
  1343. X   static char *tbuf;
  1344. X   static int init = FALSE;
  1345. X   int spaces;
  1346. X   register int i;
  1347. X   bstring *b;
  1348. X   
  1349. X   /* check for correct number of parameters */
  1350. X
  1351. X   if ( argc < 1 )
  1352. X      {
  1353. X      #if PROG_ERRORS
  1354. X      sprintf( bwb_ebuf, "Not enough parameters (%d) to function SPACE$().",
  1355. X         argc );
  1356. X      bwb_error( bwb_ebuf );
  1357. X      #else
  1358. X      bwb_error( err_syntax );
  1359. X      #endif
  1360. X      break_handler();
  1361. X      return NULL;
  1362. X      }
  1363. X   else if ( argc > 1 )
  1364. X      {
  1365. X      #if PROG_ERRORS
  1366. X      sprintf( bwb_ebuf, "Too many parameters (%d) to function SPACE$().",
  1367. X         argc );
  1368. X      bwb_error( bwb_ebuf );
  1369. X      #else
  1370. X      bwb_error( err_syntax );
  1371. X      #endif
  1372. X      break_handler();
  1373. X      return NULL;
  1374. X      }
  1375. X
  1376. X   /* initialize nvar if necessary */
  1377. X
  1378. X   if ( init == FALSE )
  1379. X      {
  1380. X      init = TRUE;
  1381. X      var_make( &nvar, (int) STRING );
  1382. X      if ( ( tbuf = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  1383. X         {
  1384. X         bwb_error( err_getmem );
  1385. X         }
  1386. X      }
  1387. X
  1388. X   tbuf[ 0 ] = '\0';
  1389. X   spaces = var_getival( &( argv[ 0 ] ));
  1390. X
  1391. X   /* add spaces to the string */
  1392. X
  1393. X   for ( i = 0; i < spaces; ++i )
  1394. X      {
  1395. X      tbuf[ i ] = ' ';
  1396. X      tbuf[ i + 1 ] = '\0';
  1397. X      }
  1398. X
  1399. X   b = var_getsval( &nvar );
  1400. X   str_ctob( b, tbuf );
  1401. X
  1402. X   return &nvar;
  1403. X   }
  1404. X
  1405. X/***************************************************************
  1406. X
  1407. X        FUNCTION:       fnc_pos()
  1408. X
  1409. X        DESCRIPTION:    
  1410. X
  1411. X***************************************************************/
  1412. X
  1413. Xstruct bwb_variable *
  1414. Xfnc_pos( int argc, struct bwb_variable *argv )
  1415. X   {
  1416. X   static struct bwb_variable nvar;
  1417. X   static int init = FALSE;
  1418. X   static char nvar_name[] = "<pos()>";
  1419. X
  1420. X   /* initialize nvar if necessary */
  1421. X
  1422. X   if ( init == FALSE )
  1423. X      {
  1424. X      init = TRUE;
  1425. X      var_make( &nvar, (int) INTEGER );
  1426. X/*      nvar.name = nvar_name; */
  1427. X      }
  1428. X
  1429. X   * var_findival( &nvar, nvar.array_pos ) = prn_col;
  1430. X
  1431. X   return &nvar;
  1432. X   }
  1433. X
  1434. X/***************************************************************
  1435. X
  1436. X        FUNCTION:       fnc_err()
  1437. X
  1438. X        DESCRIPTION:    
  1439. X
  1440. X***************************************************************/
  1441. X
  1442. Xstruct bwb_variable *
  1443. Xfnc_err( int argc, struct bwb_variable *argv )
  1444. X   {
  1445. X   static struct bwb_variable nvar;
  1446. X   static int init = FALSE;
  1447. X   static char nvar_name[] = "<err()>";
  1448. X
  1449. X   /* initialize nvar if necessary */
  1450. X
  1451. X   if ( init == FALSE )
  1452. X      {
  1453. X      init = TRUE;
  1454. X      var_make( &nvar, (int) INTEGER );
  1455. X/*      nvar.name = nvar_name; */
  1456. X      }
  1457. X
  1458. X   * var_findival( &nvar, nvar.array_pos ) = err_number;
  1459. X
  1460. X   return &nvar;
  1461. X   }
  1462. X
  1463. X/***************************************************************
  1464. X
  1465. X        FUNCTION:       fnc_erl()
  1466. X
  1467. X        DESCRIPTION:    
  1468. X
  1469. X***************************************************************/
  1470. X
  1471. Xstruct bwb_variable *
  1472. Xfnc_erl( int argc, struct bwb_variable *argv )
  1473. X   {
  1474. X   static struct bwb_variable nvar;
  1475. X   static int init = FALSE;
  1476. X   static char nvar_name[] = "<erl()>";
  1477. X
  1478. X   /* initialize nvar if necessary */
  1479. X
  1480. X   if ( init == FALSE )
  1481. X      {
  1482. X      init = TRUE;
  1483. X      var_make( &nvar, (int) INTEGER );
  1484. X/*      nvar.name = nvar_name; */
  1485. X      }
  1486. X
  1487. X   * var_findival( &nvar, nvar.array_pos ) = err_line;
  1488. X
  1489. X   return &nvar;
  1490. X   }
  1491. X
  1492. X/***************************************************************
  1493. X
  1494. X        FUNCTION:       bwb_debug()
  1495. X
  1496. X        DESCRIPTION:    This function is called to display
  1497. X                        debugging messages in Bywater BASIC.
  1498. X                        It does not break out at the current
  1499. X                        point (as bwb_error() does).
  1500. X
  1501. X***************************************************************/
  1502. X
  1503. X#if PERMANENT_DEBUG
  1504. Xint
  1505. Xbwb_debug( char *message )
  1506. X   {
  1507. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  1508. X
  1509. X   fflush( stdout );
  1510. X   fflush( errfdevice );
  1511. X   if ( prn_col != 1 )
  1512. X      {
  1513. X      xprintf( errfdevice, "\n" );
  1514. X      }
  1515. X   sprintf( tbuf, "DEBUG %s\n", message );
  1516. X   xprintf( errfdevice, tbuf );
  1517. X
  1518. X   return TRUE;
  1519. X   }
  1520. X#endif
  1521. X
  1522. X/***************************************************************
  1523. X
  1524. X        FUNCTION:       bwb_lerror()
  1525. X
  1526. X        DESCRIPTION:    This function implements the BASIC ERROR
  1527. X                        command.
  1528. X
  1529. X***************************************************************/
  1530. X
  1531. Xstruct bwb_line *
  1532. Xbwb_lerror( struct bwb_line *l )
  1533. X   {
  1534. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  1535. X   int n;
  1536. X
  1537. X   #if INTENSIVE_DEBUG
  1538. X   sprintf( bwb_ebuf, "in bwb_lerror(): entered function " );
  1539. X   bwb_debug( bwb_ebuf );
  1540. X   #endif
  1541. X
  1542. X   /* Check for argument */
  1543. X
  1544. X   adv_ws( l->buffer, &( l->position ) );
  1545. X   switch( l->buffer[ l->position ] )
  1546. X      {
  1547. X      case '\0':
  1548. X      case '\n':
  1549. X      case '\r':
  1550. X      case ':':
  1551. X         bwb_error( err_incomplete );
  1552. X         l->next->position = 0;
  1553. X         return l->next;
  1554. X      default:
  1555. X         break;
  1556. X      }
  1557. X
  1558. X   /* get the variable name or numerical constant */
  1559. X
  1560. X   adv_element( l->buffer, &( l->position ), tbuf );
  1561. X   n = atoi( tbuf );
  1562. X
  1563. X   #if INTENSIVE_DEBUG
  1564. X   sprintf( bwb_ebuf, "in bwb_lerror(): error number is <%d> ", n );
  1565. X   bwb_debug( bwb_ebuf );
  1566. X   #endif
  1567. X
  1568. X   /* check the line number value */
  1569. X
  1570. X   if ( ( n < 0 ) || ( n >= N_ERRORS ))
  1571. X      {
  1572. X      sprintf( bwb_ebuf, "Error number %d is out of range", n );
  1573. X      bwb_xerror( bwb_ebuf );
  1574. X      return l;
  1575. X      }
  1576. X
  1577. X   bwb_xerror( err_table[ n ] );
  1578. X
  1579. X   return l;
  1580. X
  1581. X   }
  1582. X
  1583. X/***************************************************************
  1584. X
  1585. X        FUNCTION:       bwb_error()
  1586. X
  1587. X        DESCRIPTION:    This function is called to handle errors
  1588. X                        in Bywater BASIC.  It displays the error
  1589. X                        message, then calls the break_handler()
  1590. X                        routine.
  1591. X
  1592. X***************************************************************/
  1593. X
  1594. Xint
  1595. Xbwb_error( char *message )
  1596. X   {
  1597. X   register int e;
  1598. X   static char tbuf[ MAXSTRINGSIZE + 1 ];    /* must be permanent */
  1599. X
  1600. X   /* try to find the error message to identify the error number */
  1601. X
  1602. X   err_line = bwb_number;        /* set error line number */
  1603. X   for ( e = 0; e < N_ERRORS; ++e )
  1604. X      {
  1605. X      if ( message == err_table[ e ] )    /* set error number */
  1606. X         {
  1607. X         err_number = e;
  1608. X         e = N_ERRORS;            /* break out of loop quickly */
  1609. X         }
  1610. X      }
  1611. X
  1612. X   /* if err_gosubn is not set, then use xerror routine */
  1613. X
  1614. X   if ( err_gosubn == 0 )
  1615. X      {
  1616. X      return bwb_xerror( message );
  1617. X      }
  1618. X
  1619. X   /* err_gosubn is not set; call user-defined error subroutine */
  1620. X
  1621. X   sprintf( tbuf, "GOSUB %d", err_gosubn );
  1622. X   cnd_xpline( bwb_l, tbuf );
  1623. X   return TRUE;
  1624. X
  1625. X   }
  1626. X
  1627. X/***************************************************************
  1628. X
  1629. X        FUNCTION:       bwb_xerror()
  1630. X
  1631. X        DESCRIPTION:    This function is called by bwb_error()
  1632. X                        in Bywater BASIC.  It displays the error
  1633. X                        message, then calls the break_handler()
  1634. X                        routine.
  1635. X
  1636. X***************************************************************/
  1637. X
  1638. Xint
  1639. Xbwb_xerror( char *message )
  1640. X   {
  1641. X   static char tbuf[ MAXSTRINGSIZE + 1 ];    /* this memory should be 
  1642. X                           permanent in case of memory
  1643. X                           overrun errors */
  1644. X
  1645. X   fflush( stdout );
  1646. X   fflush( errfdevice );
  1647. X   if ( prn_col != 1 )
  1648. X      {
  1649. X      xprintf( errfdevice, "\n" );
  1650. X      }
  1651. X   sprintf( tbuf, "\n%s %d: %s\n", ERROR_HEADER, bwb_number, message );
  1652. X   xprintf( errfdevice, tbuf );
  1653. X   break_handler();
  1654. X
  1655. X   return FALSE;
  1656. X   }
  1657. X
  1658. X/***************************************************************
  1659. X
  1660. X        FUNCTION:       matherr()
  1661. X
  1662. X        DESCRIPTION:    This function is called to handle math
  1663. X                        errors in Bywater BASIC.  It displays
  1664. X                        the error message, then calls the
  1665. X                        break_handler() routine.
  1666. X
  1667. X***************************************************************/
  1668. X
  1669. Xint
  1670. Xmatherr( struct exception *except )
  1671. X   {
  1672. X
  1673. X   perror( MATHERR_HEADER );
  1674. X   break_handler();
  1675. X
  1676. X   return FALSE;
  1677. X   }
  1678. X
  1679. Xstatic struct bwb_variable * 
  1680. Xbwb_esetovar( struct exp_ese *e )
  1681. X   {
  1682. X   static struct bwb_variable b;
  1683. X   static init = FALSE;
  1684. X
  1685. X   var_make( &b, e->type );
  1686. X
  1687. X   switch( e->type )
  1688. X      {
  1689. X      case STRING:
  1690. X         str_btob( var_findsval( &b, b.array_pos ), exp_getsval( e ) );
  1691. X         break;
  1692. X      case DOUBLE:
  1693. X         * var_finddval( &b, b.array_pos ) = e->dval;
  1694. X         break;
  1695. X      case INTEGER:
  1696. X         * var_findival( &b, b.array_pos ) = e->ival;
  1697. X         break;
  1698. X      default:
  1699. X         * var_findfval( &b, b.array_pos ) = e->fval;
  1700. X         break;
  1701. X      }
  1702. X
  1703. X   return &b;
  1704. X
  1705. X   }
  1706. X
  1707. X/***************************************************************
  1708. X
  1709. X        FUNCTION:       bwb_width()
  1710. X
  1711. X        DESCRIPTION:
  1712. X
  1713. X***************************************************************/
  1714. X
  1715. Xstruct bwb_line *
  1716. Xbwb_width( struct bwb_line *l )
  1717. X   {
  1718. X   int req_devnumber;
  1719. X   int req_width;
  1720. X   struct exp_ese *e;
  1721. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  1722. X   int pos;
  1723. X
  1724. X   /* detect device number if present */
  1725. X
  1726. X   req_devnumber = -1;
  1727. X   adv_ws( l->buffer, &( l->position ) );
  1728. X   
  1729. X   if ( l->buffer[ l->position ] == '#' )
  1730. X      {
  1731. X      ++( l->position );
  1732. X      adv_element( l->buffer, &( l->position ), tbuf );
  1733. X      pos = 0;
  1734. X      e = bwb_exp( tbuf, FALSE, &pos );
  1735. X      adv_ws( l->buffer, &( l->position ) );
  1736. X      if ( l->buffer[ l->position ] == ',' )
  1737. X         {
  1738. X         ++( l->position );
  1739. X         }
  1740. X      else
  1741. X         {
  1742. X     #if PROG_ERRORS
  1743. X         bwb_error( "in bwb_width(): no comma after #n" );
  1744. X         #else
  1745. X         bwb_error( err_syntax );
  1746. X         #endif
  1747. X         l->next->position = 0;
  1748. X         return l->next;
  1749. X         }
  1750. X
  1751. X      req_devnumber = exp_getival( e );
  1752. X
  1753. X      /* check the requested device number */
  1754. X      
  1755. X      if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  1756. X         {
  1757. X         #if PROG_ERRORS
  1758. X         bwb_error( "in bwb_width(): Requested device number is out of range." );
  1759. X         #else
  1760. X         bwb_error( err_devnum );
  1761. X         #endif
  1762. X         l->next->position = 0;
  1763. X         return l->next;
  1764. X         }
  1765. X
  1766. X      #if INTENSIVE_DEBUG
  1767. X      sprintf( bwb_ebuf, "in bwb_width(): device number is <%d>",
  1768. X         req_devnumber );
  1769. X      bwb_debug( bwb_ebuf );
  1770. X      #endif
  1771. X
  1772. X      }
  1773. X
  1774. X   /* read the width requested */
  1775. X
  1776. X   e = bwb_exp( l->buffer, FALSE, &( l->position ));
  1777. X   req_width = exp_getival( e );
  1778. X
  1779. X   /* check the width */
  1780. X
  1781. X   if ( ( req_width < 1 ) || ( req_width > 255 ))
  1782. X      {
  1783. X      #if PROG_ERRORS
  1784. X      bwb_error( "in bwb_width(): Requested width is out of range (1-255)" );
  1785. X      #else
  1786. X      bwb_error( err_valoorange );
  1787. X      #endif
  1788. X      }
  1789. X
  1790. X   /* assign the width */
  1791. X
  1792. X   if ( req_devnumber == -1 )
  1793. X      {
  1794. X      prn_width = req_width;
  1795. X      }
  1796. X   else
  1797. X      {
  1798. X      dev_table[ req_devnumber ].width = req_width;
  1799. X      }
  1800. X
  1801. X   /* return */
  1802. X
  1803. X   return l->next;
  1804. X   }
  1805. X
  1806. X/***************************************************************
  1807. X
  1808. X        FUNCTION:       bwb_write()
  1809. X
  1810. X        DESCRIPTION:
  1811. X
  1812. X***************************************************************/
  1813. X
  1814. Xstruct bwb_line *
  1815. Xbwb_write( struct bwb_line *l )
  1816. X   {
  1817. X   struct exp_ese *e;
  1818. X   int req_devnumber;
  1819. X   int pos;
  1820. X   FILE *fp;
  1821. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  1822. X   int loop;
  1823. X   static struct bwb_variable nvar;
  1824. X   static int init = FALSE;
  1825. X
  1826. X   /* initialize variable if necessary */
  1827. X
  1828. X   if ( init == FALSE )
  1829. X      {
  1830. X      init = TRUE;
  1831. X      var_make( &nvar, SINGLE );
  1832. X      }
  1833. X
  1834. X   /* detect device number if present */
  1835. X
  1836. X   adv_ws( l->buffer, &( l->position ) );
  1837. X   
  1838. X   if ( l->buffer[ l->position ] == '#' )
  1839. X      {
  1840. X      ++( l->position );
  1841. X      adv_element( l->buffer, &( l->position ), tbuf );
  1842. X      pos = 0;
  1843. X      e = bwb_exp( tbuf, FALSE, &pos );
  1844. X      adv_ws( l->buffer, &( l->position ) );
  1845. X      if ( l->buffer[ l->position ] == ',' )
  1846. X         {
  1847. X         ++( l->position );
  1848. X         }
  1849. X      else
  1850. X         {
  1851. X     #if PROG_ERRORS
  1852. X         bwb_error( "in bwb_write(): no comma after #n" );
  1853. X         #else
  1854. X         bwb_error( err_syntax );
  1855. X         #endif
  1856. X         l->next->position = 0;
  1857. X         return l->next;
  1858. X         }
  1859. X
  1860. X      req_devnumber = exp_getival( e );
  1861. X
  1862. X      /* check the requested device number */
  1863. X      
  1864. X      if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  1865. X         {
  1866. X         #if PROG_ERRORS
  1867. X         bwb_error( "in bwb_write(): Requested device number is out of range." );
  1868. X         #else
  1869. X         bwb_error( err_devnum );
  1870. X         #endif
  1871. X         l->next->position = 0;
  1872. X         return l->next;
  1873. X         }
  1874. X
  1875. X      if (( dev_table[ req_devnumber ].mode == DEVMODE_CLOSED ) ||
  1876. X         ( dev_table[ req_devnumber ].mode == DEVMODE_AVAILABLE ))
  1877. X         {
  1878. X         #if PROG_ERRORS
  1879. X         bwb_error( "in bwb_write(): Requested device number is not open." );
  1880. X         #else
  1881. X         bwb_error( err_devnum );
  1882. X         #endif
  1883. X
  1884. X         l->next->position = 0;
  1885. X         return l->next;
  1886. X         }
  1887. X
  1888. X      if ( dev_table[ req_devnumber ].mode != DEVMODE_OUTPUT )
  1889. X         {
  1890. X         #if PROG_ERRORS
  1891. X         bwb_error( "in bwb_write(): Requested device is not open for OUTPUT." );
  1892. X         #else
  1893. X         bwb_error( err_devnum );
  1894. X         #endif
  1895. X
  1896. X         l->next->position = 0;
  1897. X         return l->next;
  1898. X         }
  1899. X
  1900. X      #if INTENSIVE_DEBUG
  1901. X      sprintf( bwb_ebuf, "in bwb_write(): device number is <%d>",
  1902. X         req_devnumber );
  1903. X      bwb_debug( bwb_ebuf );
  1904. X      #endif
  1905. X
  1906. X      /* look up the requested device in the device table */
  1907. X
  1908. X      fp = dev_table[ req_devnumber ].cfp;
  1909. X
  1910. X      }
  1911. X
  1912. X   else
  1913. X      {
  1914. X      fp = stdout;
  1915. X      }
  1916. X
  1917. X   /* be sure there is an element to print */ 
  1918. X
  1919. X   adv_ws( l->buffer, &( l->position ) );
  1920. X   loop = TRUE;
  1921. X   switch( l->buffer[ l->position ] )
  1922. X      {
  1923. X      case '\n':
  1924. X      case '\r':
  1925. X      case '\0':
  1926. X      case ':':
  1927. X         loop = FALSE;
  1928. X         break;
  1929. X      }
  1930. X
  1931. X   /* loop through elements */
  1932. X
  1933. X   while ( loop == TRUE )
  1934. X      {
  1935. X
  1936. X      /* get the next element */
  1937. X
  1938. X      e = bwb_exp( l->buffer, FALSE, &( l->position ));
  1939. X
  1940. X      /* perform type-specific output */
  1941. X
  1942. X      switch( e->type )
  1943. X         {
  1944. X         case STRING:
  1945. X            xputc( fp, '\"' );
  1946. X            str_btoc( tbuf, exp_getsval( e ) );
  1947. X            xprintf( fp, tbuf );
  1948. X            xputc( fp, '\"' );
  1949. X            #if INTENSIVE_DEBUG
  1950. X            sprintf( bwb_ebuf, "in bwb_write(): output string element <\"%s\">",
  1951. X               tbuf );
  1952. X            bwb_debug( bwb_ebuf );
  1953. X            #endif
  1954. X            break;
  1955. X         default:
  1956. X            * var_findfval( &nvar, nvar.array_pos ) =
  1957. X               exp_getfval( e );
  1958. X            sprintf( tbuf, " %.*f", prn_precision( &nvar ), 
  1959. X               var_getfval( &nvar ) );
  1960. X            xprintf( fp, tbuf );
  1961. X            #if INTENSIVE_DEBUG
  1962. X            sprintf( bwb_ebuf, "in bwb_write(): output numerical element <%s>",
  1963. X               tbuf );
  1964. X            bwb_debug( bwb_ebuf );
  1965. X            #endif
  1966. X            break;
  1967. X         }                /* end of case for type-specific output */
  1968. X
  1969. X      /* seek a comma at end of element */
  1970. X
  1971. X      adv_ws( l->buffer, &( l->position ) );
  1972. X      if ( l->buffer[ l->position ] == ',' )
  1973. X         {
  1974. X         xputc( fp, ',' );
  1975. X         ++( l->position );
  1976. X         }
  1977. X
  1978. X      /* no comma: end the loop */
  1979. X
  1980. X      else
  1981. X         {
  1982. X         loop = FALSE;
  1983. X         }
  1984. X
  1985. X      }                    /* end of loop through elements */
  1986. X
  1987. X   /* print LF */
  1988. X
  1989. X   xputc( fp, '\n' );
  1990. X
  1991. X   /* return */
  1992. X
  1993. X   l->next->position = 0;
  1994. X   return l->next;
  1995. X   }
  1996. X
  1997. END_OF_FILE
  1998.   if test 41227 -ne `wc -c <'bwb_prn.c'`; then
  1999.     echo shar: \"'bwb_prn.c'\" unpacked with wrong size!
  2000.   fi
  2001.   # end of 'bwb_prn.c'
  2002. fi
  2003. echo shar: End of archive 5 \(of 11\).
  2004. cp /dev/null ark5isdone
  2005. MISSING=""
  2006. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  2007.     if test ! -f ark${I}isdone ; then
  2008.     MISSING="${MISSING} ${I}"
  2009.     fi
  2010. done
  2011. if test "${MISSING}" = "" ; then
  2012.     echo You have unpacked all 11 archives.
  2013.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2014. else
  2015.     echo You still must unpack the following archives:
  2016.     echo "        " ${MISSING}
  2017. fi
  2018. exit 0
  2019. exit 0 # Just in case...
  2020.