ChipMaster's bwBASIC This also includes history going back to v2.10. *WARN* some binary files might have been corrupted by CRLF.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1807 lines
40 KiB

  1. /***************************************************************
  2. bwb_dio.c Device Input/Output Routines
  3. for Bywater BASIC Interpreter
  4. Copyright (c) 1993, Ted A. Campbell
  5. Bywater Software
  6. email: tcamp@delphi.com
  7. Copyright and Permissions Information:
  8. All U.S. and international rights are claimed by the author,
  9. Ted A. Campbell.
  10. This software is released under the terms of the GNU General
  11. Public License (GPL), which is distributed with this software
  12. in the file "COPYING". The GPL specifies the terms under
  13. which users may copy and use the software in this distribution.
  14. A separate license is available for commercial distribution,
  15. for information on which you should contact the author.
  16. ***************************************************************/
  17. #include <stdio.h>
  18. #include "bwbasic.h"
  19. #include "bwb_mes.h"
  20. #if HAVE_SYSSTAT
  21. #include <sys/stat.h>
  22. #endif
  23. #ifndef SEEK_SET
  24. #define SEEK_SET 0
  25. #endif
  26. #if INTENSIVE_DEBUG
  27. #define RANDOM_FILLCHAR 'X'
  28. #else
  29. #define RANDOM_FILLCHAR ' '
  30. #endif
  31. #if COMMON_CMDS
  32. struct dev_element *dev_table; /* table of devices */
  33. #endif
  34. static struct bwb_variable *v;
  35. static int pos;
  36. static int req_devnumber;
  37. static int rlen;
  38. static int mode;
  39. #if ANSI_C
  40. static struct bwb_line *dio_lrset( struct bwb_line *l, int rset );
  41. static int dio_flush( int dev_number );
  42. #else
  43. static struct bwb_line *dio_lrset();
  44. static int dio_flush();
  45. #endif
  46. #if COMMON_CMDS
  47. /***************************************************************
  48. FUNCTION: bwb_open()
  49. DESCRIPTION: This function implements the BASIC OPEN
  50. command to open a stream for device input/output.
  51. SYNTAX: 1. OPEN "I"|"O"|"R", [#]n, filename [,rlen]
  52. 2. OPEN filename [FOR INPUT|OUTPUT|APPEND|] AS [#]n [LEN=n]
  53. ***************************************************************/
  54. #if ANSI_C
  55. struct bwb_line *
  56. bwb_open( struct bwb_line *l )
  57. #else
  58. struct bwb_line *
  59. bwb_open( l )
  60. struct bwb_line *l;
  61. #endif
  62. {
  63. FILE *fp;
  64. struct exp_ese *e;
  65. int previous_buffer;
  66. char atbuf[ MAXSTRINGSIZE + 1 ];
  67. char first[ MAXSTRINGSIZE + 1 ];
  68. char devname[ MAXSTRINGSIZE + 1 ];
  69. /* initialize */
  70. mode = req_devnumber = rlen = -1;
  71. previous_buffer = FALSE;
  72. /* get the first expression element up to comma or whitespace */
  73. adv_element( l->buffer, &( l->position ), atbuf );
  74. /* parse the first expression element */
  75. pos = 0;
  76. e = bwb_exp( atbuf, FALSE, &pos );
  77. str_btoc( first, exp_getsval( e ) );
  78. #if INTENSIVE_DEBUG
  79. sprintf( bwb_ebuf, "in bwb_open(): first element is <%s>",
  80. first );
  81. bwb_debug( bwb_ebuf );
  82. #endif
  83. /* test for syntactical form: if a comma follows the first element,
  84. then the syntax is form 1 (the old CP/M BASIC format); otherwise we
  85. presume form 2 */
  86. adv_ws( l->buffer, &( l->position ) );
  87. /* Parse syntax Form 1 (OPEN "x",#n, devname...) */
  88. if ( l->buffer[ l->position ] == ',' )
  89. {
  90. /* parse the next element to get the device number */
  91. ++( l->position ); /* advance beyond comma */
  92. adv_ws( l->buffer, &( l->position ) );
  93. if ( l->buffer[ l->position ] == '#' )
  94. {
  95. ++( l->position );
  96. adv_ws( l->buffer, &( l->position ) );
  97. }
  98. adv_element( l->buffer, &( l->position ), atbuf );
  99. pos = 0;
  100. e = bwb_exp( atbuf, FALSE, &pos );
  101. if ( e->type == STRING )
  102. {
  103. #if PROG_ERRORS
  104. bwb_error( "String where number was expected for device number" );
  105. #else
  106. bwb_error( err_syntax );
  107. #endif
  108. return bwb_zline( l );
  109. }
  110. req_devnumber = (int) exp_getnval( e );
  111. #if INTENSIVE_DEBUG
  112. sprintf( bwb_ebuf, "in bwb_open(): syntax 1, req dev number is %d",
  113. req_devnumber );
  114. bwb_debug( bwb_ebuf );
  115. #endif
  116. /* parse the next element to get the devname */
  117. adv_ws( l->buffer, &( l->position ) ); /* advance past whitespace */
  118. ++( l->position ); /* advance past comma */
  119. adv_element( l->buffer, &( l->position ), atbuf );
  120. pos = 0;
  121. e = bwb_exp( atbuf, FALSE, &pos );
  122. if ( e->type != STRING )
  123. {
  124. #if PROG_ERRORS
  125. bwb_error( "in bwb_open(): number where string was expected for devname" );
  126. #else
  127. bwb_error( err_syntax );
  128. #endif
  129. return bwb_zline( l );
  130. }
  131. str_btoc( devname, exp_getsval( e ) );
  132. #if INTENSIVE_DEBUG
  133. sprintf( bwb_ebuf, "in bwb_open(): syntax 1, devname <%s>",
  134. devname );
  135. bwb_debug( bwb_ebuf );
  136. #endif
  137. /* see if there is another element; if so, parse it to get the
  138. record length */
  139. adv_ws( l->buffer, &( l->position ) );
  140. if ( l->buffer[ l->position ] == ',' )
  141. {
  142. ++( l->position ); /* advance beyond comma */
  143. adv_element( l->buffer, &( l->position ), atbuf );
  144. pos = 0;
  145. e = bwb_exp( atbuf, FALSE, &pos );
  146. if ( e->type == STRING )
  147. {
  148. #if PROG_ERRORS
  149. bwb_error( "String where number was expected for record length" );
  150. #else
  151. bwb_error( err_syntax );
  152. #endif
  153. return bwb_zline( l );
  154. }
  155. rlen = (int) exp_getnval( e );
  156. #if INTENSIVE_DEBUG
  157. sprintf( bwb_ebuf, "in bwb_open(): syntax 1, record length is %d",
  158. rlen );
  159. bwb_debug( bwb_ebuf );
  160. #endif
  161. }
  162. /* the first letter of the first should indicate the
  163. type of file opening requested: test this letter,
  164. then parse accordingly */
  165. /* open file for sequential INPUT */
  166. if ( ( first[ 0 ] == 'i' ) || ( first[ 0 ] == 'I' ))
  167. {
  168. mode = DEVMODE_INPUT;
  169. }
  170. /* open file for sequential OUTPUT */
  171. else if ( ( first[ 0 ] == 'o' ) || ( first[ 0 ] == 'O' ))
  172. {
  173. mode = DEVMODE_OUTPUT;
  174. }
  175. /* open file for RANDOM access input and output */
  176. else if ( ( first[ 0 ] == 'r' ) || ( first[ 0 ] == 'R' ))
  177. {
  178. mode = DEVMODE_RANDOM;
  179. }
  180. /* error: none of the appropriate modes found */
  181. else
  182. {
  183. #if PROG_ERRORS
  184. sprintf( bwb_ebuf, "in bwb_open(): invalid mode" );
  185. bwb_error( bwb_ebuf );
  186. #else
  187. bwb_error( err_syntax );
  188. #endif
  189. }
  190. #if INTENSIVE_DEBUG
  191. sprintf( bwb_ebuf, "in bwb_open(): syntax 1, mode is %d", mode );
  192. bwb_debug( bwb_ebuf );
  193. #endif
  194. }
  195. /* Parse syntax Form 2 (OPEN devname FOR mode AS#n ... ) */
  196. else
  197. {
  198. /* save the devname from first */
  199. strcpy( devname, first );
  200. #if INTENSIVE_DEBUG
  201. sprintf( bwb_ebuf, "in bwb_open(): syntax 2, devname <%s>",
  202. devname );
  203. bwb_debug( bwb_ebuf );
  204. #endif
  205. /* get the next element */
  206. adv_element( l->buffer, &( l->position ), atbuf );
  207. /* check for "FOR mode" statement */
  208. bwb_strtoupper( atbuf );
  209. if ( strcmp( atbuf, "FOR" ) == 0 )
  210. {
  211. adv_element( l->buffer, &( l->position ), atbuf );
  212. bwb_strtoupper( atbuf );
  213. if ( strcmp( atbuf, "INPUT" ) == 0 )
  214. {
  215. mode = DEVMODE_INPUT;
  216. }
  217. else if ( strcmp( atbuf, "OUTPUT" ) == 0 )
  218. {
  219. mode = DEVMODE_OUTPUT;
  220. }
  221. else if ( strcmp( atbuf, "APPEND" ) == 0 )
  222. {
  223. mode = DEVMODE_RANDOM;
  224. }
  225. else
  226. {
  227. #if PROG_ERRORS
  228. bwb_error( "in bwb_open(): Invalid device i/o mode specified" );
  229. #else
  230. bwb_error( err_syntax );
  231. #endif
  232. return bwb_zline( l );
  233. }
  234. /* get the next element */
  235. adv_element( l->buffer, &( l->position ), atbuf );
  236. }
  237. else
  238. {
  239. mode = DEVMODE_RANDOM;
  240. }
  241. #if INTENSIVE_DEBUG
  242. sprintf( bwb_ebuf, "in bwb_open(): syntax 2, mode is %d", mode );
  243. bwb_debug( bwb_ebuf );
  244. #endif
  245. /* This leaves us with the next element in the atbuf: it
  246. should read "AS" */
  247. bwb_strtoupper( atbuf );
  248. if ( strcmp( atbuf, "AS" ) != 0 )
  249. {
  250. #if PROG_ERRORS
  251. bwb_error( "in bwb_open(): expected AS statement" );
  252. #else
  253. bwb_error( err_syntax );
  254. #endif
  255. return bwb_zline( l );
  256. }
  257. /* get the next element */
  258. adv_ws( l->buffer, &( l->position ) );
  259. if ( l->buffer[ l->position ] == '#' )
  260. {
  261. ++( l->position );
  262. }
  263. adv_element( l->buffer, &( l->position ), atbuf );
  264. #if INTENSIVE_DEBUG
  265. sprintf( bwb_ebuf, "in bwb_open(): string to parse for req dev number <%s>",
  266. atbuf );
  267. bwb_debug( bwb_ebuf );
  268. #endif
  269. pos = 0;
  270. e = bwb_exp( atbuf, FALSE, &pos );
  271. if ( e->type == STRING )
  272. {
  273. #if PROG_ERRORS
  274. bwb_error( "String where number was expected for record length" );
  275. #else
  276. bwb_error( err_syntax );
  277. #endif
  278. return bwb_zline( l );
  279. }
  280. req_devnumber = (int) exp_getnval( e );
  281. #if INTENSIVE_DEBUG
  282. sprintf( bwb_ebuf, "in bwb_open(): syntax 2, req dev number is %d",
  283. req_devnumber );
  284. bwb_debug( bwb_ebuf );
  285. #endif
  286. /* Check for LEN = n statement */
  287. adv_element( l->buffer, &( l->position ), atbuf );
  288. bwb_strtoupper( atbuf );
  289. if ( strncmp( atbuf, "LEN", (size_t) 3 ) == 0 )
  290. {
  291. pos = l->position - strlen( atbuf );
  292. while( ( l->buffer[ pos ] != '=' ) && ( l->buffer[ pos ] != '\0' ))
  293. {
  294. ++pos;
  295. }
  296. if ( l->buffer[ pos ] == '\0' )
  297. {
  298. #if PROG_ERRORS
  299. bwb_error( "Failed to find equals sign after LEN element" );
  300. #else
  301. bwb_error( err_syntax );
  302. #endif
  303. return bwb_zline( l );
  304. }
  305. ++pos; /* advance past equal sign */
  306. e = bwb_exp( l->buffer, FALSE, &pos );
  307. if ( e->type == STRING )
  308. {
  309. #if PROG_ERRORS
  310. bwb_error( "String where number was expected for record length" );
  311. #else
  312. bwb_error( err_syntax );
  313. #endif
  314. return bwb_zline( l );
  315. }
  316. rlen = (int) exp_getnval( e );
  317. #if INTENSIVE_DEBUG
  318. sprintf( bwb_ebuf, "in bwb_open(): syntax 2, record length is %d",
  319. rlen );
  320. bwb_debug( bwb_ebuf );
  321. #endif
  322. }
  323. } /* end of syntax 2 */
  324. /* check for valid requested device number */
  325. if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  326. {
  327. #if PROG_ERRORS
  328. bwb_error( "in bwb_open(): Requested device number is out of range." );
  329. #else
  330. bwb_error( err_devnum );
  331. #endif
  332. return bwb_zline( l );
  333. }
  334. if ( dev_table[ req_devnumber ].mode == DEVMODE_CLOSED )
  335. {
  336. #if INTENSIVE_DEBUG
  337. sprintf( bwb_ebuf, "in bwb_open(): using previously closed file (and buffer)" );
  338. bwb_debug( bwb_ebuf );
  339. #endif
  340. previous_buffer = TRUE;
  341. }
  342. if ( ( dev_table[ req_devnumber ].mode != DEVMODE_CLOSED ) &&
  343. ( dev_table[ req_devnumber ].mode != DEVMODE_AVAILABLE ) )
  344. {
  345. #if PROG_ERRORS
  346. bwb_error( "in bwb_open(): Requested device number is already in use." );
  347. #else
  348. bwb_error( err_devnum );
  349. #endif
  350. return bwb_zline( l );
  351. }
  352. #if INTENSIVE_DEBUG
  353. sprintf( bwb_ebuf, "in bwb_open(): ready to open device <%s> mode <%d>",
  354. devname, mode );
  355. bwb_debug( bwb_ebuf );
  356. #endif
  357. /* attempt to open the file */
  358. switch( mode )
  359. {
  360. case DEVMODE_OUTPUT:
  361. fp = fopen( devname, "w" );
  362. break;
  363. case DEVMODE_INPUT:
  364. fp = fopen( devname, "r" );
  365. break;
  366. case DEVMODE_APPEND:
  367. fp = fopen( devname, "a" );
  368. break;
  369. case DEVMODE_RANDOM:
  370. fp = fopen( devname, "r+" );
  371. if ( fp == NULL )
  372. {
  373. fp = fopen( devname, "w" );
  374. fclose( fp );
  375. fp = fopen( devname, "r+" );
  376. }
  377. break;
  378. }
  379. /* check for valid file opening */
  380. if ( fp == NULL )
  381. {
  382. #if PROG_ERRORS
  383. sprintf( bwb_ebuf, "Failed to open device <%s>", devname );
  384. bwb_error( bwb_ebuf );
  385. #else
  386. bwb_error( err_dev );
  387. #endif
  388. return bwb_zline( l );
  389. }
  390. /* assign values to device table */
  391. dev_table[ req_devnumber ].mode = mode;
  392. dev_table[ req_devnumber ].cfp = fp;
  393. dev_table[ req_devnumber ].reclen = rlen;
  394. dev_table[ req_devnumber ].next_record = 1;
  395. dev_table[ req_devnumber ].loc = 0;
  396. strcpy( dev_table[ req_devnumber ].filename, devname );
  397. /* allocate a character buffer for random access */
  398. if (( mode == DEVMODE_RANDOM ) && ( previous_buffer != TRUE ))
  399. {
  400. if ( ( dev_table[ req_devnumber ].buffer = calloc( rlen + 1, 1 )) == NULL )
  401. {
  402. #if PROG_ERRORS
  403. bwb_error( "in bwb_open(): failed to find memory for device buffer" );
  404. #else
  405. bwb_error( err_getmem );
  406. #endif
  407. return bwb_zline( l );
  408. }
  409. dio_flush( req_devnumber );
  410. #if INTENSIVE_DEBUG
  411. sprintf( bwb_ebuf, "in bwb_open(): allocated new random-access buffer" );
  412. bwb_debug( bwb_ebuf );
  413. #endif
  414. }
  415. #if INTENSIVE_DEBUG
  416. sprintf( bwb_ebuf, "in bwb_open(): file is open now; end of function" );
  417. bwb_debug( bwb_ebuf );
  418. #endif
  419. /* return next line number in sequence */
  420. return bwb_zline( l );
  421. }
  422. /***************************************************************
  423. FUNCTION: bwb_close()
  424. DESCRIPTION: This function implements the BASIC CLOSE
  425. command to close a stream for device input/output.
  426. SYNTAX: CLOSE [#]n [,[#]n...]
  427. ***************************************************************/
  428. #if ANSI_C
  429. struct bwb_line *
  430. bwb_close( struct bwb_line *l )
  431. #else
  432. struct bwb_line *
  433. bwb_close( l )
  434. struct bwb_line *l;
  435. #endif
  436. {
  437. struct exp_ese *e;
  438. char atbuf[ MAXSTRINGSIZE + 1 ];
  439. /* loop to get device numbers to close */
  440. do
  441. {
  442. adv_ws( l->buffer, &( l->position ) );
  443. if ( l->buffer[ l->position ] =='#' )
  444. {
  445. ++( l->position );
  446. }
  447. adv_element( l->buffer, &( l->position ), atbuf );
  448. pos = 0;
  449. e = bwb_exp( atbuf, FALSE, &pos );
  450. if ( e->type == STRING )
  451. {
  452. #if PROG_ERRORS
  453. bwb_error( "String where number was expected for device number" );
  454. #else
  455. bwb_error( err_syntax );
  456. #endif
  457. return bwb_zline( l );
  458. }
  459. req_devnumber = (int) exp_getnval( e );
  460. #if INTENSIVE_DEBUG
  461. sprintf( bwb_ebuf, "in bwb_close(): requested device number <%d>",
  462. req_devnumber );
  463. bwb_debug( bwb_ebuf );
  464. #endif
  465. /* check for valid requested device number */
  466. if ( ( req_devnumber < 0 ) || ( req_devnumber >= DEF_DEVICES ))
  467. {
  468. #if PROG_ERRORS
  469. bwb_error( "in bwb_close(): Requested device number is out if range." );
  470. #else
  471. bwb_error( err_devnum );
  472. #endif
  473. return bwb_zline( l );
  474. }
  475. if (( dev_table[ req_devnumber ].mode == DEVMODE_CLOSED ) ||
  476. ( dev_table[ req_devnumber ].mode == DEVMODE_AVAILABLE ) )
  477. {
  478. #if PROG_ERRORS
  479. bwb_error( "in bwb_close(): Requested device number is not in use." );
  480. #else
  481. bwb_error( err_devnum );
  482. #endif
  483. return bwb_zline( l );
  484. }
  485. #if INTENSIVE_DEBUG
  486. sprintf( bwb_ebuf, "in bwb_close(): closing device# <%d>",
  487. req_devnumber );
  488. bwb_debug( bwb_ebuf );
  489. #endif
  490. /* attempt to close the file */
  491. if ( fclose( dev_table[ req_devnumber ].cfp ) != 0 )
  492. {
  493. #if PROG_ERRORS
  494. bwb_error( "in bwb_close(): Failed to close the device" );
  495. #else
  496. bwb_error( err_dev );
  497. #endif
  498. return bwb_zline( l );
  499. }
  500. /* mark the device in the table as unavailable */
  501. dev_table[ req_devnumber ].mode = DEVMODE_CLOSED;
  502. /* eat up any remaining whitespace */
  503. adv_ws( l->buffer, &( l->position ) );
  504. }
  505. while ( l->buffer[ l->position ] == ',' );
  506. /* return next line number in sequence */
  507. return bwb_zline( l );
  508. }
  509. #endif /* COMMON_CMDS */
  510. /***************************************************************
  511. FUNCTION: bwb_chdir()
  512. DESCRIPTION: This function implements the BASIC CHDIR
  513. command to switch logged directories.
  514. SYNTAX: CHDIR pathname$
  515. ***************************************************************/
  516. #if UNIX_CMDS
  517. #if ANSI_C
  518. struct bwb_line *
  519. bwb_chdir( struct bwb_line *l )
  520. #else
  521. struct bwb_line *
  522. bwb_chdir( l )
  523. struct bwb_line *l;
  524. #endif
  525. {
  526. int r;
  527. static int position;
  528. struct exp_ese *e;
  529. static char *atbuf;
  530. static int init = FALSE;
  531. /* get memory for temporary buffers if necessary */
  532. if ( init == FALSE )
  533. {
  534. init = TRUE;
  535. if ( ( atbuf = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  536. {
  537. #if PROG_ERRORS
  538. bwb_error( "in bwb_chdir(): failed to find memory for atbuf" );
  539. #else
  540. bwb_error( err_getmem );
  541. #endif
  542. }
  543. }
  544. /* get the next element in atbuf */
  545. adv_element( l->buffer, &( l->position ), atbuf );
  546. #if INTENSIVE_DEBUG
  547. sprintf( bwb_ebuf, "in bwb_chdir(): argument is <%s>", atbuf );
  548. bwb_debug( bwb_ebuf );
  549. #endif
  550. /* interpret the argument */
  551. position = 0;
  552. e = bwb_exp( atbuf, FALSE, &position );
  553. if ( e->type != STRING )
  554. {
  555. bwb_error( err_argstr );
  556. return bwb_zline( l );
  557. }
  558. /* try to chdir to the requested directory */
  559. str_btoc( atbuf, &( e->sval ) );
  560. r = chdir( atbuf );
  561. /* detect error */
  562. if ( r == -1 )
  563. {
  564. bwb_error( err_opsys );
  565. return bwb_zline( l );
  566. }
  567. return bwb_zline( l );
  568. }
  569. /***************************************************************
  570. FUNCTION: bwb_rmdir()
  571. DESCRIPTION: This function implements the BASIC CHDIR
  572. command to remove a subdirectory.
  573. SYNTAX: RMDIR pathname$
  574. ***************************************************************/
  575. #if ANSI_C
  576. struct bwb_line *
  577. bwb_rmdir( struct bwb_line *l )
  578. #else
  579. struct bwb_line *
  580. bwb_rmdir( l )
  581. struct bwb_line *l;
  582. #endif
  583. {
  584. int r;
  585. static int position;
  586. struct exp_ese *e;
  587. static char *atbuf;
  588. static int init = FALSE;
  589. /* get memory for temporary buffers if necessary */
  590. if ( init == FALSE )
  591. {
  592. init = TRUE;
  593. if ( ( atbuf = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  594. {
  595. #if PROG_ERRORS
  596. bwb_error( "in rmdir(): failed to find memory for atbuf" );
  597. #else
  598. bwb_error( err_getmem );
  599. #endif
  600. }
  601. }
  602. /* get the next element in atbuf */
  603. adv_element( l->buffer, &( l->position ), atbuf );
  604. #if INTENSIVE_DEBUG
  605. sprintf( bwb_ebuf, "in bwb_rmdir(): argument is <%s>", atbuf );
  606. bwb_debug( bwb_ebuf );
  607. #endif
  608. /* interpret the argument */
  609. position = 0;
  610. e = bwb_exp( atbuf, FALSE, &position );
  611. if ( e->type != STRING )
  612. {
  613. bwb_error( err_argstr );
  614. return bwb_zline( l );
  615. }
  616. /* try to remove the requested directory */
  617. str_btoc( atbuf, &( e->sval ) );
  618. r = rmdir( atbuf );
  619. /* detect error */
  620. if ( r == -1 )
  621. {
  622. bwb_error( err_opsys );
  623. }
  624. return bwb_zline( l );
  625. }
  626. /***************************************************************
  627. FUNCTION: bwb_mkdir()
  628. DESCRIPTION: This function implements the BASIC MKDIR
  629. command to create a new subdirectory.
  630. SYNTAX: MKDIR pathname$
  631. ***************************************************************/
  632. #if ANSI_C
  633. struct bwb_line *
  634. bwb_mkdir( struct bwb_line *l )
  635. #else
  636. struct bwb_line *
  637. bwb_mkdir( l )
  638. struct bwb_line *l;
  639. #endif
  640. {
  641. int r;
  642. static int position;
  643. struct exp_ese *e;
  644. static char *atbuf;
  645. static int init = FALSE;
  646. /* get memory for temporary buffers if necessary */
  647. if ( init == FALSE )
  648. {
  649. init = TRUE;
  650. if ( ( atbuf = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  651. {
  652. #if PROG_ERRORS
  653. bwb_error( "in bwb_mkdir(): failed to find memory for atbuf" );
  654. #else
  655. bwb_error( err_getmem );
  656. #endif
  657. }
  658. }
  659. /* get the next element in atbuf */
  660. adv_element( l->buffer, &( l->position ), atbuf );
  661. #if INTENSIVE_DEBUG
  662. sprintf( bwb_ebuf, "in bwb_mkdir(): argument is <%s>", atbuf );
  663. bwb_debug( bwb_ebuf );
  664. #endif
  665. /* interpret the argument */
  666. position = 0;
  667. e = bwb_exp( atbuf, FALSE, &position );
  668. if ( e->type != STRING )
  669. {
  670. bwb_error( err_argstr );
  671. return bwb_zline( l );
  672. }
  673. /* try to make the requested directory */
  674. str_btoc( atbuf, &( e->sval ) );
  675. #if MKDIR_ONE_ARG
  676. r = mkdir( atbuf );
  677. #else
  678. r = mkdir( atbuf, PERMISSIONS );
  679. #endif
  680. /* detect error */
  681. if ( r == -1 )
  682. {
  683. bwb_error( err_opsys );
  684. }
  685. return bwb_zline( l );
  686. }
  687. /***************************************************************
  688. FUNCTION: bwb_kill()
  689. DESCRIPTION: This function implements the BASIC KILL
  690. command to erase a disk file.
  691. SYNTAX: KILL filename
  692. ***************************************************************/
  693. #if ANSI_C
  694. struct bwb_line *
  695. bwb_kill( struct bwb_line *l )
  696. #else
  697. struct bwb_line *
  698. bwb_kill( l )
  699. struct bwb_line *l;
  700. #endif
  701. {
  702. int r;
  703. static int position;
  704. struct exp_ese *e;
  705. static char *atbuf;
  706. static int init = FALSE;
  707. /* get memory for temporary buffers if necessary */
  708. if ( init == FALSE )
  709. {
  710. init = TRUE;
  711. if ( ( atbuf = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  712. {
  713. #if PROG_ERRORS
  714. bwb_error( "in bwb_kill(): failed to find memory for atbuf" );
  715. #else
  716. bwb_error( err_getmem );
  717. #endif
  718. }
  719. }
  720. /* get the next element in atbuf */
  721. adv_element( l->buffer, &( l->position ), atbuf );
  722. #if INTENSIVE_DEBUG
  723. sprintf( bwb_ebuf, "in bwb_kill(): argument is <%s>", atbuf );
  724. bwb_debug( bwb_ebuf );
  725. #endif
  726. /* interpret the argument */
  727. position = 0;
  728. e = bwb_exp( atbuf, FALSE, &position );
  729. if ( e->type != STRING )
  730. {
  731. bwb_error( err_argstr );
  732. return bwb_zline( l );
  733. }
  734. /* try to delete the specified file */
  735. str_btoc( atbuf, &( e->sval ) );
  736. r = unlink( atbuf );
  737. /* detect error */
  738. if ( r == -1 )
  739. {
  740. bwb_error( err_opsys );
  741. }
  742. return bwb_zline( l );
  743. }
  744. #endif /* UNIX_CMDS */
  745. #if COMMON_CMDS
  746. /***************************************************************
  747. FUNCTION: bwb_name()
  748. DESCRIPTION: This function implements the BASIC NAME
  749. command to rename a disk file.
  750. SYNTAX: NAME old_filename AS new_filename
  751. ***************************************************************/
  752. #if ANSI_C
  753. struct bwb_line *
  754. bwb_name( struct bwb_line *l )
  755. #else
  756. struct bwb_line *
  757. bwb_name( l )
  758. struct bwb_line *l;
  759. #endif
  760. {
  761. int r;
  762. static int position;
  763. struct exp_ese *e;
  764. static char *atbuf;
  765. static char *btbuf;
  766. static int init = FALSE;
  767. /* get memory for temporary buffers if necessary */
  768. if ( init == FALSE )
  769. {
  770. init = TRUE;
  771. if ( ( atbuf = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  772. {
  773. #if PROG_ERRORS
  774. bwb_error( "in bwb_name(): failed to find memory for atbuf" );
  775. #else
  776. bwb_error( err_getmem );
  777. #endif
  778. }
  779. if ( ( btbuf = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  780. {
  781. #if PROG_ERRORS
  782. bwb_error( "in bwb_name(): failed to find memory for btbuf" );
  783. #else
  784. bwb_error( err_getmem );
  785. #endif
  786. }
  787. }
  788. /* get the first argument in atbuf */
  789. adv_element( l->buffer, &( l->position ), atbuf );
  790. /* interpret the first argument */
  791. position = 0;
  792. e = bwb_exp( atbuf, FALSE, &position );
  793. if ( e->type != STRING )
  794. {
  795. bwb_error( err_argstr );
  796. return bwb_zline( l );
  797. }
  798. /* this argument must be copied back to atbuf, else the next
  799. call to bwb_exp() will overwrite the structure to which e
  800. refers */
  801. str_btoc( atbuf, &( e->sval ) );
  802. #if INTENSIVE_DEBUG
  803. sprintf( bwb_ebuf, "in bwb_name(): old name is <%s>", atbuf );
  804. bwb_debug( bwb_ebuf );
  805. #endif
  806. /* get the second argument in btbuf */
  807. adv_element( l->buffer, &( l->position ), btbuf );
  808. bwb_strtoupper( btbuf );
  809. #if INTENSIVE_DEBUG
  810. sprintf( bwb_ebuf, "in bwb_name(): AS string is <%s>", btbuf );
  811. bwb_debug( bwb_ebuf );
  812. #endif
  813. if ( strcmp( btbuf, "AS" ) != 0 )
  814. {
  815. bwb_error( err_syntax );
  816. return bwb_zline( l );
  817. }
  818. /* get the third argument in btbuf */
  819. adv_element( l->buffer, &( l->position ), btbuf );
  820. /* interpret the third argument */
  821. position = 0;
  822. e = bwb_exp( btbuf, FALSE, &position );
  823. if ( e->type != STRING )
  824. {
  825. bwb_error( err_argstr );
  826. return bwb_zline( l );
  827. }
  828. str_btoc( btbuf, &( e->sval ) );
  829. #if INTENSIVE_DEBUG
  830. sprintf( bwb_ebuf, "in bwb_name(): new name is <%s>", btbuf );
  831. bwb_debug( bwb_ebuf );
  832. #endif
  833. /* try to rename the file */
  834. r = rename( atbuf, btbuf );
  835. /* detect error */
  836. if ( r != 0 )
  837. {
  838. bwb_error( err_opsys );
  839. }
  840. return bwb_zline( l );
  841. }
  842. /***************************************************************
  843. FUNCTION: bwb_field()
  844. DESCRIPTION: This C function implements the BASIC
  845. FIELD command.
  846. ***************************************************************/
  847. #if ANSI_C
  848. struct bwb_line *
  849. bwb_field( struct bwb_line *l )
  850. #else
  851. struct bwb_line *
  852. bwb_field( l )
  853. struct bwb_line *l;
  854. #endif
  855. {
  856. int dev_number;
  857. int length;
  858. struct exp_ese *e;
  859. struct bwb_variable *v;
  860. bstring *b;
  861. int current_pos;
  862. char atbuf[ MAXSTRINGSIZE + 1 ];
  863. current_pos = 0;
  864. /* first read device number */
  865. adv_ws( l->buffer, &( l->position ) );
  866. if ( l->buffer[ l->position ] =='#' )
  867. {
  868. ++( l->position );
  869. }
  870. adv_element( l->buffer, &( l->position ), atbuf );
  871. #if INTENSIVE_DEBUG
  872. sprintf( bwb_ebuf, "in bwb_field(): device# buffer <%s>", atbuf );
  873. bwb_debug( bwb_ebuf );
  874. #endif
  875. pos = 0;
  876. e = bwb_exp( atbuf, FALSE, &pos );
  877. if ( e->type != NUMBER )
  878. {
  879. #if PROG_ERRORS
  880. bwb_error( "in bwb_field(): Number was expected for device number" );
  881. #else
  882. bwb_error( err_syntax );
  883. #endif
  884. return bwb_zline( l );
  885. }
  886. dev_number = (int) exp_getnval( e );
  887. #if INTENSIVE_DEBUG
  888. sprintf( bwb_ebuf, "in bwb_field(): device <%d>", dev_number );
  889. bwb_debug( bwb_ebuf );
  890. #endif
  891. /* be sure that the requested device is open */
  892. if (( dev_table[ dev_number ].mode == DEVMODE_CLOSED ) ||
  893. ( dev_table[ req_devnumber ].mode == DEVMODE_AVAILABLE ) )
  894. {
  895. #if PROG_ERRORS
  896. bwb_error( "in bwb_field(): Requested device number is not in use." );
  897. #else
  898. bwb_error( err_devnum );
  899. #endif
  900. return bwb_zline( l );
  901. }
  902. /* loop to read variables */
  903. do
  904. {
  905. /* read the comma and advance beyond it */
  906. adv_ws( l->buffer, &( l->position ) );
  907. if ( l->buffer[ l->position ] ==',' )
  908. {
  909. ++( l->position );
  910. }
  911. /* first find the size of the field */
  912. adv_element( l->buffer, &( l->position ), atbuf ); /* get element */
  913. pos = 0;
  914. e = bwb_exp( atbuf, FALSE, &pos );
  915. if ( e->type != NUMBER )
  916. {
  917. #if PROG_ERRORS
  918. bwb_error( "in bwb_field(): number value for field size not found" );
  919. #else
  920. bwb_error( err_syntax );
  921. #endif
  922. return bwb_zline( l );
  923. }
  924. length = (int) exp_getnval( e );
  925. #if INTENSIVE_DEBUG
  926. sprintf( bwb_ebuf, "in bwb_field(): device <%d> length <%d> buf <%s>",
  927. dev_number, length, &( l->buffer[ l->position ] ) );
  928. bwb_debug( bwb_ebuf );
  929. #endif
  930. /* read the AS */
  931. adv_element( l->buffer, &( l->position ), atbuf ); /* get element */
  932. bwb_strtoupper( atbuf );
  933. #if INTENSIVE_DEBUG
  934. sprintf( bwb_ebuf, "in bwb_field(): AS element <%s>", atbuf );
  935. bwb_debug( bwb_ebuf );
  936. #endif
  937. if ( strncmp( atbuf, "AS", 2 ) != 0 )
  938. {
  939. #if PROG_ERRORS
  940. bwb_error( "in bwb_field(): AS statement not found" );
  941. #else
  942. bwb_error( err_syntax );
  943. #endif
  944. return bwb_zline( l );
  945. }
  946. /* read the string variable name */
  947. adv_element( l->buffer, &( l->position ), atbuf ); /* get element */
  948. v = var_find( atbuf );
  949. if ( v->type != STRING )
  950. {
  951. #if PROG_ERRORS
  952. bwb_error( "in bwb_field(): string variable name not found" );
  953. #else
  954. bwb_error( err_syntax );
  955. #endif
  956. return bwb_zline( l );
  957. }
  958. #if INTENSIVE_DEBUG
  959. sprintf( bwb_ebuf, "in bwb_field(): device <%d> var <%s> length <%d>",
  960. dev_number, v->name, length );
  961. bwb_debug( bwb_ebuf );
  962. #endif
  963. /* check for overflow of record length */
  964. if ( ( current_pos + length ) > dev_table[ dev_number ].reclen )
  965. {
  966. #if PROG_ERRORS
  967. bwb_error( "in bwb_field(): record length exceeded" );
  968. #else
  969. bwb_error( err_overflow );
  970. #endif
  971. return bwb_zline( l );
  972. }
  973. /* set buffer */
  974. b = var_findsval( v, v->array_pos );
  975. #if DONTDOTHIS
  976. if ( b->sbuffer != NULL )
  977. {
  978. free( b->sbuffer );
  979. }
  980. #endif
  981. b->sbuffer = dev_table[ dev_number ].buffer + current_pos;
  982. b->length = (unsigned char) length;
  983. b->rab = TRUE;
  984. current_pos += length;
  985. #if INTENSIVE_DEBUG
  986. sprintf( bwb_ebuf, "in bwb_field(): buffer <%lXh> var <%s> buffer <%lXh>",
  987. (long) dev_table[ dev_number ].buffer, v->name, (long) b->buffer );
  988. bwb_debug( bwb_ebuf );
  989. #endif
  990. /* eat up any remaining whitespace */
  991. adv_ws( l->buffer, &( l->position ) );
  992. }
  993. while ( l->buffer[ l->position ] == ',' );
  994. /* return */
  995. return bwb_zline( l );
  996. }
  997. /***************************************************************
  998. FUNCTION: bwb_lset()
  999. DESCRIPTION: This C function implements the BASIC
  1000. LSET command.
  1001. SYNTAX: LSET string-variable$ = expression
  1002. ***************************************************************/
  1003. #if ANSI_C
  1004. struct bwb_line *
  1005. bwb_lset( struct bwb_line *l )
  1006. #else
  1007. struct bwb_line *
  1008. bwb_lset( l )
  1009. struct bwb_line *l;
  1010. #endif
  1011. {
  1012. return dio_lrset( l, FALSE );
  1013. }
  1014. /***************************************************************
  1015. FUNCTION: bwb_rset()
  1016. DESCRIPTION: This C function implements the BASIC
  1017. RSET command.
  1018. SYNTAX: RSET string-variable$ = expression
  1019. ***************************************************************/
  1020. #if ANSI_C
  1021. struct bwb_line *
  1022. bwb_rset( struct bwb_line *l )
  1023. #else
  1024. struct bwb_line *
  1025. bwb_rset( l )
  1026. struct bwb_line *l;
  1027. #endif
  1028. {
  1029. return dio_lrset( l, TRUE );
  1030. }
  1031. /***************************************************************
  1032. FUNCTION: dio_lrset()
  1033. DESCRIPTION: This C function implements the BASIC
  1034. RSET and LSET commands.
  1035. ***************************************************************/
  1036. #if ANSI_C
  1037. static struct bwb_line *
  1038. dio_lrset( struct bwb_line *l, int rset )
  1039. #else
  1040. static struct bwb_line *
  1041. dio_lrset( l, rset )
  1042. struct bwb_line *l;
  1043. int rset;
  1044. #endif
  1045. {
  1046. char varname[ MAXVARNAMESIZE + 1 ];
  1047. bstring *d, *s;
  1048. int *pp;
  1049. int n_params;
  1050. int p;
  1051. register int n, i;
  1052. int startpos;
  1053. struct exp_ese *e;
  1054. /* find the variable name */
  1055. bwb_getvarname( l->buffer, varname, &( l->position ));
  1056. v = var_find( varname );
  1057. if ( v == NULL )
  1058. {
  1059. #if PROG_ERRORS
  1060. sprintf( bwb_ebuf, "in dio_lrset(): failed to find variable" );
  1061. bwb_error( bwb_ebuf );
  1062. #else
  1063. bwb_error( err_syntax );
  1064. #endif
  1065. }
  1066. if ( v->type != STRING )
  1067. {
  1068. #if PROG_ERRORS
  1069. sprintf( bwb_ebuf, "in dio_lrset(): assignment must be to string variable" );
  1070. bwb_error( bwb_ebuf );
  1071. #else
  1072. bwb_error( err_syntax );
  1073. #endif
  1074. }
  1075. /* read subscripts */
  1076. pos = 0;
  1077. if ( ( v->dimensions == 1 ) && ( v->array_sizes[ 0 ] == 1 ))
  1078. {
  1079. #if INTENSIVE_DEBUG
  1080. sprintf( bwb_ebuf, "in dio_lrset(): variable <%s> has 1 dimension",
  1081. v->name );
  1082. bwb_debug( bwb_ebuf );
  1083. #endif
  1084. n_params = 1;
  1085. pp = &p;
  1086. pp[ 0 ] = dim_base;
  1087. }
  1088. else
  1089. {
  1090. #if INTENSIVE_DEBUG
  1091. sprintf( bwb_ebuf, "in dio_lrset(): variable <%s> has > 1 dimensions",
  1092. v->name );
  1093. bwb_debug( bwb_ebuf );
  1094. #endif
  1095. dim_getparams( l->buffer, &( l->position ), &n_params, &pp );
  1096. }
  1097. CURTASK exps[ CURTASK expsc ].pos_adv = pos;
  1098. for ( n = 0; n < v->dimensions; ++n )
  1099. {
  1100. v->array_pos[ n ] = pp[ n ];
  1101. }
  1102. /* get bstring pointer */
  1103. d = var_findsval( v, pp );
  1104. /* find equals sign */
  1105. adv_ws( l->buffer, &( l->position ));
  1106. if ( l->buffer[ l->position ] != '=' )
  1107. {
  1108. #if PROG_ERRORS
  1109. sprintf( bwb_ebuf, "in dio_lrset(): failed to find equal sign" );
  1110. bwb_error( bwb_ebuf );
  1111. #else
  1112. bwb_error( err_syntax );
  1113. #endif
  1114. }
  1115. ++( l->position );
  1116. adv_ws( l->buffer, &( l->position ));
  1117. /* read remainder of line to get value */
  1118. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  1119. s = exp_getsval( e );
  1120. /* set starting position */
  1121. startpos = 0;
  1122. if ( rset == TRUE )
  1123. {
  1124. if ( s->length < d->length )
  1125. {
  1126. startpos = d->length - s->length;
  1127. }
  1128. }
  1129. #if INTENSIVE_DEBUG
  1130. sprintf( bwb_ebuf, "in dio_lrset(): startpos <%d> buffer <%lX>",
  1131. startpos, (long) d->buffer );
  1132. bwb_debug( bwb_ebuf );
  1133. #endif
  1134. /* write characters to new position */
  1135. i = 0;
  1136. for ( n = startpos; ( i < (int) s->length ) && ( n < (int) d->length ); ++n )
  1137. {
  1138. d->sbuffer[ n ] = s->sbuffer[ i ];
  1139. ++i;
  1140. }
  1141. /* return */
  1142. return bwb_zline( l );
  1143. }
  1144. /***************************************************************
  1145. FUNCTION: bwb_get()
  1146. DESCRIPTION: This C function implements the BASIC
  1147. GET command.
  1148. SYNTAX: GET [#] device-number [, record-number]
  1149. ***************************************************************/
  1150. #if ANSI_C
  1151. struct bwb_line *
  1152. bwb_get( struct bwb_line *l )
  1153. #else
  1154. struct bwb_line *
  1155. bwb_get( l )
  1156. struct bwb_line *l;
  1157. #endif
  1158. {
  1159. int dev_number;
  1160. int rec_number;
  1161. register int i;
  1162. struct exp_ese *e;
  1163. char atbuf[ MAXSTRINGSIZE + 1 ];
  1164. /* first read device number */
  1165. adv_ws( l->buffer, &( l->position ) );
  1166. if ( l->buffer[ l->position ] =='#' )
  1167. {
  1168. ++( l->position );
  1169. }
  1170. adv_element( l->buffer, &( l->position ), atbuf );
  1171. pos = 0;
  1172. e = bwb_exp( atbuf, FALSE, &pos );
  1173. if ( e->type != NUMBER )
  1174. {
  1175. #if PROG_ERRORS
  1176. bwb_error( "in bwb_get(): Number was expected for device number" );
  1177. #else
  1178. bwb_error( err_syntax );
  1179. #endif
  1180. return bwb_zline( l );
  1181. }
  1182. dev_number = (int) exp_getnval( e );
  1183. #if INTENSIVE_DEBUG
  1184. sprintf( bwb_ebuf, "in bwb_get(): device <%d>", dev_number );
  1185. bwb_debug( bwb_ebuf );
  1186. #endif
  1187. /* be sure that the requested device is open */
  1188. if ( ( dev_table[ dev_number ].mode == DEVMODE_CLOSED ) ||
  1189. ( dev_table[ req_devnumber ].mode == DEVMODE_AVAILABLE ) )
  1190. {
  1191. #if PROG_ERRORS
  1192. bwb_error( "in bwb_get(): Requested device number is not in use." );
  1193. #else
  1194. bwb_error( err_devnum );
  1195. #endif
  1196. return bwb_zline( l );
  1197. }
  1198. /* see if there is a comma (and record number) */
  1199. adv_ws( l->buffer, &( l->position ) );
  1200. if ( l->buffer[ l->position ] == ',' ) /* yes, there is a comma */
  1201. {
  1202. ++( l->position );
  1203. /* get the record number element */
  1204. adv_element( l->buffer, &( l->position ), atbuf );
  1205. pos = 0;
  1206. e = bwb_exp( atbuf, FALSE, &pos );
  1207. rec_number = (int) exp_getnval( e );
  1208. }
  1209. else /* no record number given */
  1210. {
  1211. rec_number = dev_table[ dev_number ].next_record;
  1212. }
  1213. #if INTENSIVE_DEBUG
  1214. sprintf( bwb_ebuf, "in bwb_get(): record number <%d>", rec_number );
  1215. bwb_debug( bwb_ebuf );
  1216. #endif
  1217. /* wind the c file up to the proper point */
  1218. if ( fseek( dev_table[ dev_number ].cfp,
  1219. (long) (( rec_number - 1 ) * dev_table[ dev_number ].reclen ),
  1220. SEEK_SET ) != 0 )
  1221. {
  1222. #if PROG_ERRORS
  1223. sprintf( bwb_ebuf, "in bwb_get(): fseek() failed, rec number <%d> offset <%ld>",
  1224. rec_number, (long) (( rec_number - 1 ) * dev_table[ dev_number ].reclen ) );
  1225. bwb_error( bwb_ebuf );
  1226. #else
  1227. bwb_error( err_dev );
  1228. #endif
  1229. return bwb_zline( l );
  1230. }
  1231. /* read the requested bytes into the buffer */
  1232. for ( i = 0; i < dev_table[ dev_number ].reclen; ++i )
  1233. {
  1234. dev_table[ dev_number ].buffer[ i ] =
  1235. (char) fgetc( dev_table[ dev_number ].cfp );
  1236. ++( dev_table[ dev_number ].loc );
  1237. }
  1238. /* increment (or reset) the current record */
  1239. dev_table[ dev_number ].next_record = rec_number + 1;
  1240. return bwb_zline( l );
  1241. }
  1242. /***************************************************************
  1243. FUNCTION: bwb_put()
  1244. DESCRIPTION: This C function implements the BASIC
  1245. PUT command.
  1246. SYNTAX: PUT [#] device-number [, record-number]
  1247. ***************************************************************/
  1248. #if ANSI_C
  1249. struct bwb_line *
  1250. bwb_put( struct bwb_line *l )
  1251. #else
  1252. struct bwb_line *
  1253. bwb_put( l )
  1254. struct bwb_line *l;
  1255. #endif
  1256. {
  1257. int dev_number;
  1258. int rec_number;
  1259. register int i;
  1260. struct exp_ese *e;
  1261. char atbuf[ MAXSTRINGSIZE + 1 ];
  1262. /* first read device number */
  1263. adv_ws( l->buffer, &( l->position ) );
  1264. if ( l->buffer[ l->position ] =='#' )
  1265. {
  1266. ++( l->position );
  1267. }
  1268. adv_element( l->buffer, &( l->position ), atbuf );
  1269. dev_number = atoi( atbuf );
  1270. #if INTENSIVE_DEBUG
  1271. sprintf( bwb_ebuf, "in bwb_put(): device <%d>", dev_number );
  1272. bwb_debug( bwb_ebuf );
  1273. #endif
  1274. /* be sure that the requested device is open */
  1275. if ( ( dev_table[ dev_number ].mode == DEVMODE_CLOSED ) ||
  1276. ( dev_table[ req_devnumber ].mode == DEVMODE_AVAILABLE ) )
  1277. {
  1278. #if PROG_ERRORS
  1279. bwb_error( "in bwb_put(): Requested device number is not in use." );
  1280. #else
  1281. bwb_error( err_devnum );
  1282. #endif
  1283. return bwb_zline( l );
  1284. }
  1285. /* see if there is a comma (and record number) */
  1286. adv_ws( l->buffer, &( l->position ) );
  1287. if ( l->buffer[ l->position ] == ',' ) /* yes, there is a comma */
  1288. {
  1289. ++( l->position );
  1290. /* get the record number element */
  1291. adv_element( l->buffer, &( l->position ), atbuf );
  1292. #if INTENSIVE_DEBUG
  1293. sprintf( bwb_ebuf, "in bwb_put(): rec no buffer <%s>", atbuf );
  1294. bwb_debug( bwb_ebuf );
  1295. #endif
  1296. pos = 0;
  1297. e = bwb_exp( atbuf, FALSE, &pos );
  1298. #if INTENSIVE_DEBUG
  1299. sprintf( bwb_ebuf, "in bwb_put(): return type <%c>", e->type );
  1300. bwb_debug( bwb_ebuf );
  1301. #endif
  1302. rec_number = (int) exp_getnval( e );
  1303. }
  1304. else /* no record number given */
  1305. {
  1306. rec_number = dev_table[ dev_number ].next_record;
  1307. }
  1308. #if INTENSIVE_DEBUG
  1309. sprintf( bwb_ebuf, "in bwb_put(): record number <%d>", rec_number );
  1310. bwb_debug( bwb_ebuf );
  1311. #endif
  1312. /* wind the c file up to the proper point */
  1313. if ( fseek( dev_table[ dev_number ].cfp,
  1314. (long) (( rec_number - 1 ) * dev_table[ dev_number ].reclen ),
  1315. SEEK_SET ) != 0 )
  1316. {
  1317. #if PROG_ERRORS
  1318. sprintf( bwb_ebuf, "in bwb_get(): fseek() failed, rec number <%d> offset <%ld>",
  1319. rec_number, (long) (( rec_number - 1 ) * dev_table[ dev_number ].reclen ) );
  1320. bwb_error( bwb_ebuf );
  1321. #else
  1322. bwb_error( err_dev );
  1323. #endif
  1324. return bwb_zline( l );
  1325. }
  1326. #if INTENSIVE_DEBUG
  1327. sprintf( bwb_ebuf, "in bwb_put(): ready to write to file, buffer <%lXh>",
  1328. (long) dev_table[ dev_number ].buffer );
  1329. bwb_debug( bwb_ebuf );
  1330. prn_xprintf( stderr, "Buffer: <" );
  1331. #endif
  1332. /* write the requested bytes to the file */
  1333. for ( i = 0; i < dev_table[ dev_number ].reclen; ++i )
  1334. {
  1335. fputc( dev_table[ dev_number ].buffer[ i ],
  1336. dev_table[ dev_number ].cfp );
  1337. #if INTENSIVE_DEBUG
  1338. xputc( stderr, dev_table[ dev_number ].buffer[ i ] );
  1339. #endif
  1340. ++( dev_table[ dev_number ].loc );
  1341. }
  1342. #if INTENSIVE_DEBUG
  1343. prn_xprintf( stderr, ">\n" );
  1344. sprintf( bwb_ebuf, "in bwb_put(): write to file complete" );
  1345. bwb_debug( bwb_ebuf );
  1346. #endif
  1347. /* flush the buffer */
  1348. dio_flush( dev_number );
  1349. /* increment (or reset) the current record */
  1350. dev_table[ dev_number ].next_record = rec_number + 1;
  1351. return bwb_zline( l );
  1352. }
  1353. /***************************************************************
  1354. FUNCTION: dio_flush()
  1355. DESCRIPTION: This C function flushes the random-access
  1356. buffer associated with file dev_number.
  1357. ***************************************************************/
  1358. #if ANSI_C
  1359. static int
  1360. dio_flush( int dev_number )
  1361. #else
  1362. static int
  1363. dio_flush( dev_number )
  1364. int dev_number;
  1365. #endif
  1366. {
  1367. register int n;
  1368. if ( dev_table[ dev_number ].mode != DEVMODE_RANDOM )
  1369. {
  1370. #if PROG_ERRORS
  1371. sprintf( bwb_ebuf, "in dio_flush(): only random-access buffers can be flushed" );
  1372. bwb_error( bwb_ebuf );
  1373. #else
  1374. bwb_error( err_dev );
  1375. #endif
  1376. }
  1377. /* fill buffer with blanks (or 'X' for test) */
  1378. for ( n = 0; n < dev_table[ req_devnumber ].reclen; ++n )
  1379. {
  1380. dev_table[ req_devnumber ].buffer[ n ] = RANDOM_FILLCHAR;
  1381. }
  1382. return TRUE;
  1383. }
  1384. #endif /* COMMON_CMDS */
  1385.