#!/bin/sh
# PLEASE SUBMIT BUGS AND REQUESTS AT:
# http://code.google.com/p/vee/issues/list
VERSION=0.9.9-epsilon
#
# vee is a zero configuration, commandline blog tool that
# requires NO installation other than dropping the vee
# script into your ~/bin, or someother directory in your PATH
#
# vee accepts input when in batch mode (-b), so it is well
# suited for use in batch situations, such as in a cronjob
#
# change log
# Applied patch from efbeha@gmail.com:
# added code to keep words whole when using fold
# added code to remove extraneous lines from groff
# made sort options customizable
# made publish date format customizable
disclaimer ()
{ echo "Copyright (c) 2007 /me"
echo "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:"
echo "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software."
echo "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
}
#
# vee - the minimal, zero configuration command line blog thingy
#
# Contact (bugs, patches, suggestions)
# estrabd+vee 'at' gmail
# AIM: bz743
#
# Instructions:
# 1. put in directory accessible via PATH
# 2. go to a web visible directory and type 'vee'
# 3. put in your title and write your post in vi
# 4. tell your mom to visit: http://..../yourdir/vee.html
#
# Tips:
#
# 1 You can force the index to be index.html using "-I", or
# you can specify the index with "-i somefile.html". But,
# if you do this, you'll have to specify this for all other
# commands, otherwise vee defaults to vee.html
#
# 2 vee respects your EDITOR environmental variable
#
# 3 What you do with vee.html or the formatting is up to you :)
#
# CREDITS
# efbeha (efbeha@gmail.com) - supplied first patch ever :)
# Oliver @ forums.bsdnexus.com
# arun @ chat.taucher.net #bsd
# J65nko @ bsdforums.com
if [ ! ${EDITOR} ]; then
EDITOR=vi
fi
FORMAT_FUNC=format_with_groff
MARGIN=64
FORMAT=html
INDEX=vee.html
DIR=.vee
DRAFT=${DIR}/.vee.tmp.$$
DATE=`date`
YEAR=`date "+%Y"`
TIME=`date "+%Y-%m-%dT%H:%M:%S"`
SEC=`date "+%s"`
TITLE=
DEFAULT_TITLE="Entry #${SEC}";
HEADERTXT= # text or `cat some.header.txt`
FOOTERTXT="Powered by vee
Copyright © 2006-${YEAR}"
TOP_TPL=./vee-top.tpl
BOT_TPL=./vee-bottom.tpl
USE_EDITOR=1
LISTENSTDIN=0
SORT_ALL="sort -t. +0f -1 +1nr" # sorts all in file listing
SORT_NEWEST="sort -t. -nr" # sorts all new to old
SORT_OLDEST="sort -t. -r" # sorts all old to new
SORT_INDEX="sort -t; +0f -1 +1nr" # sorts lines in index file based on line number in
PUBLISHED=`date "+%m/%d/%Y"` # date formated for index page entry
# ideas:
# email2groff ... would process stdin to get message, title from email format
# groffXYZ ... process using other groff options
# latex ... not standard, would use pdflatex to generate pdf file
set_format_func ()
{ case "$1" in
default) FORMAT_FUNC=format_with_groff
echo using $FORMAT_FUNC
;;
groff) FORMAT_FUNC=format_with_groff
echo using $FORMAT_FUNC
;;
groff-utf8) FORMAT_FUNC=format_with_groff_utf8
echo using $FORMAT_FUNC
;;
fold) FORMAT_FUNC=format_with_fold
echo using $FORMAT_FUNC
;;
none) FORMAT_FUNC=with_no_formatting
echo using $FORMAT_FUNC
;;
custom) echo "add your own function and list here"
die_cleanly
;;
*) echo "bad format type"
die_cleanly
esac
}
usage ()
{ echo " "
echo " vee - the Zero-conf, commandline blog tool thingy "
echo " "
echo "Version: ${VERSION} "
echo " "
echo "Usage: "
echo " %vee [-c fold_column] [-t title] [-m message] [-b #toggle batchmode] "
echo " "
echo "Options: "
echo " -i 'custom.html' specify a custom index file over the default "
echo " -I force index file to be \"index.html\" "
echo " -d 'publis_dir' specify the directory .vee is in - defaults to PWD "
echo " -t 'title' specify title at commandline and avoid annoying default prompt"
echo " -T file define top template; default is ./vee-top.tpl "
echo " -l edit latest post's *.raw; used with '-r' publishes changes"
echo " -m 'message ...' specify entry message at commandline and avoid vi "
echo " -f 'format' use defined format instead of the default, groff;"
echo " 'groff', 'fold', and 'none' are supported out of the box"
echo " -c [1-9\d*] specify the number of characters 'fold' allows per line "
echo " this only applies when 'fold' (-f) is used "
echo " -b batch mode; used when piping in msg via stdin "
echo " -B file define bottom template; default is ./vee-bottom.tpl "
echo " -n lists all entries, newest first, then quits "
echo " -o lists all entries, oldest first, then quits "
echo " -r reformats the latest post; used in conjuction with -l "
echo " -R reformats _all_ .vee/*.raw files; -c applies as well "
echo " -h prints this blurb "
echo " -v version and exit "
echo " "
echo "Examples: "
echo " "
echo "%vee "
echo " "
echo " user will be prompted for title and presented with vi "
echo " "
echo " if no default dir/files are found, they will be created "
echo " "
echo "%vee -t \"this is the title\" "
echo " "
echo " user will just be presented with a vi session; "
echo " "
echo "%cat text.txt | vee -b -t \"my title\" -m \"text to go before stdin\" "
echo " "
echo " publishes contents of text.txt with provided title; -m's msg will be "
echo " shown above the cat'd text "
echo " "
echo "%vee -lr "
echo " "
echo " brings up the latest entry as a vi sessions; when changes are save, "
echo " all messages are reformatted "
echo " "
echo "Notes: "
echo " "
echo "1. Batch mode looks for piped input via STDIN; if none after a short time, "
echo " message creation fails UNLESS something was passed in via '-m' as well. "
echo " If nothing was passed in via '-t' for the title, some default is used; "
echo " This is set at the top of the script as 'DEFAULT_TITLE'. "
echo " "
echo "2. Interactive mode (default) prompts for a title if no '-t' is provided. "
echo " Such is the case even if '-m' is used. If '-m' is not used in this "
echo " "
echo "3. Patches are welcome; the goal is not more feature bloat, but a nicer "
echo " way of dealing with standard in, etc would be welcomed. "
echo " "
echo `disclaimer`
echo " "
echo "(press 'q' for commandline) "
exit 1
}
output_top ()
{ echo ${HEADERTXT} > ${FINAL}
if [ -e "${TOP_TPL}" ]; then
cat "${TOP_TPL}" >> ${FINAL}
echo "
" >> ${FINAL}
else
echo "" >> ${FINAL}
echo "" >> ${FINAL}
echo "${TITLE} - ${DATE} " >> ${FINAL}
echo "" >> ${FINAL}
echo "" >> ${FINAL}
echo "[index][raw][main]" >> ${FINAL}
fi
echo >> ${FINAL}
}
output_bottom ()
{ echo >> ${FINAL}
echo -- >> ${FINAL}
echo ${FOOTERTXT} >> ${FINAL}
if [ -e "${BOT_TPL}" ]; then
cat "${BOT_TPL}" >> ${FINAL}
else
echo "" >> ${FINAL}
echo "" >> ${FINAL}
echo "" >> ${FINAL}
fi
}
# begin formatting funcs
format_with_groff ()
{ #sed 1liner from http://sed.sourceforge.net/sed1line.txt
groff -man -Tascii ${RAW} >> bla.raw
sed '/^$/N;/\n$/D' bla.raw >> ${FINAL}
rm bla.raw
# groff -man -Tascii ${RAW} >> ${FINAL}
}
format_with_groff_utf8 ()
{ #sed 1liner from http://sed.sourceforge.net/sed1line.txt
exe=`which groff-utf8 2> /dev/null || echo -1`
if [ "-1" != ${exe} ]; then
groff-utf8 -man -Tutf8 ${RAW} >> bla.raw
sed '/^$/N;/\n$/D' bla.raw >> ${FINAL}
rm bla.raw
else
echo "Warning: groff-utf8 not found, falling back to format_with_groff"
format_with_groff
fi
}
with_no_formatting ()
{ cat ${RAW} >> ${FINAL}
}
format_with_fold ()
{ if [ 0 -lt "${MARGIN}" ]; then
fold -s -w ${MARGIN} ${RAW} >> ${FINAL}
else
with_no_formatting
fi
}
# end formatting funcs
format_main ()
{ FINAL=${DIR}/${1}
FINALNAME=${1}
RAW=${DIR}/${2}
RAWNAME=${2}
# save raw form before formatting if it doesn't exist
# which is the case when reformatting all
if [ ! -e ${RAW} ]; then
echo ${DATE} > ${RAW} # in RAW, line 1 is date
echo >> ${RAW}
echo ${TITLE} >> ${RAW} # in RAW, line 2 is title
echo >> ${RAW}
echo "--" >> ${RAW}
echo >> ${RAW} # this blank line is important
cat ${DRAFT} >> ${RAW}
fi
output_top
${FORMAT_FUNC}
output_bottom
}
reformat_singleton ()
{ if [ -e "${DIR}/${1}.raw" ]; then
echo "Reformatting message: \"${1}\""
cat "${DIR}/${1}.raw" > "${DRAFT}"
format_main "${1}.${FORMAT}" "${1}.raw"
fi
}
reformat_all ()
{ FILES=`ls -c ${DIR}/*.raw | ${SORT_ALL}`
for RAW in $FILES; do
# From: Randall R Schulz
FULLNAME="${RAW}"
DIR="${FULLNAME%/*}"
FILE="${FULLNAME##*/}"
MAXBASE="${FILE%.*}"
MINBASE="${FILE%%.*}"
MAXSUF="${FILE#*.}"
MINSUF="${FILE##*.}"
reformat_singleton "${MAXBASE}"
done
}
newest_first ()
{ FILES=`ls -c ${DIR}/*.raw | ${SORT_NEWEST}`
echo ${FILES}
}
list_newest_first ()
{ FILES=`newest_first`
for FILE in ${FILES}; do
FULLNAME="${FILE}"
DIR="${FULLNAME%/*}"
FILE="${FULLNAME##*/}"
MAXBASE="${FILE%.*}"
echo ${MAXBASE}
done
}
oldest_first ()
{ FILES=`ls -c ${DIR}/*.raw | ${SORT_OLDEST}`
echo ${FILES}
}
list_oldest_first ()
{ FILES=`oldest_first`
for FILE in ${FILES}; do
FULLNAME="${FILE}"
DIR="${FULLNAME%/*}"
FILE="${FULLNAME##*/}"
MAXBASE="${FILE%.*}"
echo ${MAXBASE}
done
}
# would like to make this so that user can request
# a msg relative to the last; example:
# vee -l2 -r ..... this would open up 2 entries
# back from the current; vee -l 1 -r would open up
# the one right before the latest, etc
get_latest () # gets *just* the latest one for now
{ FILES=`ls -c ${DIR}/*.raw | ${SORT_NEWEST}`
for FILE in ${FILES}; do
FULLNAME="${FILE}"
DIR="${FULLNAME%/*}"
FILE="${FULLNAME##*/}"
MAXBASE="${FILE%.*}"
echo ${MAXBASE}
break
done
}
die_cleanly ()
{ if [ -e ${DRAFT} ]; then
rm -f ${DRAFT}
fi
exit 0
}
REFORMATLAST=0
REFORMATALL=0
EDITLAST=0
MESSAGE=
# get opts ! stdin append to anything passed in by -m
while getopts 'f:m:t:T:c:d:i:IbB:hRrlnov' option; do
case "$option" in
i) INDEX="${OPTARG}" # specify INDEX to $OPTARG
;;
I) INDEX="index.html" # force INDEX to index.html
;;
d) if [ -d "${OPTARG}" ]; then
cd "${OPTARG}"
else
echo "${OPTARG}" is not a directory!
die_cleanly
fi
echo `pwd`
;;
r) REFORMATLAST=1
;;
R) REFORMATALL=1
;;
b) LISTENSTDIN=1
USE_EDITOR=0
;;
B) BOT_TPL="${OPTARG}"
;;
f) set_format_func "${OPTARG}"
;;
c) MARGIN=${OPTARG}
;;
l) EDITLAST=1
;;
m) MESSAGE="${OPTARG}"
USE_EDITOR=0
;;
n) list_newest_first
die_cleanly
;;
o) list_oldest_first
die_cleanly
;;
t) TITLE=${OPTARG}
;;
T) TOP_TPL="${OPTARG}"
;;
v) echo $VERSION
die_cleanly
;;
h) usage | less
die_cleanly
;;
?) usage | less
die_cleanly
;;
esac
done
post_opts ()
{ if [ ${EDITLAST} -eq 1 ]; then
LATEST=`get_latest`
${EDITOR} ${DIR}/${LATEST}.raw
echo "Updated: ${LATEST} (remember to reformat)"
fi
if [ ${REFORMATLAST} -eq 1 ]; then
LATEST=`get_latest`
reformat_singleton "${LATEST}"
die_cleanly
fi
# if "-R", or reformat all, is set
if [ ${REFORMATALL} -eq 1 ]; then
# future may yield seperate "rebuild reindex" functionality
reformat_all
die_cleanly
fi
# blocks vee -l (without the -r) from going on
if [ ${EDITLAST} -eq 1 ]; then
die_cleanly
fi
# Batch message creation: -m and stdin
# handles -m
if [ -n "${MESSAGE}" ]; then
echo "${MESSAGE}" >> ${DRAFT}
fi
if [ ${LISTENSTDIN} -eq 1 ]; then
IFS="" # ensures that leading spaces are retained
while read -r IN <&0 ; do # break after 1 sec of no stdin
echo "${IN}" # echo's stdin back out so user can see
echo "${IN}" >> ${DRAFT}
LISTENSTDIN=1
USE_EDITOR=0
done
fi
}
# generates INDEX file if none exists
setup ()
{ mkdir -p ${DIR} || echo ${DIR} exists...
if [ ! -e ${INDEX} ]; then
echo
echo "...creating ${INDEX}"
echo "my vee index " >> ${INDEX}
echo "" >> ${INDEX}
# header stuff
echo "" >> ${INDEX}
echo "" >> ${INDEX}
echo "" >> ${INDEX}
# footer stuff
echo "" >> ${INDEX}
echo "" >> ${INDEX}
echo "Powered by vee" >> ${INDEX}
echo "" >> ${INDEX}
echo
fi
}
sort_index ()
{ #echo sorting ${INDEX} ...
#sort -t";" +0f -1 +1nr ${INDEX} > .${INDEX}.$$.sorted
${SORT_INDEX} ${INDEX} > .${INDEX}.$$.sorted
#echo rebuilding ${INDEX}
mv .${INDEX}.$$.sorted ${INDEX} # "rebuild ${INDEX}
}
use_editor ()
{ if [ ${USE_EDITOR} -eq 1 ]; then
OK=0
${EDITOR} ${DRAFT} && OK=1
if [ $OK -ne 1 ]; then
echo there has been a problem with your editor session
exit
fi
#else
#echo ...vi mode off
fi
}
update_index ()
{ echo "${SEC}: ${TITLE} ... ${PUBLISHED}" >> ${INDEX}
sort_index
}
# ask for title if not set with -t and not in batch mode
# if in batch mode with no -t set, use default title below
get_title ()
{ if [ -z "${TITLE}" ]; then
TITLE=$DEFAULT_TITLE
fi
}
read_config ()
{ if [ -e ./.veerc ]; then
. ./.veerc
fi
}
# Main program body
read_config # done after all options are read in, could look in -d before
# opts are processed though so opts could override defaults
# and config file .. yeah do that
post_opts
setup
get_title
use_editor
if [ -e ${DRAFT} ]; then
format_main "${SEC}.${TIME}.${FORMAT}" "${SEC}.${TIME}.raw"
update_index
die_cleanly
else
echo Error! ${DRAFT} not found
fi