home *** CD-ROM | disk | FTP | other *** search
- Xref: sparky alt.sources:2848 news.misc:2073 news.software.readers:2534
- Path: sparky!uunet!pipex!bnr.co.uk!uknet!mcsun!sunic!news.lth.se!bengtl
- From: bengtl@maths.lth.se (Bengt Larsson)
- Newsgroups: alt.sources,news.misc,news.software.readers
- Subject: faq - FAQ reader/lister/indexer
- Message-ID: <1992Dec22.162838.22949@lth.se>
- Date: 22 Dec 92 16:28:38 GMT
- Sender: news@lth.se
- Followup-To: alt.sources.d
- Organization: Lund Institute of Technology, Sweden
- Lines: 646
-
- This is an updated version of the "faq" script. It has some
- bugs fixed, better error messages and argument checking and a man page.
-
- README
-
- Faq is a script for looking up, listing and reading FAQs in
- news.answers.
-
- It's a Bourne shell script and should be very portable. See the source
- for comments.
-
- Notes:
- - It needs a spool directory. No NNTP.
- - It looks for articles crossposted between news.answers and other
- groups, and keeps an index of groups for fast access.
-
- Usage:
- faq [options...] [newsgroup...]
-
- Examples:
- faq rec.games.frp # read FAQ(s) for newsgroup
- faq -g # list all groups with FAQs
-
- Enjoy.
-
- Bengt L, 92-12-22
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create the files:
- # CHANGES
- # INSTALL
- # README
- # faq
- # faq.1
- # This archive created: Tue Dec 22 16:58:30 1992
- export PATH; PATH=/bin:$PATH
- if test -f 'CHANGES'
- then
- echo shar: will not over-write existing file "'CHANGES'"
- else
- sed 's/^X//' << \SHAR_EOF > 'CHANGES'
- XOriginally written: 1992-03-30
- X
- XChanges 92-06-10:
- X
- X - Added better argument checking and saner error messages
- X - Options -x and -c now implies -g.
- X - Added -n switch to generate no output, only exit status returned.
- X Indexes are updated.
- X - Always updates common index /usr/lib/news/faqindex if it's writable.
- X - All groups ending with ".answers" are considered answers groups
- X
- XChanges 92-07-09:
- X
- X - Added "Scanning..." message when output is a terminal (to see
- X that something is happening)
- X
- XChanges 92-12-22:
- X
- X - Added a man page, CHANGES file and INSTALL file
- SHAR_EOF
- fi # end of overwriting check
- if test -f 'INSTALL'
- then
- echo shar: will not over-write existing file "'INSTALL'"
- else
- sed 's/^X//' << \SHAR_EOF > 'INSTALL'
- XFor users & administrators:
- X
- XLook at the options at the beginning of the script (marked
- X"Start configurable options/End configurable options") and change them
- Xif needed. The defaults should work for most people.
- X
- XFor administrators:
- X
- XIf you are the news administrator, you can:
- X
- X1 ) Create a common index file and make it writable for all
- X (/usr/lib/news/faqindex mode 666). This way the common index is
- X always up-to-date. This invites to abuse though.
- X
- X2) Make the common index mode 644 and run "faq -n" periodically
- X from cron as user news (or the owner of the file). This is safer, and
- X nearly as effective.
- X
- X3) Skip the common index altogether. This means extra load on the server
- X (scanning of articles in news.answers) since every user then maintains
- X his own faq index file.
- X
- XArticles already scanned into the common index are never rescanned
- Xby users (unless they use the -f switch).
- X
- XThe spool directory for news.answers is only consulted (using /bin/ls)
- Xif it has been modified more recently than the newest index file.
- X
- XA crontab line might look like:
- X
- X 0,10,20,30,40,50 * * * * /usr/local/bin/faq -n
- X
- Xto check for FAQs every 10 minutes.
- X
- XExpired articles are removed from an index when it's updated.
- X
- XBengt L. 92-12-22.
- SHAR_EOF
- fi # end of overwriting check
- if test -f 'README'
- then
- echo shar: will not over-write existing file "'README'"
- else
- sed 's/^X//' << \SHAR_EOF > 'README'
- XFaq is a script for looking up, listing and reading FAQs in
- Xnews.answers.
- X
- XIt's a Bourne shell script and should be very portable. See the source
- Xfor comments.
- X
- XNotes:
- X - It needs a spool directory. No NNTP.
- X - It looks for articles crossposted between news.answers and other
- X groups, and keeps an index of groups for fast access.
- X
- XUsage:
- X faq [options...] [newsgroup...]
- X
- XExamples:
- X faq rec.games.frp # read FAQ(s) for newsgroup
- X faq -g # list all groups with FAQs
- X
- XEnjoy.
- X
- XBengt L, 92-12-22
- SHAR_EOF
- fi # end of overwriting check
- if test -f 'faq'
- then
- echo shar: will not over-write existing file "'faq'"
- else
- sed 's/^X//' << \SHAR_EOF > 'faq'
- X#!/bin/sh
- X
- X# faq: Look up and read Usenet news Frequently Asked Questions.
- X# Uses information from the spool directory of "news.answers".
- X
- X# Usage: faq [-a|-g|-l|-f|-s|-c|-p|-x|-d] [newsgroup|number...]
- X
- X# Options:
- X# -a Match all groups
- X# -g List all groups that have faqs
- X# -l List filenames of faqs
- X# -f Force index rebuild
- X# -s List subjects
- X# -c Count faqs per newsgroup (with -g)
- X# -i Interactive mode
- X# -p Search for newsgroup matching a pattern
- X# -x Show crossposts (with -g)
- X# -d Dump index
- X# -n Only exit with status
- X
- X# Written by Bengt Larsson <bengtl@maths.lth.se>, 92-03-24
- X# Updated 92-06-10, argument checking, exit status, -n option,
- X# better error messages
- X# 92-07-09, Added "dots" to "Scanning..."
- X
- X# Start configurable options
- X
- Xspool=/usr/spool/news # Spool directory
- Xlib=/usr/lib/news # Lib directory
- X
- Xanswers=$spool/news/answers # Database directory
- Xindex1=$lib/faqindex # Global index (optional)
- Xindex2=$HOME/.faq # Local index
- X
- Xdefaultpager=more # Maybe "pg" for SVR3
- Xxargs=false # true if you have xargs
- Xbackup=true # true if you want backup copy of index
- X
- X# End configurable options
- X
- Xpager="${FAQPAGER-${PAGER-$defaultpager}}"
- X
- Xtemp=/tmp/faq$$
- Xcleanup="rm -f $temp.*"
- X$cleanup
- Xtrap "$cleanup; exit 1" 0 1 2 15
- Xreturn="eval $cleanup; trap 0; exit" # Hack to get exit status
- X
- Xall=false
- Xgroups=false
- Xforce=false
- X
- Xlist=false
- Xsubjects=false
- Xcount=false
- Xinteractive=false
- Xpattern=false
- Xcrosspost=false
- Xiopt=""
- Xdump=false
- Xsilent=false
- Xrescan=false
- X
- Xwhile :
- Xdo
- X case $1 in
- X -a) all=true;; # All
- X -l) list=true;; # List filenames
- X -g) groups=true;; # List group names
- X -f) force=true;; # Force index rebuild
- X -s) subjects=true;; # List subjects
- X -c) count=true; groups=true;; # Count articles (with -g)
- X -i) interactive=true;; # Interactive mode
- X -p) pattern=true; iopt="-p";; # Pattern instead of exact match
- X -x) crosspost=true; groups=true;; # Show X-posts (with -g)
- X -d) dump=true;; # Dump index file
- X -n) silent=true;; # Only return exit status
- X -r) rescan=true;; # rescan spool dir
- X -*) echo "faq: invalid switch $1" 1>&2; exit 2;;
- X *) break;;
- X esac
- X shift
- Xdone
- X
- Xif test $# -eq 0 -a $all = false -a $groups = false -a $interactive = false\
- X -a $dump = false -a $silent = false
- Xthen
- X echo "Usage: faq [-l|-s] {-p pattern | -a | {newsgroup|number}...}" 1>&2
- X echo " faq [-g|-c|-x] [-p pattern] [-a]" 1>&2
- X echo 'Enter "faq -i" for informational postings' 1>&2
- X $return 2
- Xfi
- X
- X# Interactive. List subjects and pick and choose.
- X
- Xif $interactive
- Xthen
- X defaultgroup=news.announce.newusers
- X default=false
- X
- X
- X if test $# -eq 0
- X then
- X set "$defaultgroup"
- X default=true
- X fi
- X
- X if test $silent = false || faq -n "$@"
- X then
- X echo "$@"
- X faq -s $iopt "$@" | tee $temp.s
- X test -s $temp.s || $return 1
- X else
- X $return 1
- X fi
- X
- X if $default
- X then
- X echo "This group ($defaultgroup), contains general introductory"
- X echo "documents. Enter \"number\" to read, \"help\" for help."
- X fi
- X
- X if test ! -t 1; then $return 0; fi
- X
- X while true
- X do
- X echo "faq> " | tr -d "\012" # portable...
- X read faq
- X case $faq in
- X ""|q|quit) break;;
- X \*) faq $iopt "$@"; echo "$@"; cat $temp.s;;
- X h|help|\?) echo 'help, quit or list. (number) to read. * to read all.';;
- X l|list) echo "$@"; cat $temp.s;;
- X *) faq $faq; echo "$@"; cat $temp.s;;
- X esac
- X done
- X $return 0
- Xfi
- X
- Xset -e
- Xcd $answers
- X
- X# Find newest index file (common index if it's writable)
- X
- Xif test -f $index1
- Xthen
- X if test -f $index2
- X then
- X if test -w $index1 -o `ls -td $index1 $index2 | sed 1q` = $index1
- X then
- X rm -f $index2
- X index=$index1
- X else
- X index=$index2
- X fi
- X else
- X index=$index1
- X fi
- Xelse
- X index=$index2
- Xfi
- X
- X# Determine if index is up-to-date
- X
- Xif test ! -f $index || $force
- Xthen
- X ls | grep '^[0-9]*$' | sort -n >$temp.n
- X >$temp.o
- X update=true
- Xelif test `ls -td $index $answers | sed 1q` = $index -a $rescan = false
- Xthen
- X >$temp.n
- X update=false
- Xelse
- X >$temp.n
- X ls | grep '^[0-9]*$' | sort +0n -1 +1n -2 - $index | awk '
- X NF == 1 {if (lastnf==1) print num >"'"$temp.n"'"; lastnf=NF; num=$1}
- X NF != 1 {if ($1 == num) print
- X else if (lastnf==1) print num >"'"$temp.n"'"
- X lastnf=NF}
- X END {if (lastnf==1) print num >"'"$temp.n"'"}' >$temp.o
- X update=true
- Xfi
- X
- X# Do update
- X
- Xif $update
- Xthen
- X if test -t 1
- X then
- X echo "Scanning..." | tr -d "\012" 1>&2
- X termout=true
- X dots=""
- X else
- X termout=false
- X fi
- X
- X if $backup
- X then
- X cp $index $index.old 2>/dev/null || :
- X else
- X rm -f $index.old
- X fi
- X
- X cat $temp.n |
- X while read file
- X do
- X awk '
- X BEGIN {file="'"$file"'"}
- X $1 == "Newsgroups:" {
- X split($2,groups,",")
- X num=1
- X for (i in groups) {
- X if (groups[i] !~ /\.answers$/) print file,num++,groups[i]
- X }
- X if (num==1) {for (i in groups) {print file,num++,groups[i]}}
- X exit
- X }' $file
- X
- X case $termout$dots in
- X true.....) echo "$dots" | tr -d "\012" 1>&2; dots=".";;
- X true*) dots="$dots.";;
- X esac
- X done >>$temp.o
- X
- X if $termout; then echo "$dots" 1>&2; fi
- X
- X if cp $temp.o $index 2>/dev/null
- X then
- X : ok
- X elif cp $temp.o $index2 2>/dev/null
- X then
- X index=$index2 # user copy of index
- X else
- X index=$temp.i # temp index
- X cp $temp.o $index
- X fi
- Xfi
- X
- X# Dump index
- X
- Xif $dump
- Xthen
- X if $pattern
- X then
- X awk '$3 ~ /'"$1"'/' $index
- X elif test $# -ne 0
- X then
- X awk '$3 == "'"$1"'"' $index
- X else
- X cat $index
- X fi
- X $return 0
- Xfi
- X
- X# List groups
- X
- Xif $groups
- Xthen
- X if $crosspost
- X then
- X awk '{if (num==$1) {groups=groups "," $3}
- X else {if (groups!="") print groups; groups=$3}; num=$1}
- X END {if (groups!="") print groups}' $index
- X else
- X awk '{print $3}' $index
- X fi |
- X if $pattern
- X then
- X egrep "$1"
- X else
- X cat
- X fi |
- X if $all
- X then
- X sort
- X elif $count
- X then
- X sort | uniq -c
- X else
- X sort -u
- X fi
- X $return 0
- Xfi
- X
- X# Normal search for group/number/pattern
- X
- Xif $all
- Xthen
- X awk '{print $1}' $index
- Xelse
- X for i
- X do
- X case $i in
- X [0-9]*|*/*)
- X if test -f "$i"
- X then
- X echo "$i"
- X else
- X echo "faq: $i not found" 1>&2~
- X fi;;
- X *) if $pattern
- X then
- X awk '$3 ~ /'"$i"'/ {print $1}' $index
- X else
- X awk '$3 == "'"$i"'" {print $1}' $index
- X fi;;
- X esac
- X done
- Xfi | sort -un >$temp.x
- X
- X# If anything matched, act on it
- X
- Xif test -s $temp.x
- Xthen
- X if $silent
- X then
- X $return 0
- X elif $list
- X then
- X awk '{printf "%s/%s\n","'"$answers"'",$1}' $temp.x
- X elif $subjects
- X then
- X while read file
- X do
- X sed -n '
- X /^Subject:/{s/^Subject: */'"$file:"'/
- X p
- X q
- X }' "$file"
- X done <$temp.x
- X else
- X if $xargs
- X then
- X xargs $pager <$temp.x
- X else
- X awk '{if (num<19) {files= files " " $1; num++}
- X else {print files,$1; files=""; num=0}}
- X END {if (files!="") print files}' $temp.x |
- X while read files
- X do
- X $pager $files
- X done
- X fi
- X fi
- X $return 0
- Xelse
- X if test $silent = false -a $# -ne 0
- X then
- X echo "faq: no faqs found for $*" 1>&2;
- X $return 1
- X elif test $# -ne 0
- X then
- X $return 1
- X else
- X $return 0
- X fi
- Xfi
- SHAR_EOF
- chmod +x 'faq'
- fi # end of overwriting check
- if test -f 'faq.1'
- then
- echo shar: will not over-write existing file "'faq.1'"
- else
- sed 's/^X//' << \SHAR_EOF > 'faq.1'
- X.TH FAQ 1 "22 December 1992"
- X.SH NAME
- Xfaq \- FAQ reader/lister/indexer
- X.SH SYNOPSIS
- X.B faq
- X[
- X.B \-i
- X|
- X.B \-l
- X|
- X.B \-s
- X]
- X{\fB\-p\fP\fI pattern\fR|\fB \-a \fP| {\fIgroup\fR|\fInumber\fR}...}
- X.br
- X.B faq
- X[
- X.B \-g
- X|
- X.B \-c
- X|
- X.B \-x
- X]
- X[
- X.BI \-p " pattern"
- X]
- X[
- X.B \-a
- X]
- X.LP
- X.SH DESCRIPTION
- X.LP
- X.B faq
- Xis a script for reading, listing and indexing FAQs (Frequently Asked
- XQuestions) crossposted to the newsgroup
- X.BR news.answers .
- X.SH OPTIONS
- X.TP
- X.BI \-a
- XThe
- Xcommand either applies to all FAQ postings, or to all groups containing FAQ
- Xpostings.
- X.TP
- X.B \-g
- XList names of all groups that have FAQs. Group names may
- Xbe matched with a pattern using
- X.BR \-p .
- X.TP
- X.B \-l
- XList file names of matching FAQs.
- X.TP
- X.B \-f
- XForce full index rebuild. Use when the database is corrupted.
- X.TP
- X.B \-s
- XList subject lines of matching FAQs.
- X.TP
- X.B \-c
- XDisplay names of groups containing FAQs (optionally matching a pattern
- Xwith \fB\-p\fP).
- XEach name is preceded with the number of FAQs in the group.
- X.TP
- X.B \-i
- XInteractive mode. Lists the subject lines of the matching FAQs and
- Xprompts for which FAQs to read.
- X
- X.B "faq -i"
- Xwithout a group name defaults to the group
- X.BR news.announce.newusers .
- X.TP
- X.BI \-p " pattern"
- XMatch newsgroup pattern (default is exact match on newsgroup name).
- XPatterns use the format of
- X.BR "grep(1)" .
- X.TP
- X.B \-x
- XAs
- X.BR \-g ,
- Xbut list all combinations of crossposted group names (separated by ","),
- Xinstead of only group names.
- X.TP
- X.B \-d
- XDump the updated index file on standard output. Each line in the index
- Xconsists of \fImessage-number crosspost-count newsgroup-name\fR.
- X.TP
- X.B \-n
- XUpdate index file, but give no output. Returns a status of 0
- Xif the specified group (or pattern) matched, otherwise returns a status of 1.
- X
- X.B "faq -n"
- Xwith no parameters updates the index file and returns status 0 if this
- Xsucceeded.
- X.SH EXAMPLES
- X.LP
- XRead the FAQs in \fBnews.group\fR, if any:
- X.IP
- X.B faq
- X.I news.group
- X.LP
- XList groups that have FAQs:
- X.IP
- X.B faq -g
- X.SH FILES
- X.TP
- X.B $HOME/.faq
- XPrivate FAQ index
- X.TP
- X.B /usr/lib/news/faqindex
- XCommon FAQ index.
- X
- X.B Faq
- Xupdates the common FAQ index if its writable. If it is readable,
- Xthe data in it is used. A private index file is created if
- Xthe common index file isn't up-to-date or doesn't exist.
- X.TP
- X.B /usr/spool/news/news/answers
- XDirectory scanned for FAQ postings.
- X.SH BUGS
- X.B faq
- Xonly works when news is kept in a spool directory (commonly
- X\fB/usr/spool/news\fP).
- XIt does not work over NNTP.
- X.PP
- XNot too fast, since it's a shell script. It should be very portable though.
- X.PP
- XNote that the names of the spool directory and library directory
- Xhas to be configured at the beginning of the script if they're
- Xnot the standard
- X.B /usr/spool/news
- Xand
- X.BR /usr/lib/news .
- X.SH AUTHOR
- XBengt Larsson <bengtl@maths.lth.se>
- SHAR_EOF
- fi # end of overwriting check
- # End of shell archive
- exit 0
- --
- Bengt Larsson - bengtl@maths.lth.se
-