home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / alt / sources / 2848 < prev    next >
Encoding:
Internet Message Format  |  1992-12-22  |  15.4 KB

  1. Xref: sparky alt.sources:2848 news.misc:2073 news.software.readers:2534
  2. Path: sparky!uunet!pipex!bnr.co.uk!uknet!mcsun!sunic!news.lth.se!bengtl
  3. From: bengtl@maths.lth.se (Bengt Larsson)
  4. Newsgroups: alt.sources,news.misc,news.software.readers
  5. Subject: faq - FAQ reader/lister/indexer
  6. Message-ID: <1992Dec22.162838.22949@lth.se>
  7. Date: 22 Dec 92 16:28:38 GMT
  8. Sender: news@lth.se
  9. Followup-To: alt.sources.d
  10. Organization: Lund Institute of Technology, Sweden
  11. Lines: 646
  12.  
  13. This is an updated version of the "faq" script. It has some
  14. bugs fixed, better error messages and argument checking and a man page.
  15.  
  16. README
  17.  
  18. Faq is a script for looking up, listing and reading FAQs in
  19. news.answers. 
  20.  
  21. It's a Bourne shell script and should be very portable. See the source
  22. for comments. 
  23.  
  24. Notes: 
  25.    - It needs a spool directory. No NNTP.
  26.    - It looks for articles crossposted between news.answers and other
  27.      groups, and keeps an index of groups for fast access.
  28.  
  29. Usage:
  30.    faq [options...] [newsgroup...]
  31.    
  32. Examples:
  33.    faq rec.games.frp    # read FAQ(s) for newsgroup
  34.    faq -g        # list all groups with FAQs
  35.  
  36. Enjoy.
  37.  
  38. Bengt L, 92-12-22
  39.  
  40. #! /bin/sh
  41. # This is a shell archive, meaning:
  42. # 1. Remove everything above the #! /bin/sh line.
  43. # 2. Save the resulting text in a file.
  44. # 3. Execute the file with /bin/sh (not csh) to create the files:
  45. #    CHANGES
  46. #    INSTALL
  47. #    README
  48. #    faq
  49. #    faq.1
  50. # This archive created: Tue Dec 22 16:58:30 1992
  51. export PATH; PATH=/bin:$PATH
  52. if test -f 'CHANGES'
  53. then
  54.     echo shar: will not over-write existing file "'CHANGES'"
  55. else
  56. sed 's/^X//' << \SHAR_EOF > 'CHANGES'
  57. XOriginally written: 1992-03-30
  58. X
  59. XChanges 92-06-10:
  60. X
  61. X   - Added better argument checking and saner error messages
  62. X   - Options -x and -c now implies -g.
  63. X   - Added -n switch to generate no output, only exit status returned.
  64. X     Indexes are updated.
  65. X   - Always updates common index /usr/lib/news/faqindex if it's writable.
  66. X   - All groups ending with ".answers" are considered answers groups
  67. X
  68. XChanges 92-07-09:
  69. X
  70. X   - Added "Scanning..." message when output is a terminal (to see
  71. X     that something is happening)
  72. X
  73. XChanges 92-12-22:
  74. X   
  75. X   - Added a man page, CHANGES file and INSTALL file
  76. SHAR_EOF
  77. fi # end of overwriting check
  78. if test -f 'INSTALL'
  79. then
  80.     echo shar: will not over-write existing file "'INSTALL'"
  81. else
  82. sed 's/^X//' << \SHAR_EOF > 'INSTALL'
  83. XFor users & administrators:
  84. X
  85. XLook at the options at the beginning of the script (marked
  86. X"Start configurable options/End configurable options") and change them 
  87. Xif needed. The defaults should work for most people. 
  88. X
  89. XFor administrators:
  90. X
  91. XIf you are the news administrator, you can:
  92. X
  93. X1 ) Create a common index file and make it writable for all 
  94. X    (/usr/lib/news/faqindex mode 666). This way the common index is 
  95. X    always up-to-date. This invites to abuse though.
  96. X
  97. X2)  Make the common index mode 644 and run "faq -n" periodically
  98. X    from cron as user news (or the owner of the file). This is safer, and
  99. X    nearly as effective.
  100. X
  101. X3)  Skip the common index altogether. This means extra load on the server
  102. X    (scanning of articles in news.answers) since every user then maintains 
  103. X    his own faq index file.
  104. X
  105. XArticles already scanned into the common index are never rescanned
  106. Xby users (unless they use the -f switch).
  107. X
  108. XThe spool directory for news.answers is only consulted (using /bin/ls)
  109. Xif it has been modified more recently than the newest index file. 
  110. X
  111. XA crontab line might look like:
  112. X
  113. X  0,10,20,30,40,50 * * * * /usr/local/bin/faq -n
  114. X
  115. Xto check for FAQs every 10 minutes.
  116. X
  117. XExpired articles are removed from an index when it's updated. 
  118. X
  119. XBengt L. 92-12-22.
  120. SHAR_EOF
  121. fi # end of overwriting check
  122. if test -f 'README'
  123. then
  124.     echo shar: will not over-write existing file "'README'"
  125. else
  126. sed 's/^X//' << \SHAR_EOF > 'README'
  127. XFaq is a script for looking up, listing and reading FAQs in
  128. Xnews.answers. 
  129. X
  130. XIt's a Bourne shell script and should be very portable. See the source
  131. Xfor comments. 
  132. X
  133. XNotes: 
  134. X   - It needs a spool directory. No NNTP.
  135. X   - It looks for articles crossposted between news.answers and other
  136. X     groups, and keeps an index of groups for fast access.
  137. X
  138. XUsage:
  139. X   faq [options...] [newsgroup...]
  140. X   
  141. XExamples:
  142. X   faq rec.games.frp    # read FAQ(s) for newsgroup
  143. X   faq -g        # list all groups with FAQs
  144. X
  145. XEnjoy.
  146. X
  147. XBengt L, 92-12-22
  148. SHAR_EOF
  149. fi # end of overwriting check
  150. if test -f 'faq'
  151. then
  152.     echo shar: will not over-write existing file "'faq'"
  153. else
  154. sed 's/^X//' << \SHAR_EOF > 'faq'
  155. X#!/bin/sh
  156. X
  157. X# faq: Look up and read Usenet news Frequently Asked Questions.
  158. X#      Uses information from the spool directory of "news.answers".
  159. X
  160. X# Usage: faq [-a|-g|-l|-f|-s|-c|-p|-x|-d] [newsgroup|number...]
  161. X
  162. X# Options:
  163. X#    -a        Match all groups
  164. X#    -g        List all groups that have faqs
  165. X#    -l        List filenames of faqs
  166. X#    -f        Force index rebuild
  167. X#    -s        List subjects
  168. X#    -c        Count faqs per newsgroup (with -g)
  169. X#    -i     Interactive mode
  170. X#    -p        Search for newsgroup matching a pattern
  171. X#    -x        Show crossposts (with -g)
  172. X#    -d     Dump index
  173. X#    -n        Only exit with status
  174. X
  175. X# Written by Bengt Larsson <bengtl@maths.lth.se>, 92-03-24
  176. X# Updated 92-06-10, argument checking, exit status, -n option,
  177. X#    better error messages
  178. X# 92-07-09, Added "dots" to "Scanning..."
  179. X
  180. X# Start configurable options 
  181. X
  182. Xspool=/usr/spool/news            # Spool directory
  183. Xlib=/usr/lib/news            # Lib directory
  184. X
  185. Xanswers=$spool/news/answers        # Database directory
  186. Xindex1=$lib/faqindex            # Global index (optional)
  187. Xindex2=$HOME/.faq            # Local index
  188. X
  189. Xdefaultpager=more            # Maybe "pg" for SVR3
  190. Xxargs=false                # true if you have xargs
  191. Xbackup=true                # true if you want backup copy of index
  192. X
  193. X# End configurable options 
  194. X
  195. Xpager="${FAQPAGER-${PAGER-$defaultpager}}"
  196. X
  197. Xtemp=/tmp/faq$$
  198. Xcleanup="rm -f $temp.*"
  199. X$cleanup
  200. Xtrap "$cleanup; exit 1" 0 1 2 15
  201. Xreturn="eval $cleanup; trap 0; exit"    # Hack to get exit status
  202. X
  203. Xall=false
  204. Xgroups=false
  205. Xforce=false
  206. X
  207. Xlist=false
  208. Xsubjects=false
  209. Xcount=false
  210. Xinteractive=false
  211. Xpattern=false
  212. Xcrosspost=false
  213. Xiopt=""
  214. Xdump=false
  215. Xsilent=false
  216. Xrescan=false
  217. X
  218. Xwhile :
  219. Xdo
  220. X   case $1 in
  221. X      -a) all=true;;            # All
  222. X      -l) list=true;;            # List filenames
  223. X      -g) groups=true;;            # List group names
  224. X      -f) force=true;;            # Force index rebuild
  225. X      -s) subjects=true;;        # List subjects
  226. X      -c) count=true; groups=true;;    # Count articles (with -g)
  227. X      -i) interactive=true;;        # Interactive mode
  228. X      -p) pattern=true; iopt="-p";;    # Pattern instead of exact match
  229. X      -x) crosspost=true; groups=true;;    # Show X-posts (with -g)
  230. X      -d) dump=true;;            # Dump index file
  231. X      -n) silent=true;;            # Only return exit status
  232. X      -r) rescan=true;;            # rescan spool dir
  233. X      -*) echo "faq: invalid switch $1" 1>&2; exit 2;;
  234. X      *)  break;;
  235. X   esac
  236. X   shift
  237. Xdone
  238. X
  239. Xif test $# -eq 0 -a $all = false -a $groups = false -a $interactive = false\
  240. X                 -a $dump = false -a $silent = false
  241. Xthen
  242. X   echo "Usage: faq [-l|-s]  {-p pattern | -a | {newsgroup|number}...}" 1>&2
  243. X   echo "       faq [-g|-c|-x] [-p pattern] [-a]" 1>&2
  244. X   echo 'Enter "faq -i" for informational postings' 1>&2
  245. X   $return 2
  246. Xfi
  247. X
  248. X# Interactive. List subjects and pick and choose.
  249. X       
  250. Xif $interactive
  251. Xthen
  252. X   defaultgroup=news.announce.newusers
  253. X   default=false
  254. X   
  255. X   
  256. X   if test $# -eq 0
  257. X   then
  258. X      set "$defaultgroup"
  259. X      default=true
  260. X   fi
  261. X   
  262. X   if test $silent = false || faq -n "$@"
  263. X   then
  264. X      echo "$@"
  265. X      faq -s $iopt "$@" | tee $temp.s
  266. X      test -s $temp.s || $return 1
  267. X   else
  268. X      $return 1
  269. X   fi
  270. X   
  271. X   if $default
  272. X   then
  273. X      echo "This group ($defaultgroup), contains general introductory"
  274. X      echo "documents. Enter \"number\" to read, \"help\" for help."
  275. X   fi
  276. X         
  277. X   if test ! -t 1; then $return 0; fi
  278. X   
  279. X   while true
  280. X   do 
  281. X      echo "faq> " | tr -d "\012"    # portable...
  282. X      read faq
  283. X      case $faq in
  284. X         ""|q|quit)     break;;
  285. X         \*)         faq $iopt "$@"; echo "$@"; cat $temp.s;;
  286. X         h|help|\?)    echo 'help, quit or list. (number) to read. * to read all.';;
  287. X         l|list)    echo "$@"; cat $temp.s;;
  288. X         *)        faq $faq; echo "$@"; cat $temp.s;;
  289. X      esac
  290. X   done
  291. X   $return 0
  292. Xfi
  293. X
  294. Xset -e
  295. Xcd $answers
  296. X
  297. X# Find newest index file (common index if it's writable)
  298. X
  299. Xif test -f $index1        
  300. Xthen
  301. X   if test -f $index2
  302. X   then
  303. X      if test -w $index1 -o `ls -td $index1 $index2 | sed 1q` = $index1
  304. X      then
  305. X         rm -f $index2
  306. X         index=$index1
  307. X      else
  308. X         index=$index2
  309. X      fi
  310. X   else
  311. X      index=$index1
  312. X   fi
  313. Xelse
  314. X   index=$index2
  315. Xfi
  316. X
  317. X# Determine if index is up-to-date
  318. X
  319. Xif test ! -f $index || $force
  320. Xthen
  321. X   ls | grep '^[0-9]*$' | sort -n >$temp.n
  322. X   >$temp.o
  323. X   update=true
  324. Xelif test `ls -td $index $answers | sed 1q` = $index -a $rescan = false
  325. Xthen                
  326. X   >$temp.n
  327. X   update=false
  328. Xelse
  329. X   >$temp.n
  330. X   ls | grep '^[0-9]*$' | sort +0n -1 +1n -2 - $index | awk '
  331. X   NF == 1 {if (lastnf==1) print num >"'"$temp.n"'"; lastnf=NF; num=$1}
  332. X   NF != 1 {if ($1 == num) print
  333. X            else if (lastnf==1) print num >"'"$temp.n"'"
  334. X        lastnf=NF}
  335. X   END     {if (lastnf==1) print num >"'"$temp.n"'"}' >$temp.o
  336. X   update=true
  337. Xfi
  338. X
  339. X# Do update
  340. X
  341. Xif $update
  342. Xthen
  343. X   if test -t 1
  344. X   then 
  345. X      echo "Scanning..." | tr -d "\012" 1>&2
  346. X      termout=true
  347. X      dots=""
  348. X   else
  349. X      termout=false
  350. X   fi
  351. X   
  352. X   if $backup
  353. X   then
  354. X      cp $index $index.old 2>/dev/null || :
  355. X   else
  356. X      rm -f $index.old
  357. X   fi
  358. X   
  359. X   cat $temp.n |
  360. X   while read file
  361. X   do
  362. X   awk '
  363. X      BEGIN {file="'"$file"'"}
  364. X      $1 == "Newsgroups:" {
  365. X         split($2,groups,",")
  366. X         num=1
  367. X         for (i in groups) {
  368. X           if (groups[i] !~ /\.answers$/) print file,num++,groups[i]
  369. X         }
  370. X         if (num==1) {for (i in groups) {print file,num++,groups[i]}}
  371. X     exit
  372. X      }' $file
  373. X      
  374. X      case $termout$dots in
  375. X         true.....) echo "$dots" | tr -d "\012" 1>&2; dots=".";;
  376. X         true*)     dots="$dots.";;
  377. X      esac
  378. X   done >>$temp.o
  379. X   
  380. X   if $termout; then echo "$dots" 1>&2; fi
  381. X   
  382. X   if cp $temp.o $index 2>/dev/null
  383. X   then
  384. X      : ok
  385. X   elif cp $temp.o $index2 2>/dev/null
  386. X   then
  387. X      index=$index2    # user copy of index
  388. X   else
  389. X      index=$temp.i    # temp index
  390. X      cp $temp.o $index
  391. X   fi
  392. Xfi
  393. X
  394. X# Dump index
  395. X
  396. Xif $dump
  397. Xthen
  398. X   if $pattern
  399. X   then
  400. X      awk '$3 ~ /'"$1"'/' $index
  401. X   elif test $# -ne 0
  402. X   then
  403. X      awk '$3 == "'"$1"'"' $index
  404. X   else
  405. X      cat $index
  406. X   fi
  407. X   $return 0
  408. Xfi
  409. X
  410. X# List groups
  411. X
  412. Xif $groups
  413. Xthen
  414. X   if $crosspost
  415. X   then
  416. X      awk '{if (num==$1) {groups=groups "," $3}
  417. X            else {if (groups!="") print groups; groups=$3}; num=$1}
  418. X           END {if (groups!="") print groups}' $index
  419. X   else
  420. X      awk '{print $3}' $index
  421. X   fi |
  422. X   if $pattern
  423. X   then 
  424. X      egrep "$1"
  425. X   else
  426. X      cat
  427. X   fi |
  428. X   if $all
  429. X   then
  430. X      sort
  431. X   elif $count
  432. X   then
  433. X      sort | uniq -c
  434. X   else
  435. X      sort -u
  436. X   fi
  437. X   $return 0
  438. Xfi
  439. X
  440. X# Normal search for group/number/pattern
  441. X
  442. Xif $all
  443. Xthen
  444. X   awk '{print $1}' $index
  445. Xelse
  446. X   for i
  447. X   do
  448. X      case $i in
  449. X         [0-9]*|*/*)  
  450. X            if test -f "$i"
  451. X            then 
  452. X               echo "$i"
  453. X            else
  454. X               echo "faq: $i not found" 1>&2~
  455. X            fi;;
  456. X         *) if $pattern
  457. X        then 
  458. X           awk '$3 ~ /'"$i"'/ {print $1}' $index
  459. X            else
  460. X               awk '$3 == "'"$i"'" {print $1}' $index
  461. X            fi;;
  462. X      esac
  463. X   done
  464. Xfi | sort -un >$temp.x
  465. X
  466. X# If anything matched, act on it
  467. X
  468. Xif test -s $temp.x
  469. Xthen
  470. X   if $silent
  471. X   then
  472. X      $return 0
  473. X   elif $list
  474. X   then
  475. X       awk '{printf "%s/%s\n","'"$answers"'",$1}' $temp.x
  476. X   elif $subjects
  477. X   then
  478. X      while read file
  479. X      do
  480. X         sed -n '
  481. X         /^Subject:/{s/^Subject: */'"$file:"'/
  482. X         p
  483. X         q
  484. X         }' "$file"
  485. X      done <$temp.x
  486. X   else
  487. X      if $xargs
  488. X      then
  489. X          xargs $pager <$temp.x
  490. X      else
  491. X         awk '{if (num<19) {files= files " " $1; num++}
  492. X               else {print files,$1; files=""; num=0}}
  493. X              END {if (files!="") print files}' $temp.x |
  494. X         while read files
  495. X         do
  496. X            $pager $files
  497. X         done
  498. X      fi
  499. X   fi
  500. X   $return 0
  501. Xelse
  502. X   if test $silent = false -a $# -ne 0
  503. X   then  
  504. X      echo "faq: no faqs found for $*" 1>&2;
  505. X      $return 1
  506. X   elif test $# -ne 0
  507. X   then
  508. X      $return 1
  509. X   else
  510. X      $return 0
  511. X   fi
  512. Xfi
  513. SHAR_EOF
  514. chmod +x 'faq'
  515. fi # end of overwriting check
  516. if test -f 'faq.1'
  517. then
  518.     echo shar: will not over-write existing file "'faq.1'"
  519. else
  520. sed 's/^X//' << \SHAR_EOF > 'faq.1'
  521. X.TH FAQ 1 "22 December 1992"
  522. X.SH NAME
  523. Xfaq \- FAQ reader/lister/indexer
  524. X.SH SYNOPSIS
  525. X.B faq
  526. X[
  527. X.B \-i
  528. X|
  529. X.B \-l
  530. X|
  531. X.B \-s
  532. X]
  533. X{\fB\-p\fP\fI pattern\fR|\fB \-a \fP| {\fIgroup\fR|\fInumber\fR}...}
  534. X.br
  535. X.B faq
  536. X[
  537. X.B \-g
  538. X|
  539. X.B \-c
  540. X|
  541. X.B \-x
  542. X]
  543. X[
  544. X.BI \-p " pattern"
  545. X]
  546. X[
  547. X.B \-a
  548. X]
  549. X.LP
  550. X.SH DESCRIPTION
  551. X.LP
  552. X.B faq
  553. Xis a script for reading, listing and indexing FAQs (Frequently Asked
  554. XQuestions) crossposted to the newsgroup
  555. X.BR news.answers .
  556. X.SH OPTIONS
  557. X.TP
  558. X.BI \-a
  559. XThe
  560. Xcommand either applies to all FAQ postings, or to all groups containing FAQ
  561. Xpostings.
  562. X.TP
  563. X.B \-g
  564. XList names of all groups that have FAQs. Group names may
  565. Xbe matched with a pattern using 
  566. X.BR \-p .
  567. X.TP
  568. X.B \-l
  569. XList file names of matching FAQs.
  570. X.TP
  571. X.B \-f
  572. XForce full index rebuild. Use when the database is corrupted.
  573. X.TP
  574. X.B \-s
  575. XList subject lines of matching FAQs.
  576. X.TP
  577. X.B \-c
  578. XDisplay names of groups containing FAQs (optionally matching a pattern 
  579. Xwith \fB\-p\fP).
  580. XEach name is preceded with the number of FAQs in the group.
  581. X.TP
  582. X.B \-i
  583. XInteractive mode. Lists the subject lines of the matching FAQs and
  584. Xprompts for which FAQs to read.
  585. X
  586. X.B "faq -i"
  587. Xwithout a group name defaults to the group
  588. X.BR news.announce.newusers .
  589. X.TP
  590. X.BI \-p " pattern"
  591. XMatch newsgroup pattern (default is exact match on newsgroup name).
  592. XPatterns use the format of
  593. X.BR "grep(1)" .
  594. X.TP
  595. X.B \-x
  596. XAs 
  597. X.BR \-g ,
  598. Xbut list all combinations of crossposted group names (separated by ","), 
  599. Xinstead of only group names.
  600. X.TP
  601. X.B \-d
  602. XDump the updated index file on standard output. Each line in the index
  603. Xconsists of \fImessage-number crosspost-count newsgroup-name\fR.
  604. X.TP
  605. X.B \-n
  606. XUpdate index file, but give no output. Returns a status of 0
  607. Xif the specified group (or pattern) matched, otherwise returns a status  of 1.
  608. X
  609. X.B "faq -n"
  610. Xwith no parameters updates the index file and returns status 0 if this
  611. Xsucceeded.
  612. X.SH EXAMPLES
  613. X.LP
  614. XRead the FAQs in \fBnews.group\fR, if any:
  615. X.IP
  616. X.B faq
  617. X.I news.group
  618. X.LP
  619. XList groups that have FAQs:
  620. X.IP
  621. X.B faq -g
  622. X.SH FILES
  623. X.TP
  624. X.B $HOME/.faq
  625. XPrivate FAQ index
  626. X.TP
  627. X.B /usr/lib/news/faqindex
  628. XCommon FAQ index. 
  629. X
  630. X.B Faq 
  631. Xupdates the common FAQ index if its writable. If it is readable,
  632. Xthe data in it is used. A private index file is created if
  633. Xthe common index file isn't up-to-date or doesn't exist.
  634. X.TP
  635. X.B /usr/spool/news/news/answers 
  636. XDirectory scanned for FAQ postings.
  637. X.SH BUGS
  638. X.B faq
  639. Xonly works when news is kept in a spool directory (commonly 
  640. X\fB/usr/spool/news\fP).
  641. XIt does not work over NNTP.
  642. X.PP
  643. XNot too fast, since it's a shell script. It should be very portable though.
  644. X.PP
  645. XNote that the names of the spool directory and library directory
  646. Xhas to be configured at the beginning of the script if they're
  647. Xnot the standard
  648. X.B /usr/spool/news
  649. Xand 
  650. X.BR /usr/lib/news .
  651. X.SH AUTHOR
  652. XBengt Larsson <bengtl@maths.lth.se>
  653. SHAR_EOF
  654. fi # end of overwriting check
  655. #    End of shell archive
  656. exit 0
  657. -- 
  658. Bengt Larsson - bengtl@maths.lth.se
  659.