home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume3 / bt-rio < prev    next >
Internet Message Format  |  1989-02-03  |  44KB

  1. Path: xanth!mcnc!decvax!decwrl!purdue!umd5!ames!necntc!ncoast!allbery
  2. From: mjr@welchsun2.UUCP (Marcus J. Ranum)
  3. Newsgroups: comp.sources.misc
  4. Subject: v03i050: record I/O library for use with btree package
  5. Message-ID: <7953@ncoast.UUCP>
  6. Date: 12 Jun 88 21:53:45 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: mjr@welchsun2.UUCP (Marcus J. Ranum)
  9. Lines: 1736
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. comp.sources.misc: Volume 3, Issue 50
  13. Submitted-By: "Marcus J. Ranum" <mjr@welchsun2.UUCP>
  14. Archive-Name: bt-rio
  15.  
  16. [Repackaged:  I applied a patch before posting.  ++bsa]
  17.  
  18. #--------------------------------CUT HERE-------------------------------------
  19. #! /bin/sh
  20. #
  21. # This is a shell archive.  Save this into a file, edit it
  22. # and delete all lines above this comment.  Then give this
  23. # file to sh by executing the command "sh file".  The files
  24. # will be extracted into the current directory owned by
  25. # you with default permissions.
  26. #
  27. # The files contained herein are:
  28. #
  29. # -rw-r--r--   1 allbery  System      1512 Jun 12 17:44 Makefile
  30. # -rw-r--r--   1 allbery  System      3119 Jun 12 17:44 README
  31. # -rw-r--r--   1 allbery  System      5585 Jun 12 17:44 example.c
  32. # -rw-r--r--   1 allbery  System      7001 Jun 12 17:44 recio.3
  33. # -rw-r--r--   1 allbery  System     17221 Jun 12 17:45 recio.c
  34. # -rw-r--r--   1 allbery  System      2905 Jun 12 17:44 recio.h
  35. # -rw-r--r--   1 allbery  System       823 Jun 12 17:44 sizes.c
  36. #
  37. echo 'x - Makefile'
  38. if test -f Makefile; then echo 'shar: not overwriting Makefile'; else
  39. sed 's/^X//' << '________This_Is_The_END________' > Makefile
  40. X# Makefile for record I/O library 
  41. X# Copyright (C) 1988, Marcus J. Ranum, William Welch Medical Library
  42. X# $Author: mjr $ 
  43. X# 
  44. X# $Header: Makefile,v 1.1 88/06/01 21:29:16 mjr rel $: Makefile 
  45. X# 
  46. X# $Log:    Makefile,v $
  47. X# Revision 1.1  88/06/01  21:29:16  mjr
  48. X# Initial revision
  49. X# 
  50. X# 
  51. X# define SYSV or BSD (only for purposes of test code) - recio.c doesn't care.
  52. X# defining BYTEORDER forces the system to maintain disk data structures
  53. X# in network byteorder. This may be more or less portable. (tested on
  54. X# VAXEN running ULTRIX and Suns)
  55. X# 
  56. X#CFLAGS=-O -DBSD -DBYTEORDER
  57. XCFLAGS=-O -DBSD
  58. XLFLAGS=-s
  59. XLINTFLAGS=-h -x -u -DBSD
  60. X
  61. XLIB=    librecio.a
  62. X#LIB=    recio.o
  63. X
  64. X# installation stuff
  65. XLIBDIR=    /usr/local/lib
  66. XHDR=    recio.h
  67. XHDRDIR=    /usr/include/local
  68. XMAN=    recio.3
  69. XMANDIR=    /usr/man/manl
  70. X
  71. Xall:    example sizes
  72. X
  73. Xlibrecio.a:    recio.o
  74. X    ar rcv $@ recio.o
  75. X    ranlib $@
  76. X
  77. Xexample:    $(LIB) example.o
  78. X    cc $(LFLAGS) -o example example.o $(LIB)
  79. X
  80. Xsizes:        sizes.o
  81. X    cc $(LFLAGS) -o sizes sizes.o
  82. X    @sizes
  83. X
  84. Xrecio.o:    $(HDR) Makefile
  85. Xexample.o:    $(HDR) Makefile
  86. X
  87. Xinstall:    $(LIB) $(MAN)
  88. X    cp $(LIB) $(LIBDIR)/$(LIB)
  89. X    chmod 644 $(LIBDIR)/$(LIB)
  90. X    cp $(HDR) $(HDRDIR)/$(HDR)
  91. X    chmod 644 $(HDRDIR)/$(HDR)
  92. X    ranlib $(LIBDIR)/$(LIB)
  93. X    cp $(MAN) $(MANDIR)/$(MAN)
  94. X    chmod 644 $(MANDIR)/$(MAN)
  95. X
  96. Xclean:
  97. X    rm -f $(LIB) *.o example core mon.out sizes llib-lrecio.ln \
  98. X    recio.shar tags
  99. X
  100. Xlint:
  101. X    lint $(LINTFLAGS) recio.c
  102. X
  103. Xdiction:
  104. X    style $(MAN)
  105. X    diction $(MAN)
  106. X
  107. Xlintlib:
  108. X    lint -Crecio recio.c
  109. X
  110. Xshar:
  111. X    shar -a README Makefile recio.c $(HDR) $(MAN) sizes.c example.c\
  112. X    > recio.shar
  113. ________This_Is_The_END________
  114. if test `wc -c < Makefile` -ne 1512; then
  115.     echo 'shar: Makefile was damaged during transit (should have been 1512 bytes)'
  116. fi
  117. fi        ; : end of overwriting check
  118. echo 'x - README'
  119. if test -f README; then echo 'shar: not overwriting README'; else
  120. sed 's/^X//' << '________This_Is_The_END________' > README
  121. XThe poor man's record management library:
  122. X
  123. XThis is partII of the poor man's data management library. It's intended
  124. Xfor use with the btree index library, but can also be used stand alone.
  125. XThe recio library is designed with the following in mind:
  126. X
  127. X1) a simple low-level package to support inserting, modifying and
  128. Xretrieving records of (not necessarily fixed) length into a file. This
  129. Xis doubtless less efficient than simply keeping a whole bunch of UNIX
  130. Xfiles around, but that is a pain.  The recio package, then, trades the
  131. Xspeed and elegance of UNIX files for a chunk-oriented structure that
  132. Xresides in a single UNIX file.
  133. X
  134. X2) a read/write/lseek-like interface, with a rudimentary higher level
  135. Xthat looks somewhat like stdio (at least puts/gets)
  136. X
  137. X3) reasonable performance and stability. It'll never be as fast as UNIX
  138. Xfiles, since the files are stored in 'linked' chunks, which are parsed
  139. Xin succession. There are a lot of trade offs.
  140. X
  141. XThe recio files are stored as a pair of UNIX files, one of which
  142. Xcontains a map of records by number to pages in the actual data file.
  143. XThe map file also contains information about which blocks in the data
  144. Xfile are free, etc. This file can contain 'holes', since a record is
  145. Xcreated at a specific offset per record number. The structures are as
  146. Xsmall as possible to minimize side-effects. The data file consists of
  147. Xpages of variable size (set when the data file is created). Each page
  148. Xcontains some small amount of information in a header, including
  149. Xpointers to a chain of offspring nodes, if needed, as well as
  150. Xadditional information about whether that block is free, in case the
  151. Xfile needs to be reconstructed.  The recio.h header file lays it all
  152. Xout, somewhat.
  153. X
  154. XAs with the poor man's btree library, there are no concurrency controls
  155. Xin effect. The design of the whole package is with an eye to having it
  156. Xbe serviced by a deamon across a network, anyway, so this problem is
  157. Xleft as an excercise for the reader :-) Also, like the poor man's btree
  158. Xlibrary, this code is not public domain, though it is freely modifiable
  159. Xand distributable as long as the copyright notices are retained.  If
  160. Xyou make any nifty improvements, please let me know, (E-mail, I am not
  161. Xon usenet) bugfixes, etc, are welcome.
  162. X
  163. XByte-order and portability: There are #ifdefs for BYTEORDER, which make
  164. Xthe program store data in network byte order (at least the data
  165. Xstructures that drive the library - user data is the user's problem.)
  166. XThere are several unsolved problems with this approach. It works fine
  167. Xbetween my Sun and my VAX, but the way the structures are written to
  168. Xdisk is also going to depend on your compiler. (the deleted element of
  169. Xstruct ripag is a long to force alignment in the VAX compiler, which
  170. Xthought a ripag was 16 bytes, while the Sun thought it was 15, with
  171. XNASTY results) The BYTEORDER code is not guaranteed to work, and if it
  172. Xdoesn't, your best bet is to look at the output of sizes.c and to check
  173. Xto see if your compiler assembles the structures in the same ORDER.
  174. X
  175. X    Marcus J. Ranum, William Welch Medical Library, 1988
  176. X    mjr@jhuigf.BITNET || uunet!mimsy!aplcen!osiris!welchvax!mjr
  177. ________This_Is_The_END________
  178. if test `wc -c < README` -ne 3119; then
  179.     echo 'shar: README was damaged during transit (should have been 3119 bytes)'
  180. fi
  181. fi        ; : end of overwriting check
  182. echo 'x - example.c'
  183. if test -f example.c; then echo 'shar: not overwriting example.c'; else
  184. sed 's/^X//' << '________This_Is_The_END________' > example.c
  185. X/*
  186. X * Copyright (C) 1988, Marcus J. Ranum, William Welch Medical Library
  187. X * $Author: mjr $
  188. X */
  189. X
  190. X#ifndef lint
  191. Xstatic char *RCSid="$Header: example.c,v 1.1 88/06/01 21:27:06 mjr Rel $: example.c";
  192. X#endif
  193. X
  194. X/*
  195. X * $Log:    example.c,v $
  196. X * Revision 1.1  88/06/01  21:27:06  mjr
  197. X * Initial revision
  198. X * 
  199. X */
  200. X
  201. X/* sample page size to use - obviously 20 is quite small, but it makes */
  202. X/* testing things really a lot easier than having to enter 1024 bytes of */
  203. X/* junk data for testing input */
  204. X
  205. X#define SAMPLESIZE 20
  206. X
  207. X
  208. X/* nobody ever writes nice test programs. in fact, this one is pretty gross */
  209. X/* basically, this allows exercising all the various functions of the rifd */
  210. X/* library */
  211. X
  212. X#ifdef BSD
  213. X#include <sys/file.h>
  214. X#endif
  215. X#ifdef SYSV
  216. X#include <sys/fcntl.h>
  217. X#endif
  218. X#include <stdio.h>
  219. X#include "recio.h"
  220. X
  221. Xvoid
  222. Xhelp()
  223. X{
  224. X    (void)printf("commands are:\n");
  225. X    (void)printf("Read:\treads a chunk of the requested record.\n");
  226. X    (void)printf("\tNote that this is artificially constrained in this\n");
  227. X    (void)printf("\texample, to show how the consecutive reads work\n");
  228. X    (void)printf("\nMore\tprints the next chunk in consecutive reads.\n");
  229. X    (void)printf("\nGets\treturns pointer to next line.\n");
  230. X    (void)printf("\nPuts\tappends a newline terminated string to rec.\n");
  231. X    (void)printf("\nDel\tdeletes the named record by placing its blocks\n");
  232. X    (void)printf("\ton the free block list\n");
  233. X    (void)printf("\nLabel\tsets the database comment block that resides\n");
  234. X    (void)printf("\tin page #0 of the page file.\n");
  235. X    (void)printf("\nWrite\tallows input of text to a specified record.\n");
  236. X    (void)printf("\nAppen\tallows appending text to a specified record.\n");
  237. X    (void)printf("\nHelp\tthis.\n");
  238. X}
  239. X
  240. Xmain(ac,av)
  241. Xint    ac;
  242. Xchar    *av[];
  243. X{
  244. X    RIFD    *h1;
  245. X    char    instr[BUFSIZ];
  246. X    char    buf[BUFSIZ];
  247. X    char    *files[2];
  248. X    long    rec;
  249. X    int    ret;
  250. X    int    size = SAMPLESIZE;/* page block size - we use a small */
  251. X                /* size to give things a real workout */
  252. X    int    num;
  253. X    extern    long    atol();
  254. X    extern    char    *gets();
  255. X    extern    char    *strcat();
  256. X
  257. X    if(ac < 3) {
  258. X        (void)fprintf(stderr,"(using foo.map foo.pag)\n");
  259. X        files[0] = "foo.map";
  260. X        files[1] = "foo.pag";
  261. X    } else {
  262. X        /* there are keener ways of doing this, but why ? */
  263. X        files[0] = av[1]; 
  264. X        files[1] = av[2];
  265. X    }
  266. X
  267. X    (void)printf("record page size to use:(<return> = %d)",size);
  268. X    (void)gets(instr);
  269. X    if(strlen(instr) != 0)
  270. X        size = atoi(instr);
  271. X
  272. X    /* args passed in order: textfile,mapfile */
  273. X    if((h1 = riopen(files,O_CREAT|O_RDWR,0600,size)) ==NULL) {
  274. X        perror(av[1]);
  275. X        exit(1);
  276. X    }
  277. X
  278. X
  279. X    while (1) {
  280. X        (void)printf("Read  More  Gets  Puts  Del  Label  Write  Appen  Help  Quit:");
  281. X        if(gets(instr) == NULL)
  282. X            exit(riclose(h1));
  283. X
  284. X        switch (*instr) {
  285. X
  286. X        case 'q':
  287. X        case 'Q':
  288. X            exit(riclose(h1));
  289. X
  290. X        case 'd':
  291. X        case 'D':
  292. X            (void)printf("delete record:");
  293. X            (void)gets(instr);
  294. X            rec = atol(instr);
  295. X            ret = riunlink(h1,rec);
  296. X            (void)printf("...returns %d\n",ret);
  297. X            break;
  298. X
  299. X        case 'g':
  300. X        case 'G':
  301. X            (void)printf("gets from record:(<return> = continue)");
  302. X            (void)gets(instr);
  303. X            if(strlen(instr) != 0)
  304. X                num = atol(instr);
  305. X            
  306. X            buf[0] = '\0';
  307. X            if(rigets(h1,rec,buf) != NULL)
  308. X                (void)printf("\"%s\"\n",buf);
  309. X            else
  310. X                (void)printf("returns NULL\n");
  311. X            break;
  312. X
  313. X        case 'r':
  314. X        case 'R':
  315. X            /* this is just an example - not pretty */
  316. X            (void)printf("read record:");
  317. X            (void)gets(instr);
  318. X            rec = atol(instr);
  319. X            (void)printf("how many bytes (max:%d <return> = 20):",BUFSIZ);
  320. X            (void)gets(instr);
  321. X            num = atoi(instr);
  322. X            if(num ==0)
  323. X                num = 20;
  324. X            if(num > BUFSIZ)
  325. X                num = BUFSIZ;
  326. X            
  327. X            buf[0] = '\0';
  328. X            ret = riread(h1,rec,buf,num,0);
  329. X
  330. X            if(ret >= 0) 
  331. X                (void)printf("\"%s\"\n",buf);
  332. X            else
  333. X                (void)printf("returns %d\n",ret);
  334. X            break;
  335. X
  336. X
  337. X        case 'm':
  338. X        case 'M':
  339. X            (void)printf("how many bytes (max:%d <return>=20):",BUFSIZ);
  340. X            (void)gets(instr);
  341. X            num = atoi(instr);
  342. X            if(num ==0)
  343. X                num = 20;
  344. X            if(num > BUFSIZ)
  345. X                num = BUFSIZ;
  346. X            buf[0] = '\0';
  347. X            ret = riread(h1,rec,buf,num,1);
  348. X            if(ret > 0) 
  349. X                (void)printf("\"%s\"\n",buf);
  350. X            else
  351. X                (void)printf("returns %d\n",ret);
  352. X            break;
  353. X
  354. X        case 'p':
  355. X        case 'P':
  356. X            (void)printf("puts to record: (<return> = same record)");
  357. X            (void)gets(instr);
  358. X            if(strlen(instr) != 0)
  359. X                rec = atol(instr);
  360. X
  361. X            (void)printf("enter data: ");
  362. X            (void)gets(buf);
  363. X            if(riputs(h1,rec,buf) == EOF)
  364. X                (void)printf("returns EOF\n");
  365. X            else
  366. X                (void)printf(" ok\n");
  367. X
  368. X            break;
  369. X
  370. X        case 'w':
  371. X        case 'W':
  372. X            /* this is just an example - not pretty */
  373. X            (void)printf("write to record:");
  374. X            (void)gets(instr);
  375. X            rec = atol(instr);
  376. X            (void)printf("enter data: ");
  377. X            (void)gets(buf);
  378. X            ret = riwrite(h1,rec,buf,strlen(buf),0);
  379. X
  380. X            (void)printf("....returns %d-",ret);
  381. X            if(ret == strlen(buf))
  382. X                (void)printf(" ok\n");
  383. X            else
  384. X                (void)printf(" count does not match\n");
  385. X
  386. X            break;
  387. X
  388. X        case 'a':
  389. X        case 'A':
  390. X            (void)printf("append to record:");
  391. X            (void)gets(instr);
  392. X            (void)printf("enter data:");
  393. X            (void)gets(buf);
  394. X            ret = riwrite(h1,rec,buf,strlen(buf),1);
  395. X
  396. X            (void)printf("....returns %d-",ret);
  397. X            if(ret == strlen(buf))
  398. X                (void)printf(" ok\n");
  399. X            else
  400. X                (void)printf(" count does not match\n");
  401. X
  402. X            break;
  403. X
  404. X        case 'h':
  405. X        case 'H':
  406. X            (void)help();
  407. X            break;
  408. X
  409. X        case 'l':
  410. X        case 'L':
  411. X            (void)printf("enter label:");
  412. X            *buf = '\0';
  413. X
  414. X            (void)gets(buf);
  415. X            ret = risetlab(h1,buf,strlen(buf));
  416. X            if(ret == 0) {
  417. X                *buf = '\0';
  418. X                if(rigetlab(h1,buf,BUFSIZ) <0) {
  419. X                    (void)printf("error reading label\n");
  420. X                } else {
  421. X                    (void)printf("label is:\"%s\"\n",buf);
  422. X                }
  423. X            } else {
  424. X                (void)printf("error writing label\n");
  425. X            }
  426. X            break;
  427. X
  428. X
  429. X        default:
  430. X            (void)printf("huh?\n");
  431. X        }
  432. X    }
  433. X}
  434. ________This_Is_The_END________
  435. if test `wc -c < example.c` -ne 5585; then
  436.     echo 'shar: example.c was damaged during transit (should have been 5585 bytes)'
  437. fi
  438. fi        ; : end of overwriting check
  439. echo 'x - recio.3'
  440. if test -f recio.3; then echo 'shar: not overwriting recio.3'; else
  441. sed 's/^X//' << '________This_Is_The_END________' > recio.3
  442. X.\" recio.3l (C)1988 Marcus J. Ranum, Welch Medical Library
  443. X.\" $Header: recio.3,v 1.1 88/06/01 21:28:40 mjr rel $
  444. X.TH RECIO 3l
  445. X.SH NAME
  446. Xriopen, riclose, riwrite, riread, riunlink, rigets, riputs, risetlab, rigetlab
  447. X.br
  448. X\- the poor man's record management library
  449. X.SH SYNTAX
  450. X.B #include <local/recio.h>
  451. X.PP
  452. X.B RIFD *riopen(paths,flags,mode,size)
  453. X.br
  454. X.SM
  455. X.B char *paths[2];
  456. X.br
  457. X.B int flags, mode, size;
  458. X.PP
  459. X.B int riclose(rifd)
  460. X.br
  461. X.SM
  462. X.B RIFD *rifd;
  463. X.PP
  464. X.B int riwrite(rifd,recno,buf,num,appen)
  465. X.br
  466. X.SM
  467. X.B RIFD *rifd;
  468. X.br
  469. X.B long recno;
  470. X.br
  471. X.B char *buf;
  472. X.br
  473. X.B int num, appen;
  474. X.PP
  475. X.B int riread(rifd,recno,buf,num,cont)
  476. X.br
  477. X.SM
  478. X.B RIFD *rifd;
  479. X.br
  480. X.B long recno;
  481. X.br
  482. X.B char *buf;
  483. X.br
  484. X.B int num, cont;
  485. X.PP
  486. X.B int riunlink(rifd,recno)
  487. X.br
  488. X.SM
  489. X.B RIFD *rifd;
  490. X.br
  491. X.B long recno;
  492. X.PP
  493. X.B char *rigets(rifd,recno,buf)
  494. X.br
  495. X.SM
  496. X.B RIFD *rifd;
  497. X.br
  498. X.B long recno;
  499. X.br
  500. X.B char *buf;
  501. X.PP
  502. X.B int riputs(rifd,recno,buf)
  503. X.br
  504. X.SM
  505. X.B RIFD *rifd;
  506. X.br
  507. X.B long recno;
  508. X.br
  509. X.B char *buf;
  510. X.sp
  511. X.PP
  512. X.B int risetlab(rifd,buf,size)
  513. X.br
  514. X.SM
  515. X.B RIFD *rifd;
  516. X.br
  517. X.B char *buf;
  518. X.br
  519. X.B int size;
  520. X.sp
  521. X.PP
  522. X.B int rigetlab(rifd,buf,size)
  523. X.br
  524. X.SM
  525. X.B RIFD *rifd;
  526. X.br
  527. X.B char *buf;
  528. X.br
  529. X.B int size;
  530. X.sp
  531. X.SH DESCRIPTION
  532. X.PP
  533. XThe poor man's record management library is a set of routines to manage
  534. Xfiles containing linked chunks of data that can be either fixed or
  535. Xvariable length. Records are designed to be stored based on the
  536. Xrecord number (presumably indexed someplace else, hashed, or whatever).
  537. XEach data file consists of two UNIX files, the "record" file and the "map"
  538. Xfile. The "map" file contains very little, holding one entry per
  539. Xrecord number, consisting of the numbers of the first and last data
  540. Xrecords. The "record" file contains a linked list of records, with a small
  541. Xheader preceeding each, with information about which record it belongs
  542. Xto, whether it is deleted, which record is the successor, etc. Some of
  543. Xthe information is redundant, to make consistency checking possible.
  544. XA free chain of records is maintained, with a pointer to the first 
  545. Xstored in a superblock at the head of the "map" file. Deleted records are
  546. Xreclaimed as needed, though not in any order that prevents fragmentation.
  547. X.PP
  548. XThere are several extraneous elements in the RIFD data structure that
  549. Xkeep track of the current record, record offset, and so forth. This is used
  550. Xin the 
  551. X.B rigets()
  552. Xand
  553. X.B riputs()
  554. Xfunctions, which are designed to provide a familiar interface, as well
  555. Xas allowing a user to append to existing records, or read them a line
  556. Xat a time, with some minimally intelligent buffering. The
  557. X.B riwrite()
  558. Xand 
  559. X.B riread()
  560. Xfunctions also contain means for appending writes, or performing
  561. Xa sequential series of partial reads. These are useful kludges.
  562. X.PP
  563. XThe
  564. X.B riopen
  565. Xsubroutine allocates a  control structure, using the path names
  566. Xprovided in
  567. X.B paths.
  568. XThe first string in paths is assumed to be the name of the "map" file
  569. Xto use, and the second the "record" file. Needless to say, they should
  570. Xboth be the appropriate type of file, or trouble may ensue.
  571. XThe
  572. X.B flags
  573. Xand 
  574. X.B mode
  575. Xarguments are passed to open(2) to control creation and permissions.
  576. XThe
  577. X.B size
  578. Xargument is used to set the record size if the file needs to be
  579. Xcreated. (If the file already exists, the
  580. X.B size
  581. Xargument is ignored.)
  582. XIf the data file is created (either through
  583. Xopen(2) flags O_TRUNC or O_CREAT on a nonexistent file) a new header
  584. Xis initialized automatically, and the record size is set as
  585. Xrequested. A
  586. X.B size
  587. Xof 0 will result in the file being initialized with a record
  588. Xsize of BUFSIZ less the size of a record header.
  589. XThe size of the records should be chosen carefully, since it will
  590. Xaffect either disk usage or performance considerably.
  591. X.B Riopen
  592. Xchecks a magic number stored in the "map" file superblock, and will fail
  593. Xunless the magic number is correct, to prevent accidentally using a
  594. Xdamaged file, or an incorrect file. No such check is performed on
  595. Xthe "record" file. If
  596. X.B riopen
  597. Xcannot open the requested file, or encounters other problems,
  598. Xit returns NULL.
  599. X.PP
  600. XThe
  601. X.B riclose
  602. Xsubroutine closes opened files, and deallocates the memory that
  603. Xwas allocated in riopen.
  604. X.PP
  605. XThe
  606. X.B riwrite
  607. Xfunction writes
  608. X.B num
  609. Xbytes of data to the specified record from
  610. X.B buf.
  611. XIf the
  612. X.B appen
  613. Xflag is nonzero, the data is written to the end of the record. If the
  614. X.B appen
  615. Xflag is zero, any old data is overwritten. 
  616. X.B riwrite
  617. Xreturns -1 on error, or the number of bytes written. 
  618. X.PP
  619. XThe 
  620. X.B riread
  621. Xfunction reads data from the record file into 
  622. X.B buf,
  623. Xstopping when it has read 
  624. X.B num
  625. Xbytes, or when it has run out of data to read.
  626. X.B Riread
  627. Xreturns the number of bytes read, or -1 in the event of error. If 
  628. X.B cont
  629. Xis nonzero,
  630. X.B riread
  631. Xwill continue reading from where it left off after the last read,
  632. Xor from the beginning of the record. Due to the implementation, if
  633. Xa different record is read, the 
  634. X.B cont
  635. Xflag is ignored, and reads are performed from the beginning of the
  636. Xrecord. If the current record is deleted with
  637. X.B riunlink
  638. Xthe position is invalidated. Thus, continuous reads work unless
  639. Xyou read a different record, delete the current one, or read from
  640. Xthe beginning of the same record. Since
  641. X.B rigets
  642. Xis built on 
  643. X.B riread
  644. Xthe same restrictions apply. Performing a 
  645. X.B rigets
  646. Xof a different record from the one you were last
  647. Xreading will reset the current record pointer to the
  648. Xnew record, which may produce some confusion.
  649. XThis implementation is rather
  650. Xodd, but it seems to be fairly useful, and is certainly more useful
  651. Xthan not supporting continuous reads at all.
  652. X.PP
  653. XThe
  654. X.B riunlink
  655. Xfunction marks record
  656. X.B recno
  657. Xas deleted, and adds all of its record blocks to the free list.
  658. X.PP
  659. XThe
  660. X.B rigets
  661. Xfunction reads a newline-terminated string from record 
  662. X.B recno
  663. Xinto 
  664. X.B buf,
  665. Xreplacing the final newline with a null terminator.
  666. X.B Buf
  667. Xis assumed to be large enough to contain the returned data. Some internal
  668. Xbuffering is performed, and sequential calls to
  669. X.B rigets
  670. Xwill return sequential strings from the record, unless the current
  671. Xrecord is reset (see 
  672. X.B riread
  673. Xabove).
  674. XIf there is an error, or the end of a record is reached, 
  675. X.B rigets
  676. Xreturns NULL, otherwise it returns
  677. X.B buf.
  678. X.PP
  679. XThe
  680. X.B riputs
  681. Xfunction acts like its counterpart
  682. X.B puts,
  683. Xby appending the contents of
  684. X.B buf
  685. Xfollowed with a newline to record
  686. X.B recno.
  687. X.B Riputs
  688. Xreturns 0 if successful, or EOF in the event of a failure.
  689. X.PP
  690. XThe 
  691. X.B risetlab
  692. Xand
  693. X.B riputlab
  694. Xroutines allow access to record #0 of the record file (which is otherwise
  695. Xinaccessible). This can be used to store any miscellaneous data that
  696. Xcan fit. If the
  697. X.B size
  698. Xis larger than the size of a "record", the label will not be set,
  699. Xand -1 is returned. Otherwise 
  700. X.B risetlab
  701. Xreturns 0. The function
  702. X.B rigetlab
  703. Xretrieves 
  704. X.B size
  705. Xbytes from the label into
  706. X.B buf,
  707. Xreturning 0 for success, and -1 to indicate failure.
  708. X.PP
  709. X.SH RESTRICTIONS
  710. X.PP
  711. X.SH DIAGNOSTICS
  712. X.PP
  713. X.SH AUTHOR
  714. X.PP
  715. XMarcus J. Ranum, Welch Medical Library.
  716. X.br
  717. X.ti 1i
  718. Xuunet!aplcen!osiris!welchvax!mjr
  719. X.br
  720. X.ti 1i
  721. Xmjr@jhuigf.BITNET
  722. X.SH SEE ALSO
  723. ________This_Is_The_END________
  724. if test `wc -c < recio.3` -ne 7001; then
  725.     echo 'shar: recio.3 was damaged during transit (should have been 7001 bytes)'
  726. fi
  727. fi        ; : end of overwriting check
  728. echo 'x - recio.c'
  729. if test -f recio.c; then echo 'shar: not overwriting recio.c'; else
  730. sed 's/^X//' << '________This_Is_The_END________' > recio.c
  731. X/*
  732. X * Copyright (C) 1988, Marcus J. Ranum, William Welch Medical Library
  733. X * $Author: mjr $
  734. X */
  735. X
  736. X#ifndef lint
  737. Xstatic char *RCSid="$Header: recio.c,v 1.4 88/06/06 13:44:58 mjr Exp $: recio.c";
  738. X#endif
  739. X
  740. X/*
  741. X * $Log:    recio.c,v $
  742. X * Revision 1.4  88/06/06  13:44:58  mjr
  743. X * fixed the drop of occasional chars in rigets()
  744. X * 
  745. X * Revision 1.3  88/06/06  09:58:58  mjr
  746. X * *** empty log message ***
  747. X * 
  748. X * Revision 1.2  88/06/02  15:35:32  mjr
  749. X * added rigetcurpag and risetcurpag
  750. X * 
  751. X * Revision 1.1  88/06/01  21:27:20  mjr
  752. X * Initial revision
  753. X * 
  754. X */
  755. X
  756. X#include    <stdio.h>
  757. X#include    "recio.h"
  758. X
  759. X/* if we wish to store our disk data in network byte order */
  760. X#ifdef    BYTEORDER
  761. X#include    <sys/types.h>
  762. X#include    <netinet/in.h>
  763. X#endif
  764. X
  765. X/* size of a page header (without buffer) */
  766. X#define    RI_PHSIZ    sizeof(struct ripag)
  767. X
  768. X/* size of a page (with buffer) */
  769. X#define    RI_PSIZ(rf)    (sizeof(struct ripag) + (rf)->sblk.reclen)
  770. X
  771. X/* size of a rifd superblock */
  772. X#define    RI_SSIZ        (sizeof(struct risuper))
  773. X
  774. X/* size of a map file entry */
  775. X#define    RI_MSIZ        (sizeof(struct rimap))
  776. X
  777. X/* write the rifd mapfile superblock to disk */
  778. Xstatic int
  779. Xwsuper(rf)
  780. Xstruct    rifd    *rf;
  781. X{
  782. X    extern    long    lseek();
  783. X#ifdef    BYTEORDER
  784. X    struct    risuper boge;
  785. X#endif
  786. X
  787. X
  788. X    if (lseek(rf->mfd, 0L, 0) < 0)
  789. X        return (-1);
  790. X
  791. X#ifdef    BYTEORDER
  792. X    boge.magic = htonl(rf->sblk.magic);
  793. X    boge.reclen = htonl(rf->sblk.reclen);
  794. X    boge.free = htonl(rf->sblk.free);
  795. X    boge.last = htonl(rf->sblk.last);
  796. X
  797. X    if (write(rf->mfd, (char *) &boge, RI_SSIZ) != RI_SSIZ)
  798. X        return (-1);
  799. X#else
  800. X    if (write(rf->mfd, (char *) &rf->sblk, RI_SSIZ) != RI_SSIZ)
  801. X        return (-1);
  802. X#endif
  803. X
  804. X
  805. X    return (0);
  806. X}
  807. X
  808. X
  809. X
  810. X/* read the rifd mapfile superblock from disk */
  811. Xstatic int
  812. Xrsuper(rf)
  813. Xstruct    rifd    *rf;
  814. X{
  815. X    extern    long    lseek();
  816. X#ifdef    BYTEORDER
  817. X    struct     risuper boge;
  818. X#endif
  819. X
  820. X    if (lseek(rf->mfd, 0L, 0) < 0)
  821. X        return (-1);
  822. X
  823. X#ifdef    BYTEORDER
  824. X    if (read(rf->mfd, (char *) &boge, RI_SSIZ) != RI_SSIZ)
  825. X    return (-1);
  826. X
  827. X    rf->sblk.magic = ntohl(boge.magic);
  828. X    rf->sblk.reclen = ntohl(boge.reclen);
  829. X    rf->sblk.free = ntohl(boge.free);
  830. X    rf->sblk.last = ntohl(boge.last);
  831. X#else
  832. X    if (read(rf->mfd, (char *) &rf->sblk, RI_SSIZ) != RI_SSIZ)
  833. X        return (-1);
  834. X#endif
  835. X
  836. X    return (0);
  837. X}
  838. X
  839. X
  840. X
  841. X/* dynamically allocate a control structure for an open rifd */
  842. X/* including opening and checking the mapfile and textfile */
  843. Xstruct rifd    *
  844. Xriopen(path, flags, mode, reclen)
  845. Xchar    *path[2];
  846. Xint    flags;
  847. Xint    mode;
  848. Xint    reclen;
  849. X{
  850. X    struct    rifd    *rf;
  851. X    int    r;
  852. X    extern    char    *malloc();
  853. X
  854. X    /* lets be dynamic, shall we ? */
  855. X#ifndef lint
  856. X    /* this to avoid the possible pointer alignment lint message */
  857. X    if ((rf = (struct rifd *) malloc(sizeof(struct rifd))) == NULL)
  858. X        return (NULL);
  859. X#else
  860. X    rf = (struct rifd *)0;
  861. X#endif
  862. X
  863. X    /* open and check the mapfile - the long part */
  864. X    if ((rf->mfd = open(path[0], flags, mode)) > -1) {
  865. X
  866. X        r = read(rf->mfd, (char *) &rf->sblk, RI_SSIZ);
  867. X
  868. X        /* if read nothing, must be a new guy, right ? */
  869. X        if (r == 0) {
  870. X            rf->sblk.magic = RI_MAGIC;
  871. X            if(reclen == 0)
  872. X                rf->sblk.reclen = BUFSIZ - sizeof(struct rimap);
  873. X            else
  874. X                rf->sblk.reclen = reclen;
  875. X            rf->sblk.free = 0L;
  876. X
  877. X            /* this keeps page 0 as a comment page */
  878. X            rf->sblk.last = 1L;
  879. X
  880. X            if (wsuper(rf) == 0)
  881. X                r = RI_SSIZ;
  882. X        }
  883. X#ifdef    BYTEORDER
  884. X        else {
  885. X            /* read something, decode the numbers */
  886. X            rf->sblk.magic = ntohl(rf->sblk.magic);
  887. X            rf->sblk.reclen = ntohl(rf->sblk.reclen);
  888. X            rf->sblk.free = ntohl(rf->sblk.free);
  889. X            rf->sblk.last = ntohl(rf->sblk.last);
  890. X        }
  891. X#endif
  892. X
  893. X
  894. X        /* cleverly check ret value from either read or write */
  895. X        if (r != RI_SSIZ) {
  896. X            (void) close(rf->mfd);
  897. X            (void) free((char *) rf);
  898. X            return (NULL);
  899. X        }
  900. X
  901. X        /* check that ole magic number */
  902. X        if (rf->sblk.magic != RI_MAGIC) {
  903. X            (void) close(rf->mfd);
  904. X            (void) free((char *) rf);
  905. X            return (NULL);
  906. X        }
  907. X    } else {
  908. X        /* couldnt even open the bloody file */
  909. X        (void) free((char *) rf);
  910. X        return (NULL);
  911. X    }
  912. X
  913. X    /* allocate buffer memory */
  914. X    if((rf->dat = malloc((unsigned)rf->sblk.reclen)) == NULL) {
  915. X        (void) close(rf->mfd);
  916. X        (void) free((char *) rf);
  917. X        return (NULL);
  918. X    }
  919. X
  920. X    /* now open the text file */
  921. X    if ((rf->fd = open(path[1], flags, mode)) < 0) {
  922. X        (void) close(rf->mfd);
  923. X        (void) free((char *) rf->dat);
  924. X        (void) free((char *) rf);
  925. X        return (NULL);
  926. X    }
  927. X    
  928. X    rf->pagoff = 0;
  929. X    rf->curpag = 0L;
  930. X
  931. X    return (rf);
  932. X}
  933. X
  934. X
  935. X
  936. X/* close and deallocate the control structure */
  937. Xriclose(rf)
  938. Xstruct    rifd    *rf;
  939. X{
  940. X    int    t;
  941. X
  942. X    t = wsuper(rf);
  943. X    (void) close(rf->fd);
  944. X    (void) close(rf->mfd);
  945. X    (void) free((char *) rf->dat);
  946. X    (void) free((char *) rf);
  947. X    return (t);
  948. X}
  949. X
  950. X
  951. X
  952. X/* allocate a page block, either by using the free page chain or */
  953. X/* by creating a new page at the end of the file */
  954. Xstatic    long
  955. Xpagalloc(rf,rec)
  956. Xstruct    rifd    *rf;
  957. Xlong    rec;
  958. X{
  959. X    struct    ripag    pag;
  960. X    long    nfree;
  961. X    extern    long    lseek();
  962. X
  963. X
  964. X    /* read superblock in case someone else has changed it */
  965. X    /* this is not totally bulletproof, but doubtless helps */
  966. X    if(rsuper(rf) < 0)
  967. X        return(-1);
  968. X
  969. X    /* if there are free blocks, use them, otherwise use the end of file */
  970. X    if(rf->sblk.free != 0L) {
  971. X        /* allocate the block, and then reset the free pointer */
  972. X        if(rpaghed(rf,rf->sblk.free,&pag) < 0)
  973. X            return(-1);
  974. X
  975. X        /* should never happen ! this block is marked as in */
  976. X        /* use but is on the free list ! */
  977. X        /* (the other alternative is to just eat through the */
  978. X        /* file, using allocated blocks instead of the free */
  979. X        /* list :-)) */
  980. X        if(pag.deleted != RI_DELETED) {
  981. X            /* AIIIEEEEEE!!!! */
  982. X            return(-1);
  983. X        }
  984. X
  985. X        /* remember it */
  986. X        nfree = rf->sblk.free;
  987. X
  988. X        /* the new free pointer is the free block successor */
  989. X        rf->sblk.free = pag.next;
  990. X    } else {
  991. X        /* use page after current highest page in file */
  992. X        /* this is dependent on your OS being UNIX-like */
  993. X        /* in that 'holes' in files are filled with 0s */
  994. X        /* rather than something else - hence we expect */
  995. X        /* that data blocks in a 'hole' will read as all 0 */
  996. X        /* this should blow up MS-DOS */
  997. X        nfree = rf->sblk.last++;
  998. X    }
  999. X    
  1000. X    /* all is OK - rewrite our superblock - new free head */
  1001. X    if(wsuper(rf) < 0)
  1002. X        return(-1);
  1003. X        
  1004. X    /* we now have removed the free entry from the list */
  1005. X    /* and mark it as active */
  1006. X    pag.deleted = RI_ACTIVE;
  1007. X    pag.next = 0L;
  1008. X    pag.recno = rec;
  1009. X    pag.high = 0;
  1010. X    if(wpaghed(rf,nfree,&pag) < 0)
  1011. X        return(-1);
  1012. X
  1013. X    return(nfree);
  1014. X}
  1015. X
  1016. X
  1017. X
  1018. X/* write a map block from the given struct */
  1019. Xstatic    int
  1020. Xwmapblk(rf,rec,blk)
  1021. Xstruct    rifd    *rf;
  1022. Xlong    rec;
  1023. Xstruct    rimap    *blk;
  1024. X{
  1025. X    extern    long    lseek();
  1026. X#ifdef    BYTEORDER
  1027. X    struct    rimap boge;
  1028. X#endif
  1029. X
  1030. X
  1031. X    if(lseek(rf->mfd,(rec * RI_MSIZ) + RI_SSIZ,0) < 0)
  1032. X        return(-1);
  1033. X
  1034. X#ifdef    BYTEORDER
  1035. X    boge.page = htonl(blk->page);
  1036. X    boge.tail = htonl(blk->tail);
  1037. X
  1038. X    if (write(rf->mfd, (char *) &boge, RI_MSIZ) != RI_MSIZ)
  1039. X        return (-1);
  1040. X#else
  1041. X    if(write(rf->mfd,(char *)blk, RI_MSIZ) != RI_MSIZ)
  1042. X        return(-1);
  1043. X#endif
  1044. X    return(0);
  1045. X}
  1046. X
  1047. X
  1048. X
  1049. X/* read a map block into the given struct */
  1050. Xstatic    int
  1051. Xrmapblk(rf,rec,blk)
  1052. Xstruct    rifd    *rf;
  1053. Xlong    rec;
  1054. Xstruct    rimap    *blk;
  1055. X{
  1056. X    int    ret;
  1057. X    extern    long    lseek();
  1058. X#ifdef    BYTEORDER
  1059. X    struct    rimap    boge;
  1060. X#endif
  1061. X
  1062. X    if(lseek(rf->mfd,(rec * RI_MSIZ) + RI_SSIZ,0) <0)
  1063. X        return(-1);
  1064. X
  1065. X#ifdef    BYTEORDER
  1066. X    ret = read(rf->mfd,(char *)&boge, RI_MSIZ);
  1067. X    blk->page = ntohl(boge.page);
  1068. X    blk->tail = ntohl(boge.tail);
  1069. X#else
  1070. X    ret = read(rf->mfd,(char *)blk, RI_MSIZ);
  1071. X#endif
  1072. X
  1073. X    /* if we EOFfed we are still (maybe) OK */
  1074. X    if(ret == 0) {
  1075. X        blk->page = 0L;
  1076. X        blk->tail = 0L;
  1077. X        ret = RI_MSIZ;    /* kluge */
  1078. X    }
  1079. X
  1080. X    if(ret != RI_MSIZ)
  1081. X        return(-1);
  1082. X
  1083. X    return(0);
  1084. X}
  1085. X
  1086. X
  1087. X
  1088. X/* read a page header into the given struct */
  1089. Xstatic    int
  1090. Xrpaghed(rf,rec,blk)
  1091. Xstruct    rifd    *rf;
  1092. Xlong    rec;
  1093. Xstruct    ripag    *blk;
  1094. X{
  1095. X    int    r;
  1096. X    extern    long    lseek();
  1097. X#ifdef    BYTEORDER
  1098. X    struct    ripag    boge;
  1099. X#endif
  1100. X
  1101. X    /* seek the distance, and read a page header */
  1102. X    if(lseek(rf->fd,(rec * RI_PSIZ(rf)),0) < 0)
  1103. X        return(-1);
  1104. X
  1105. X#ifdef    BYTEORDER
  1106. X    r = read(rf->fd,(char *)&boge, RI_PHSIZ);
  1107. X    blk->recno = ntohl(boge.recno);
  1108. X    blk->next = ntohl(boge.next);
  1109. X    blk->high = ntohl(boge.high);
  1110. X    blk->deleted = ntohl(boge.deleted);
  1111. X#else
  1112. X    /* try to read a page */
  1113. X    r = read(rf->fd,(char *)blk, RI_PHSIZ);
  1114. X#endif
  1115. X
  1116. X    /* if we EOFfed, we are still (maybe) OK */
  1117. X    if(r == 0) {
  1118. X        blk->recno = rec;
  1119. X        blk->next = 0L;
  1120. X        blk->high = 0;
  1121. X        blk->deleted = RI_DELETED;
  1122. X        r = RI_PHSIZ;    /* kluge */
  1123. X    }
  1124. X
  1125. X    if(r != RI_PHSIZ)
  1126. X        return(-1);
  1127. X
  1128. X    return(0);
  1129. X}
  1130. X
  1131. X
  1132. X
  1133. X/* write a page header from the given struct */
  1134. Xstatic    int
  1135. Xwpaghed(rf,rec,blk)
  1136. Xstruct    rifd    *rf;
  1137. Xlong    rec;
  1138. Xstruct    ripag    *blk;
  1139. X{
  1140. X    extern    long    lseek();
  1141. X#ifdef    BYTEORDER
  1142. X    struct    ripag    boge;
  1143. X#endif
  1144. X
  1145. X    if(lseek(rf->fd,(rec * RI_PSIZ(rf)),0) < 0)
  1146. X        return(-1);
  1147. X#ifdef    BYTEORDER
  1148. X    boge.recno = htonl(blk->recno);
  1149. X    boge.next = htonl(blk->next);
  1150. X    boge.high = htonl(blk->high);
  1151. X    boge.deleted = htonl(blk->deleted);
  1152. X    if(write(rf->fd,(char *)&boge, RI_PHSIZ) != RI_PHSIZ)
  1153. X        return(-1);
  1154. X#else
  1155. X    if(write(rf->fd,(char *)blk, RI_PHSIZ) != RI_PHSIZ)
  1156. X        return(-1);
  1157. X#endif
  1158. X    return(0);
  1159. X}
  1160. X
  1161. X
  1162. X
  1163. Xriwrite(rf,rec,buf,num,appen)
  1164. Xstruct    rifd    *rf;
  1165. Xlong    rec;
  1166. Xchar    *buf;
  1167. Xint    num;
  1168. Xint    appen;
  1169. X{
  1170. X    long    j;        /* junk */
  1171. X    int    k;        /* junk */
  1172. X    int    wrote =0;    /* number of char written */
  1173. X    long    this =0L;    /* current page */
  1174. X    struct    rimap    map;    /* buffer for map entries */
  1175. X    struct    ripag    pag;    /* buffer for page entries */
  1176. X    extern    long    lseek();
  1177. X
  1178. X    /* no matter what, we will need our map block */
  1179. X    if(rmapblk(rf,rec,&map) < 0)
  1180. X        return(-1);
  1181. X
  1182. X    /* turn off read continuation for this record */
  1183. X    rf->curpag = -1L;
  1184. X
  1185. X    /* if no page at start, write map to disk now - new page */
  1186. X    if(map.page == 0L) {
  1187. X        map.page = pagalloc(rf,rec);
  1188. X        if(map.page == -1L)
  1189. X            return(-1);
  1190. X        if(wmapblk(rf,rec,&map) < 0)
  1191. X            return(-1);
  1192. X    }
  1193. X
  1194. X
  1195. X    /* if we are appending, we start at the last page and continue */
  1196. X    if(appen) {
  1197. X        if(map.tail != 0)
  1198. X            this = map.tail;
  1199. X        else
  1200. X            this = map.page;
  1201. X    } else {
  1202. X        /* start at the first page */
  1203. X        this = map.page;
  1204. X    }
  1205. X
  1206. X
  1207. X    /* main loop, in which we spit the bytes to disk */
  1208. X    while(num > 0 ) {
  1209. X        
  1210. X        /* read our page header */
  1211. X        if(rpaghed(rf,this,&pag) < 0)
  1212. X            return(-1);
  1213. X
  1214. X        /* seek to head of page data segment possibly */
  1215. X        /* skipping over previously written bytes */
  1216. X        if(appen)
  1217. X            j = (this * (long)RI_PSIZ(rf))+RI_PHSIZ+pag.high;
  1218. X        else
  1219. X            j = (this * (long)RI_PSIZ(rf))+RI_PHSIZ;
  1220. X
  1221. X        /* actually do the thing */
  1222. X        if(lseek(rf->fd,j,0) <0)
  1223. X            return(-1);
  1224. X
  1225. X        /* figure how much to write */
  1226. X        /* is this devo ?? - my head hurtz */
  1227. X        if(appen) {
  1228. X            if(num > rf->sblk.reclen - pag.high)
  1229. X                k = rf->sblk.reclen - pag.high;
  1230. X            else
  1231. X                k = num;
  1232. X        } else {
  1233. X            if(num > rf->sblk.reclen)
  1234. X                k = rf->sblk.reclen;
  1235. X            else
  1236. X                k = num;
  1237. X        }
  1238. X
  1239. X        /* actually do the thing */
  1240. X        if(write(rf->fd,&buf[wrote],k) != k)
  1241. X            return(-1);
  1242. X
  1243. X        /* adjust our notion of where we are and so on */
  1244. X        wrote += k;
  1245. X        num -= k;
  1246. X
  1247. X        if(appen) {
  1248. X            pag.high += k;
  1249. X        } else {
  1250. X            /* this prevents us from accidentally losing the */
  1251. X            /* rest of the page in overwrites */
  1252. X            if( k > pag.high)
  1253. X                pag.high = k;
  1254. X        }
  1255. X
  1256. X        /* remember our new last page in chain is this one */
  1257. X        map.tail = this;
  1258. X
  1259. X        if( num > 0 ) {
  1260. X            /* the current block has no associated page */
  1261. X            if(pag.next == 0L) {
  1262. X                pag.next = pagalloc(rf,rec);
  1263. X                if(pag.next == -1L)
  1264. X                    return(-1);
  1265. X            }
  1266. X        
  1267. X            /* write our page header with next pointer */
  1268. X            if(wpaghed(rf,this,&pag) < 0)
  1269. X                return(-1);
  1270. X    
  1271. X            /* move along to next page */
  1272. X            this = pag.next;
  1273. X        }
  1274. X    }
  1275. X
  1276. X    /* write our page header */
  1277. X    if(wpaghed(rf,this,&pag) < 0)
  1278. X        return(-1);
  1279. X
  1280. X    /* write our map block */
  1281. X    if(wmapblk(rf,rec,&map) < 0)
  1282. X        return(-1);
  1283. X
  1284. X    return(wrote);
  1285. X}
  1286. X
  1287. X
  1288. X
  1289. X/* drop a list of pages, and pop them onto the free list */
  1290. Xriunlink(rf,rec)
  1291. Xstruct    rifd    *rf;
  1292. Xlong    rec;
  1293. X{
  1294. X    long    head =0L;    /* first page - we build a chain */
  1295. X    long    this =0L;    /* current page */
  1296. X    struct    rimap    map;    /* buffer for map entries */
  1297. X    struct    ripag    pag;    /* buffer for page entries */
  1298. X    extern    long    lseek();
  1299. X
  1300. X    /* read superblock in case someone else has changed it */
  1301. X    if(rsuper(rf) < 0)
  1302. X        return(-1);
  1303. X    
  1304. X    /* turn off read continuation if this record */
  1305. X    if(rec == rf->currec)
  1306. X        rf->curpag = -1L;
  1307. X
  1308. X    /* now read the mapblock to be deleted */
  1309. X    if(rmapblk(rf,rec,&map) < 0)
  1310. X        return(-1);
  1311. X
  1312. X    /* the map block has no associated page block - life is easy */
  1313. X    if(map.page == 0L)
  1314. X        return(0);
  1315. X
  1316. X    /* remember our page */
  1317. X    this = map.page;
  1318. X    head = map.page;
  1319. X
  1320. X    map.page = 0L;
  1321. X    map.tail = 0L;
  1322. X
  1323. X    /* first off, mark the thing as gone */
  1324. X    if(wmapblk(rf,rec,&map) < 0)
  1325. X        return(-1);
  1326. X    
  1327. X    while(1) {
  1328. X        /* read our page header */
  1329. X        if(rpaghed(rf,this,&pag) < 0)
  1330. X            return(-1);
  1331. X
  1332. X        /* if no next page, we are mostly done */
  1333. X        /* drop to bottom, which links us into the free chain */
  1334. X        if(pag.next == 0L)
  1335. X            break;
  1336. X
  1337. X        /* mark it and go to next */
  1338. X        pag.deleted = RI_DELETED;
  1339. X        if(wpaghed(rf,this,&pag) < 0)
  1340. X            return(-1);
  1341. X
  1342. X        this = pag.next;
  1343. X    }
  1344. X
  1345. X    /* this now points at the end of our list */
  1346. X    /* head points at the first one. so we: */
  1347. X
  1348. X    /* make the superblock next free block pointer the next of our */
  1349. X    /* last node - if we crash here we lose our free list - they just */
  1350. X    /* sit there */
  1351. X    pag.next = rf->sblk.free;
  1352. X
  1353. X    pag.deleted = RI_DELETED;
  1354. X    if(wpaghed(rf,this,&pag) < 0)
  1355. X        return(-1);
  1356. X
  1357. X    /* now the superblock free list points to our list head */
  1358. X    rf->sblk.free = head;
  1359. X    if(wsuper(rf) < 0)
  1360. X        return(-1);
  1361. X
  1362. X    return(0);
  1363. X}
  1364. X
  1365. Xriread(rf,rec,buf,num,cont)
  1366. Xstruct    rifd    *rf;
  1367. Xlong    rec;
  1368. Xchar    *buf;
  1369. Xint    num;
  1370. Xint    cont;
  1371. X{
  1372. X    long    j;        /* junk */
  1373. X    int    k;        /* junk */
  1374. X    long    this;
  1375. X    int    nread =0;    /* number of char read */
  1376. X    struct    rimap    map;    /* buffer for map entries */
  1377. X    struct    ripag    pag;    /* buffer for page entries */
  1378. X    extern    long    lseek();
  1379. X
  1380. X    /* these check to make sure our current record and such are */
  1381. X    /* all still more or less valid - a kludge, but it works... */
  1382. X    if(rec != rf->currec) {
  1383. X        cont = 0;
  1384. X        rf->currec = rec;
  1385. X    }
  1386. X
  1387. X    if(cont) {
  1388. X        if(rf->curpag != -1L)
  1389. X            this = rf->curpag;
  1390. X        else
  1391. X            cont = 0;
  1392. X    }
  1393. X
  1394. X    if(!cont) {
  1395. X        /* we are starting a new record - read the map block */
  1396. X        if(rmapblk(rf,rec,&map) < 0)
  1397. X            return(-1);
  1398. X
  1399. X        this = map.page;
  1400. X        rf->curpag = 0L;
  1401. X        rf->pagoff = 0;
  1402. X    }
  1403. X    
  1404. X    while(num > 0 ) {
  1405. X
  1406. X        /* we have run out of pages to read */
  1407. X        if(this == 0L)
  1408. X            break;
  1409. X
  1410. X        /* read our page header */
  1411. X        if(rpaghed(rf,this,&pag) < 0)
  1412. X            return(-1);
  1413. X
  1414. X        /* seek to head of page data segment */
  1415. X        if(cont)
  1416. X            j = (this * (long)RI_PSIZ(rf))+RI_PHSIZ + rf->pagoff;
  1417. X        else
  1418. X            j = (this * (long)RI_PSIZ(rf))+RI_PHSIZ;
  1419. X
  1420. X        if(lseek(rf->fd,j,0) <0)
  1421. X            return(-1);
  1422. X
  1423. X        /* read a page worth OR whatever is left in that page */
  1424. X        if(cont) {
  1425. X            if(num >= (pag.high - rf->pagoff)) {
  1426. X                /* read rest of page, go to next */
  1427. X                k = pag.high - rf->pagoff;
  1428. X                this = pag.next;
  1429. X                rf->curpag = this;
  1430. X            } else {
  1431. X                k = num;
  1432. X            }
  1433. X        } else {
  1434. X            if(num < pag.high) {
  1435. X                k = num;
  1436. X            } else {
  1437. X                this = pag.next;
  1438. X                rf->curpag = this;
  1439. X                k = pag.high;
  1440. X            }
  1441. X        }
  1442. X
  1443. X        if(read(rf->fd,&buf[nread],k) < 0)
  1444. X            return(-1);        
  1445. X
  1446. X        /* adjust our notion of where we are */
  1447. X        nread += k;
  1448. X        num -= k;
  1449. X        rf->pagoff += k;
  1450. X        if(rf->pagoff >= rf->sblk.reclen) {
  1451. X            rf->pagoff -= rf->sblk.reclen;
  1452. X        } 
  1453. X    }
  1454. X
  1455. X    rf->curpag = this;
  1456. X    buf[nread] ='\0';
  1457. X
  1458. X    return(nread);
  1459. X}
  1460. X
  1461. X/* set the record file label (page 0) from the contents of buf */
  1462. Xrisetlab(rf,buf,num)
  1463. Xstruct    rifd    *rf;
  1464. Xchar    *buf;
  1465. Xint    num;
  1466. X{
  1467. X    extern    long    lseek();
  1468. X
  1469. X    /* will it fit ? */
  1470. X    if(num > rf->sblk.reclen)
  1471. X        return(-1);
  1472. X
  1473. X    if(lseek(rf->fd,(long)RI_PHSIZ,0) <0)
  1474. X        return(-1);
  1475. X    if(write(rf->fd,buf,num) != num)
  1476. X        return(-1);
  1477. X
  1478. X    return(0);
  1479. X}
  1480. X
  1481. X
  1482. X/* get the record file label (page 0) into buf */
  1483. Xrigetlab(rf,buf,num)
  1484. Xstruct    rifd    *rf;
  1485. Xchar    *buf;
  1486. Xint    num;
  1487. X{
  1488. X    extern    long    lseek();
  1489. X
  1490. X    if(lseek(rf->fd,(long)RI_PHSIZ,0) <0)
  1491. X        return(-1);
  1492. X
  1493. X    if(read(rf->fd,buf,num) < 0)
  1494. X        return(-1);
  1495. X
  1496. X    buf[rf->sblk.reclen] = '\0';
  1497. X
  1498. X    return(0);
  1499. X}
  1500. X
  1501. Xchar    *
  1502. Xrigets(rf,rec,buf)
  1503. Xstruct    rifd    *rf;
  1504. Xlong    rec;
  1505. Xchar    *buf;
  1506. X{
  1507. X    char    *bptr = buf;
  1508. X    static    int    cont;
  1509. X    static    char    *rptr = NULL;
  1510. X
  1511. X    /* this is kind of wasteful, but necessary */
  1512. X    /* we re-check to make sure that the record has not changed */
  1513. X    /* in riread() - but have to do it here, too, to make sure */
  1514. X    /* that we can take from our buffer, instead of reading */
  1515. X    cont = rec == rf->currec;
  1516. X    
  1517. X    /* if the record number has changed, or the buffer is empty */
  1518. X    /* we must needs fill us a buffer */
  1519. X    if(!cont || rptr == 0 || *rptr == '\0') {
  1520. X        if(riread(rf,rec,rf->dat,rf->sblk.reclen,1) == 0)
  1521. X            return(NULL);
  1522. X        rptr = rf->dat;
  1523. X    }
  1524. X
  1525. X    while(1) {
  1526. X        switch(*rptr) {
  1527. X
  1528. X        case '\0':
  1529. X                /* out of stuff, load another buffer */
  1530. X                if(riread(rf,rec,rf->dat,rf->sblk.reclen,1) == 0) {
  1531. X                    /* record empty, finish buffer */
  1532. X                    *bptr = '\0';
  1533. X                    return(buf);
  1534. X                }
  1535. X                rptr = rf->dat;
  1536. X                *bptr++ = *rptr;
  1537. X                break;
  1538. X
  1539. X            case '\n':
  1540. X                *bptr = '\0';
  1541. X                rptr++;
  1542. X                return(buf);
  1543. X        
  1544. X            default:
  1545. X                *bptr++ = *rptr;
  1546. X
  1547. X        }
  1548. X        rptr++;
  1549. X    }
  1550. X}
  1551. X
  1552. X
  1553. X
  1554. Xriputs(rf,rec,buf)
  1555. Xstruct    rifd    *rf;
  1556. Xlong    rec;
  1557. Xchar    *buf;
  1558. X{
  1559. X    char    wbuf[BUFSIZ];
  1560. X    char    *bptr = wbuf;
  1561. X    char    *rptr = buf;
  1562. X    int    count =0;
  1563. X    
  1564. X    /* combined strcpy() and strlen() */
  1565. X    while(rptr && *rptr) {
  1566. X        *bptr++ = *rptr++;
  1567. X        count++;
  1568. X    }
  1569. X    *bptr++ = '\n';
  1570. X    count++;
  1571. X
  1572. X    *bptr = '\0';
  1573. X    if(riwrite(rf,rec,wbuf,count,1) != count)
  1574. X        return(EOF);
  1575. X    
  1576. X    return(0);
  1577. X}
  1578. X
  1579. X
  1580. X
  1581. Xrigetcurpag(rf,buf)
  1582. Xstruct    rifd    *rf;
  1583. Xchar    *buf;
  1584. X{
  1585. X    if(rf->curpag <= 0L)
  1586. X        return(-1);
  1587. X    if(lseek(rf->fd,(rf->curpag * (long)RI_PSIZ(rf))+RI_PHSIZ,0) < 0)
  1588. X        return(-1);
  1589. X    if(read(rf->fd,buf,rf->sblk.reclen) != rf->sblk.reclen)
  1590. X        return(-1);
  1591. X    return(0);
  1592. X}
  1593. X
  1594. X
  1595. X
  1596. Xrisetcurpag(rf,buf)
  1597. Xstruct    rifd    *rf;
  1598. Xchar    *buf;
  1599. X{
  1600. X    if(rf->curpag <= 0L)
  1601. X        return(-1);
  1602. X    if(lseek(rf->fd,(rf->curpag * (long)RI_PSIZ(rf))+RI_PHSIZ,0) < 0)
  1603. X        return(-1);
  1604. X    if(write(rf->fd,buf,rf->sblk.reclen) != rf->sblk.reclen)
  1605. X        return(-1);
  1606. X    return(0);
  1607. X}
  1608. ________This_Is_The_END________
  1609. if test `wc -c < recio.c` -ne 17221; then
  1610.     echo 'shar: recio.c was damaged during transit (should have been 17221 bytes)'
  1611. fi
  1612. fi        ; : end of overwriting check
  1613. echo 'x - recio.h'
  1614. if test -f recio.h; then echo 'shar: not overwriting recio.h'; else
  1615. sed 's/^X//' << '________This_Is_The_END________' > recio.h
  1616. X/*
  1617. X * Copyright (C) 1988, Marcus J. Ranum, William Welch Medical Library
  1618. X * $Author: mjr $
  1619. X */
  1620. X
  1621. X/*
  1622. X * $Header: recio.h,v 1.1 88/06/01 21:28:06 mjr rel $: recio.h
  1623. X *
  1624. X * $Log:    recio.h,v $
  1625. X * Revision 1.1  88/06/01  21:28:06  mjr
  1626. X * Initial revision
  1627. X * 
  1628. X */
  1629. X
  1630. X#ifndef    _INCL_RECIO_H
  1631. X
  1632. X
  1633. X/* this is actually highly dependent on a few major assumptions: */
  1634. X/* 1) you can lseek() past EOF and extend with 'holes' */
  1635. X/* (which fails under MSDOS, I think, but who cares about DOS) */
  1636. X/* 2) when you read data from a 'hole' in a file, it will */
  1637. X/* come back zeros - hence we can check the flags to */
  1638. X/* see if it is free based on that. If your system does */
  1639. X/* not work in this way, you're out of luck, or you have */
  1640. X/* to construct large blank databases beforehand */
  1641. X/* this indicates a node deleted */
  1642. X#define    RI_DELETED    0
  1643. X#define    RI_ACTIVE    -1L
  1644. X
  1645. X/* as a result of using 0L as an indicator of being a free block or a */
  1646. X/* null block, we have a left-over page at page #0. This can be used to */
  1647. X/* store invariant information */
  1648. X
  1649. X/* our magic number - just to be safe */
  1650. X#define    RI_MAGIC    0x72252
  1651. X
  1652. X/* record file superblock (one at head of map file) */
  1653. Xstruct    risuper    {
  1654. X    long    magic;        /* magic number */
  1655. X    int    reclen;        /* record chunk length (variable) */
  1656. X    long    free;        /* head of free chain */
  1657. X    long    last;        /* last page in file (alternate free list) */
  1658. X};
  1659. X
  1660. X
  1661. X/* an individual record header - one per record in map file */
  1662. X/* the map file consists of nothing but the superblock and one */
  1663. X/* of these critters per record */
  1664. Xstruct    rimap    {
  1665. X    long    page;        /* assigned page if any, else 0L for free */
  1666. X    long    tail;        /* tail of assigned page list */
  1667. X};
  1668. X
  1669. X
  1670. X/* a page header - one at the head of each page in page file. */
  1671. X/* for now, quite rudimentary - room for more data if needed */
  1672. X/* otherwise it would not be worth defining a structure */
  1673. X/* - note - the use of longs here is a bit unecessary, but this */
  1674. X/* way its 4 longs, and there are no alignment problems between */
  1675. X/* my Sun and my VAX. Its a pain - feel free to fix it */
  1676. Xstruct    ripag    {
  1677. X    long    recno;        /* extra to help reconstruct crashes */
  1678. X    long    next;        /* next page pointer 0L = no next */
  1679. X    long    deleted;    /* 0 is free, anything else is not */
  1680. X    long    high;        /* this page highwater mark (EOF) */
  1681. X};
  1682. X
  1683. X
  1684. X/* the actual control structure. Includes a buffer for reading pages */
  1685. X/* and a few other handy buffers for map entries, etc */
  1686. Xstruct    rifd    {
  1687. X    int    fd;        /* record file descriptor */
  1688. X    int    mfd;        /* free map file descriptor */
  1689. X    struct    risuper    sblk;    /* superblock */
  1690. X                /* all used to emulate stdio, sort of */
  1691. X    char    *dat;        /* page record buffer (malloced in riopen()) */
  1692. X    long    curpag;        /* used to simulate consecutive reads */
  1693. X    long    currec;        /* used to simulate consecutive reads */
  1694. X    int    pagoff;        /* offset within current page */
  1695. X};
  1696. X#define    RIFD    struct    rifd
  1697. X
  1698. Xextern    struct    rifd    *riopen();
  1699. Xextern    long    riseek();
  1700. Xextern    char    *rigets();
  1701. X
  1702. X#define    _INCL_RECIO_H
  1703. X#endif
  1704. ________This_Is_The_END________
  1705. if test `wc -c < recio.h` -ne 2905; then
  1706.     echo 'shar: recio.h was damaged during transit (should have been 2905 bytes)'
  1707. fi
  1708. fi        ; : end of overwriting check
  1709. echo 'x - sizes.c'
  1710. if test -f sizes.c; then echo 'shar: not overwriting sizes.c'; else
  1711. sed 's/^X//' << '________This_Is_The_END________' > sizes.c
  1712. X/*
  1713. X * Copyright (C) 1988, Marcus J. Ranum, William Welch Medical Library
  1714. X * $Author: mjr $
  1715. X */
  1716. X
  1717. X#ifndef lint
  1718. Xstatic char *RCSid="$Header: sizes.c,v 1.1 88/06/01 21:27:31 mjr Rel $: sizes.c";
  1719. X#endif
  1720. X
  1721. X/*
  1722. X * $Log:    sizes.c,v $
  1723. X * Revision 1.1  88/06/01  21:27:31  mjr
  1724. X * Initial revision
  1725. X * 
  1726. X */
  1727. X
  1728. X/* provides some minimally useful info about how big your */
  1729. X/* data structures are */
  1730. X
  1731. X#include "recio.h"
  1732. X
  1733. Xmain()
  1734. X{
  1735. X    (void)printf("a record I/O control structure is %d bytes\n",sizeof(RIFD));
  1736. X    (void)printf("(that is without the dynamically allocated page buffer)\n");
  1737. X    (void)printf("\na map block is %d bytes\n",sizeof(struct rimap));
  1738. X    (void)printf("\na page header is %d bytes\n",sizeof(struct ripag));
  1739. X    (void)printf("make sure these sizes match, if you're running on\n");
  1740. X    (void)printf("several different types of CPUs.\n");
  1741. X}
  1742. ________This_Is_The_END________
  1743. if test `wc -c < sizes.c` -ne 823; then
  1744.     echo 'shar: sizes.c was damaged during transit (should have been 823 bytes)'
  1745. fi
  1746. fi        ; : end of overwriting check
  1747. exit 0
  1748.