home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume13 / rf < prev    next >
Text File  |  1988-01-31  |  17KB  |  680 lines

  1. Subject:  v13i044:  Rolodex-like filing system
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Larry Lippman <kitty!larry@UUNET.UU.NET>
  7. Posting-number: Volume 13, Issue 44
  8. Archive-name: rf
  9.  
  10.     The enclosed program is called rf(1L).  It is a simple database
  11. program written in C which stores names, addresses, telephone numbers,
  12. and other data.  It functions not unlike a "rotary file" for fast access,
  13. which is why it is called ``rf''.
  14.     This program has been tested on several different System V ports
  15. with no problems.  Some BSD ports may require some minor curses changes,
  16. but since I am not a BSD-person, I can't be specific.  There should be no
  17. other processor/port dependencies beyond curses implementation.
  18.  
  19. <>  Larry Lippman @ Recognition Research Corp., Clarence, New York
  20. <>  UUCP:  {allegra|ames|boulder|decvax|rutgers|watmath}!sunybcs!kitty!larry
  21. <>  VOICE: 716/688-1231        {hplabs|ihnp4|mtune|utzoo|uunet}!/
  22. <>  FAX:   716/741-9635 {G1,G2,G3 modes}   "Have you hugged your cat today?" 
  23.  
  24. # This is a shell archive.  Remove anything before this line, then
  25. # unpack it by saving it in a file and typing "sh file".  (Files
  26. # unpacked will be owned by you and have default permissions.)
  27. #
  28. # This archive contains:
  29. # Makefile README rf.1 rf.c
  30.  
  31. echo x - Makefile
  32. sed -e 's/^X//' > "Makefile" << '//E*O*F Makefile//'
  33. X# Makefile for rf(1L)
  34. X# Last revision 3 Jun 1985
  35. X#
  36. X# define SYSDATA if system file other than /usr/local/lib/rf_data
  37. X#
  38. XSRC = rf.c
  39. XLIBS = -lcurses
  40. XCFLAGS = -O -s
  41. XDESTDIR = /usr/bin/
  42. X
  43. Xrf:    $(SRC)
  44. X    cc $(CFLAGS) $(SRC) -o rf $(LIBS)
  45. X
  46. Xinstall:
  47. X    chmod 555 rf
  48. X    chgrp bin rf
  49. X    chown bin rf
  50. X    mv rf $(DESTDIR)
  51. X    
  52. Xlint:
  53. X    lint rf.c
  54. //E*O*F Makefile//
  55.  
  56. echo x - README
  57. sed -e 's/^X//' > "README" << '//E*O*F README//'
  58. X    The enclosed program is called rf(1L).  It is a simple database
  59. Xprogram written in C which stores names, addresses, telephone numbers,
  60. Xand other data.  It functions not unlike a "rotary file" for fast access,
  61. Xwhich is why it is called ``rf''.
  62. X    In its present form it will search for a record by individual
  63. Xname, or by organization name.  Any size search string may be used as
  64. Xthe key; command line parsing is intelligent enough such that quotes are
  65. Xunnecessary if the search string contains embedded whitespace.  The output
  66. Xis displayed in a neat page-oriented fashion using curses(3X), with a paging
  67. Xcontrol where multiple matches are encountered.
  68. X    The database file is easily configured using any editor.  The
  69. Xdatabase file format is also designed so that it may be easily accessed by
  70. Xawk or sed for mailing list or other special applications.  By setting an
  71. Xoption flag, the program will access a system-wide database, or a private
  72. Xdatabase file in the user's home directory.
  73. X    While the program could have been written using awk and tput, it
  74. Xis substantially faster using C.  In keeping with the recent discussion
  75. Xabout writing "new" UNIX functions, the increased speed is THE reason
  76. Xfor writing it in C.  Typical search and display (9,600 baud) time on
  77. Xa 3B2 for one record from a 30 kilobyte database file is < 2.0 seconds;
  78. Xthis includes curses(3X) overhead - so it's pretty fast (the entire database
  79. Xfile is always searched to detect multiple matches).
  80. X    The program is reasonably well commented, is intentionally written
  81. Xto be easily modified, and is reasonably well protected against users doing
  82. X"dumb" things.  The program runs on three different Sys V versions, and
  83. Xshould probably run under BSD since it contains its own string search
  84. Xfunction and does not use getopt; the curses(3X) use is not particularly
  85. Xexotic.
  86. X    The actual fields and field lengths were chosen to provide a
  87. Xprogram that fit the needs of my organization - an industrial R&D laboratory
  88. Xwhich communicates a GREAT deal with various other organizations.
  89. X    The program is intentionally written so that the field definitions
  90. Xand their lengths can be easily modified for a particular organization.
  91. XFor example, our organization often sends telex and facsimile machine
  92. Xmessages, but many organizations NEVER send such messages - so these
  93. Xfields could be removed, allowing character expansion of the telephone
  94. Xnumber and uucp address fields.
  95. X    Some people may not like my choice of video attributes for the
  96. Xpage display; obviously, this is easy to change.
  97. X    The program fully passes lint, except for some silliness about
  98. Xunused curses(3X) functions.
  99. X    If you are willing to accept my file name definitions and
  100. Xlocations, all you have to do is type ``make''...
  101. X
  102. X<>  Larry Lippman @ Recognition Research Corp., Clarence, New York
  103. X<>  UUCP:  {allegra|ames|boulder|decvax|rutgers|watmath}!sunybcs!kitty!larry
  104. X<>  VOICE: 716/688-1231        {hplabs|ihnp4|mtune|utzoo|uunet}!/
  105. X<>  FAX:   716/741-9635 {G1,G2,G3 modes}   "Have you hugged your cat today?" 
  106. //E*O*F README//
  107.  
  108. echo x - rf.1
  109. sed -e 's/^X//' > "rf.1" << '//E*O*F rf.1//'
  110. X.TH RF 1 Local
  111. X.UC 4
  112. X.SH NAME
  113. Xrf \- "rotary file" database for names, addresses, etc.
  114. X.SH SYNOPSIS
  115. X.B rf
  116. X[
  117. X.B \-f
  118. X] [
  119. X.B \-l
  120. X] [
  121. X.B \-o
  122. X] [
  123. X.B search string
  124. X]
  125. X.SH DESCRIPTION
  126. X.B Rf
  127. Xis a simple "rotary file" database which stores names, addresses,
  128. Xtelephone numbers, comments, etc. for rapid retrieval in a formatted
  129. Xpage fashion.
  130. X.B Rf
  131. Xsearches its database file using a search string keyed to a
  132. X.I person's
  133. X.B name
  134. Xor
  135. X.I person's
  136. X.B organization.
  137. XMultiple matches are paginated using a single key command.
  138. X.PP
  139. XThe
  140. X.B \-f
  141. Xflag selects a private database file installed as
  142. X.B .rf_data
  143. Xin the user's home directory.  Invoking
  144. X.B rf
  145. Xwithout this flag selects the database file
  146. X.B /usr/local/lib/rf_data
  147. Xavailable to all users.
  148. X.PP
  149. XThe
  150. X.B \-l
  151. Xflag lists only the
  152. X.B name
  153. Xor
  154. X.B organization
  155. Xfield matches without displaying the rest of the record,
  156. Xand is used for rapid
  157. Xscanning of the database file where multiple matches may occur.
  158. X.PP
  159. XThe
  160. X.B \-o
  161. Xflag searches for a match in the
  162. X.B organization
  163. Xfield, rather than the
  164. X.B name
  165. Xfield.
  166. X.PP
  167. X[
  168. X.B search string
  169. X] may be any string of 1 to 72 characters in length; the string may
  170. Xcontain one or more instances of whitespace without having the
  171. Xstring enclosed in quotes.  There is no upper <--> lower case
  172. Xconversion; the case presented is matched as is, and may be mixed.
  173. XPunctuation and whitespace
  174. Xembedded in the string is also matched;
  175. Xeach occurrence of whitespace must be limited to a length of
  176. Xone space.
  177. X.SH DATABASE FILE FORMAT
  178. XEach record consists of a minimum of two fields,
  179. Xwith all fields containing a two\-character identifier
  180. Xin the form of a letter followed by a colon.
  181. XThe data portion of the field may contain whitespace or any
  182. Xpunctuation to a maximum character length as described below.
  183. XEach record must begin with a
  184. X.B name
  185. Xfield; if there is an
  186. X.B organization
  187. Xfield, it must immediately follow the
  188. X.B name
  189. Xfield.
  190. XIf the record pertains to an
  191. X.B organization
  192. Xonly having no
  193. X.I person's
  194. X.B name
  195. Xentry, the
  196. X.B name
  197. Xfield identifier is still necessary,
  198. Xwith the rest of the field blank.
  199. XAll other fields are optional and may be included in any order.
  200. XRecords are separated by one blank line.
  201. X.PP
  202. XEach field is limited to one entry per record,
  203. Xexcept that
  204. X.B telephone,
  205. X.B telex,
  206. X.B fax
  207. Xand
  208. X.B uucp
  209. Xmay each have a maximum of two entries,
  210. Xfor line-order display as presented within the record;
  211. Xa maximum of four
  212. X.B comment
  213. Xentries is also permitted within the same record.
  214. X.PP
  215. X.nf
  216. X\fBN:name\fR                30 chars max.
  217. X\fBO:organization\fR            72 chars max.
  218. X\fBT:title\fR                24 chars max.
  219. X\fBD:department\fR            24 chars max.
  220. X\fBA:address\fR                72 chars max.
  221. X\fBP:telephone\fR            15 chars max.
  222. X\fBF:fax\fR                15 chars max.
  223. X\fBX:telex\fR                24 chars max.
  224. X\fBU:uucp\fR                24 chars max.
  225. X\fBH:home_telephone\fR        15 chars max.
  226. X\fBR:home_address\fR            72 chars max.
  227. X.fi
  228. X.PP
  229. XFields which exceed the above maximum number of characters
  230. Xresult in no error, but are silently truncated at
  231. Xthe maximum permissible length when displayed.
  232. XFields which contain incorrect header characters are ignored.
  233. XFor the sake of uniformity, comments in the database file
  234. Xthat are not intended for display
  235. Xshould be prefaced by the field header \fB#:\fR.
  236. X.SH EXAMPLE DATABASE FILE RECORD
  237. X.nf
  238. X.sh
  239. XN:Public, John Q.
  240. XO:Any Industry, Inc.
  241. XT:Systems Programmer
  242. XD:Widget R&D
  243. XA:123 Any Road, Anytown, NY 12345
  244. XP:716/123-4567
  245. XP:Ext 234
  246. XF:716/123-4599
  247. XX:12-3456 ANYINDNY
  248. XU:jqp@any.UUCP
  249. XH:716/123-9876
  250. XR:456 Anybrook Lane, Anysuburb, NY 12354
  251. XC:Writes CAD software for widgets
  252. XC:Has extensive experience with XYZNIX
  253. X.SH BUGS
  254. Xnone
  255. X.SH FILES
  256. X.nf
  257. X\fB$HOME/.rf_data\fR            user private database file
  258. X\fB/usr/local/lib/rf_data\fR    system-wide database file
  259. X.fi
  260. X.SH AUTHOR
  261. XLawrence G. Lippman, larry@kitty.UUCP
  262. //E*O*F rf.1//
  263.  
  264. echo x - rf.c
  265. sed -e 's/^X//' > "rf.c" << '//E*O*F rf.c//'
  266. X/*
  267. X * rf(1L)    A "rotary file"-like database for names, addresses, telephone
  268. X *        numbers and related information.
  269. X *
  270. X *        Copyright (c) 1985
  271. X *        by Lawrence Lippman, larry@kitty.UUCP
  272. X *        Recognition Research Corp., Clarence, NY
  273. X *
  274. X *        This program may be freely used and distributed, provided that
  275. X *        it is not used for monetary or other commercial gain, and
  276. X *        provided that this notice remains intact.
  277. X *
  278. X *        Last revision: 3 Jun 1985
  279. X */
  280. X
  281. X#include <stdio.h>
  282. X#include <curses.h>
  283. X#include <signal.h>
  284. X#include <string.h>
  285. X
  286. X#ifndef SYSDATA
  287. X#define    SYSDATA    "/usr/local/lib/rf_data"    /* system database file */
  288. X#endif
  289. X
  290. X/*
  291. X * Global variables
  292. X */
  293. X    char    name[31], title[25], org[73], dept[25], adr[73];
  294. X    char    phone[2][16], telex[2][25], fax[2][16], uucp[2][25];
  295. X    char    homephone[16], homeadr[65], comments[4][73];
  296. X    char    Key[73], buf[80];
  297. X    int    Org, File, List;
  298. X    int    hits, phlines, comlines;
  299. X    int    terminate(), more(), strsearch();
  300. X    FILE    *f1, *fopen();
  301. X
  302. Xmain(argc,argv)
  303. X    char    **argv;
  304. X{
  305. X    char    filename[65], *getenv();
  306. X    int    keywords;
  307. X
  308. X/*
  309. X * Set up defaults
  310. X */
  311. X    File = 0;    /* Use system-wide database file, not user file */
  312. X    List = 0;    /* Display full entry, not just hit list */
  313. X    Org = 0;    /* Search by name, not organization */
  314. X
  315. X/*
  316. X * Get options and search string
  317. X */
  318. X    (void) strcpy(Key,"");
  319. X    keywords = 0;
  320. X
  321. X    while(argc-- > 1) {
  322. X        if(*argv[1] == '-')
  323. X            switch(argv[1][1]) {
  324. X                case 'l':
  325. X                    List = 1;
  326. X                    break;
  327. X                case 'f':
  328. X                    File = 1;
  329. X                    break;
  330. X                case 'o':
  331. X                    Org = 1;
  332. X                    break;
  333. X                default:
  334. X                    usage();
  335. X            }
  336. X
  337. X        else{
  338. X            if(keywords > 0)
  339. X                (void) strcat(Key," ");
  340. X            (void) strcat(Key,argv[1]);
  341. X            keywords++;
  342. X        }
  343. X        argv++;
  344. X    }
  345. X
  346. X    if(strlen(Key) == 0)
  347. X        usage();
  348. X
  349. X/*
  350. X * Select and open database file
  351. X */
  352. X    if(File)
  353. X        (void) sprintf(filename, "%s/.rf_data", getenv("HOME"));
  354. X    else
  355. X        (void) strcpy(filename, SYSDATA);
  356. X
  357. X    if((f1 = fopen(filename,"r")) == NULL){
  358. X        (void) fprintf(stderr,"Cannot open data file %s\n",filename);
  359. X        exit(-1);
  360. X    }
  361. X
  362. X/*
  363. X * Catch signals and setup curses
  364. X */
  365. X    (void) signal(SIGINT, terminate);
  366. X    (void) signal(SIGQUIT, terminate);
  367. X
  368. X    initscr();
  369. X    if(List){
  370. X        idlok(stdscr,1);
  371. X        setscrreg(0,19);
  372. X        scrollok(stdscr,1);
  373. X    }
  374. X
  375. X/*
  376. X * Read file, search for records, and do it to it...
  377. X */
  378. X    hits = 0;
  379. X
  380. X    while(fgets(buf,80,f1) != NULL){
  381. X        if(buf[0] == 'N' && buf[1] == ':'){
  382. X            if(strlen(buf) == 2)
  383. X                (void) strcpy(name,"");
  384. X            else{
  385. X                (void) strxcpy(name,buf,2,30);
  386. X                if(!Org){
  387. X                    if(strsearch(name,Key)){
  388. X                        if(hits > 0 && !List)
  389. X                            (void) more();
  390. X                        (void) strcpy(org,"");
  391. X                        (void) clrrecord();
  392. X                        (void) rdrecord();
  393. X                        (void) display();
  394. X                        hits++;
  395. X                    }
  396. X                }
  397. X            }
  398. X        }
  399. X        if(buf[0] == 'O' && buf[1] == ':'){
  400. X            (void) strxcpy(org,buf,2,72);
  401. X            if(Org){
  402. X                if(strsearch(org,Key)){
  403. X                    if(hits > 0 && !List)
  404. X                        (void) more();
  405. X                    (void) clrrecord();
  406. X                    (void) rdrecord();
  407. X                    (void) display();
  408. X                    hits++;
  409. X                }
  410. X            }
  411. X        }
  412. X    }
  413. X
  414. X    (void) terminate();
  415. X    return(0);
  416. X}
  417. X
  418. X/*
  419. X * clrrecord:    clear all display strings
  420. X */
  421. Xclrrecord()
  422. X{
  423. X    int    i;
  424. X
  425. X    (void) strcpy(title,"");
  426. X    (void) strcpy(dept,"");
  427. X    (void) strcpy(adr,"");
  428. X    (void) strcpy(homephone,"");
  429. X    (void) strcpy(homeadr,"");
  430. X    (void) strcpy(comments[0],"");
  431. X    for(i = 0; i <= 1; i++){
  432. X        (void) strcpy(phone[i],"");
  433. X        (void) strcpy(telex[i],"");
  434. X        (void) strcpy(fax[i],"");
  435. X        (void) strcpy(uucp[i],"");
  436. X    }
  437. X}
  438. X
  439. X/*
  440. X * rdrecord:    read the rest of a record following a "name" read
  441. X */
  442. Xrdrecord()
  443. X{
  444. X    int    phln, fxln, txln, uuln;
  445. X
  446. X    phln = fxln = txln = uuln = 0;
  447. X    phlines = 0;
  448. X    comlines = 0;
  449. X
  450. X    while(fgets(buf,80,f1) != NULL){
  451. X
  452. X        if(buf[1] != ':' || strlen(buf) <= 1)
  453. X            return;
  454. X
  455. X        switch(buf[0]) {
  456. X            case 'O':
  457. X                (void) strxcpy(org,buf,2,72);
  458. X                break;
  459. X            case 'T':
  460. X                (void) strxcpy(title,buf,2,24);
  461. X                break;
  462. X            case 'D':
  463. X                (void) strxcpy(dept,buf,2,24);
  464. X                break;
  465. X            case 'A':
  466. X                (void) strxcpy(adr,buf,2,72);
  467. X                break;
  468. X            case 'P':
  469. X                if(phln > 1)
  470. X                    break;
  471. X                (void) strxcpy(phone[phln],buf,2,15);
  472. X                phln++;
  473. X                break;
  474. X            case 'X':
  475. X                if(txln > 1)
  476. X                    break;
  477. X                (void) strxcpy(telex[txln],buf,2,24);
  478. X                txln++;
  479. X                break;
  480. X            case 'F':
  481. X                if(fxln > 1)
  482. X                    break;
  483. X                (void) strxcpy(fax[fxln],buf,2,15);
  484. X                fxln++;
  485. X                break;
  486. X            case 'U':
  487. X                if(uuln > 1)
  488. X                    break;
  489. X                (void) strxcpy(uucp[uuln],buf,2,24);
  490. X                uuln++;
  491. X                break;
  492. X            case 'H':
  493. X                (void) strxcpy(homephone,buf,2,15);
  494. X                break;
  495. X            case 'R':
  496. X                (void) strxcpy(homeadr,buf,2,64);
  497. X                break;
  498. X            case 'C':
  499. X                if(comlines > 3)
  500. X                    break;
  501. X                (void) strxcpy(comments[comlines],buf,2,72);
  502. X                comlines++;
  503. X                break;
  504. X        }
  505. X        if(phln > 1 || txln > 1 || fxln > 1 || uuln > 1)
  506. X            phlines = 1;
  507. X    }
  508. X}
  509. X
  510. X/*
  511. X * display:    Display the results of a search
  512. X */
  513. Xdisplay()
  514. X{
  515. X    int    l;
  516. X
  517. X    if(List){
  518. X        if(hits == 0){
  519. X            erase();
  520. X            refresh();
  521. X            if(Org)
  522. X                mvaddstr(0, 0, org);
  523. X            else
  524. X                mvaddstr(0, 0, name);
  525. X        }else{
  526. X            if(Org)
  527. X                printw("%s", org);
  528. X            else
  529. X                printw("%s", name);
  530. X            
  531. X        }
  532. X        refresh();
  533. X        return(0);
  534. X    }
  535. X
  536. X    erase();
  537. X    refresh();
  538. X
  539. X    attron(A_REVERSE);
  540. X    mvaddstr(0, 0, "NAME");
  541. X    mvaddstr(0, 32, "TITLE");
  542. X    mvaddstr(0, 56, "DEPT");
  543. X    mvaddstr(3, 0, "ORGANIZATION NAME & ADDRESS");
  544. X    mvaddstr(7, 0, "TELEPHONE");
  545. X    mvaddstr(7, 16, "TELECOPIER");
  546. X    mvaddstr(7, 32, "TELEX");
  547. X    mvaddstr(7, 56, "UUCP");
  548. X    mvaddstr(10 + phlines, 0, "HOME TELEPHONE");
  549. X    mvaddstr(10 + phlines, 16, "HOME ADDRESS");
  550. X    mvaddstr(13 + phlines, 0, "COMMENTS");
  551. X    attroff(A_REVERSE);
  552. X    
  553. X    mvaddstr(1, 0, name);
  554. X    mvaddstr(1, 32, title);
  555. X    mvaddstr(1, 56, dept);
  556. X    mvaddstr(4, 0, org);
  557. X    mvaddstr(5, 0, adr);
  558. X    for(l = 0; l <= phlines; l++){
  559. X        mvaddstr(8 + l, 0, phone[l]);
  560. X        mvaddstr(8 + l, 16, fax[l]);
  561. X        mvaddstr(8 + l, 32, telex[l]);
  562. X        mvaddstr(8 + l, 56, uucp[l]);
  563. X    }
  564. X    mvaddstr(11 + phlines, 0, homephone);
  565. X    mvaddstr(11 + phlines, 16, homeadr);
  566. X    for(l = 0; l <= comlines; l++)
  567. X        mvaddstr(14 + phlines + l, 0, comments[l]);
  568. X
  569. X    refresh();
  570. X    return(0);
  571. X}
  572. X
  573. X/*
  574. X * more:    Prompt for display of entries when multiple hits occur
  575. X */
  576. Xmore()
  577. X{
  578. Xagain:
  579. X    attron(A_REVERSE);
  580. X    mvaddstr(20, 0, "MORE HITS: CONTINUE?");
  581. X    attroff(A_REVERSE);
  582. X    mvaddstr(20, 22, "[y] [n]  ");
  583. X    refresh();
  584. X    switch(getch()){
  585. X        case 'n':
  586. X        case 'N':
  587. X            (void) terminate();
  588. X        case 'y':
  589. X        case 'Y':
  590. X            return(0);
  591. X    }
  592. X    mvaddstr(20, 31, " ");
  593. X    goto again;
  594. X}
  595. X
  596. X/*
  597. X * terminate:    Exit gracefully
  598. X */
  599. Xterminate()
  600. X{
  601. X    (void) fclose(f1);
  602. X
  603. X    move(LINES-1, 0);
  604. X    refresh();
  605. X    endwin();
  606. X    exit(0);
  607. X}
  608. X
  609. X/*
  610. X * strsearch:    Search for any occurence of string "t" in string "s";
  611. X *        return 1 if a match found, otherwise return 0
  612. X */
  613. Xstrsearch(s,t)
  614. X    char    s[80], t[80];
  615. X{
  616. X    register    i, n, nn;
  617. X    int    slength, tlength;
  618. X    char    st[80];
  619. X
  620. X    slength = strlen(s);
  621. X    tlength = strlen(t);
  622. X    if(slength == 0 || tlength == 0)
  623. X        return(0);
  624. X
  625. X    for (i = 0; i < slength; i++){
  626. X        n=0;
  627. X        for(nn = i; nn < i + tlength; nn++){
  628. X            if(nn > slength)
  629. X                return(0);
  630. X            st[n] = s[nn];
  631. X            n++;
  632. X        }
  633. X        st[n] = '\0';
  634. X        if (strcmp(st,t) == 0)
  635. X            return(1);
  636. X    }
  637. X    return(0);
  638. X}
  639. X
  640. X/*
  641. X * strxcpy:    Copy string "t" to string "s", with "offset" characters in
  642. X *        string "t" skipped before the copy, and with a maximum of
  643. X *        "maxs" characters [not including NULL] copied to string "s"
  644. X */
  645. Xstrxcpy(s,t,offset,maxs)
  646. X    char    s[80], t[80];
  647. X    int    offset, maxs;
  648. X{
  649. X    register    n, nn;
  650. X    int    tlength;
  651. X
  652. X    nn = 0;
  653. X    tlength = strlen(t);
  654. X
  655. X    for(n = offset; n <= tlength + 1; n++){
  656. X        s[nn] = t[n];
  657. X        if(t[n] == '\0')
  658. X            return(0);
  659. X        nn++;
  660. X        if(nn == maxs){
  661. X            s[nn + 1] = '\0';
  662. X            return(0);
  663. X        }
  664. X    }
  665. X    return(0);
  666. X}
  667. X
  668. X/*
  669. X * usage:    Display usage error message and exit
  670. X */
  671. Xusage()
  672. X{
  673. X    (void) fprintf(stderr,"usage: rf [-f] [-l] [-o] searchstring\n");
  674. X    exit(-1);
  675. X}
  676. //E*O*F rf.c//
  677.  
  678. exit 0
  679.  
  680.