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.
 
 
 
 
 
 

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