home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume40 / plod / part01 < prev    next >
Encoding:
Text File  |  1993-11-02  |  43.2 KB  |  1,404 lines

  1. Newsgroups: comp.sources.misc
  2. From: pomeranz@aqm.com (Hal Pomeranz)
  3. Subject: v40i083:  plod - keep track of the work you do, Part01/01
  4. Message-ID: <1993Nov2.234638.8003@sparky.sterling.com>
  5. Summary: Personal logging software
  6. X-Md4-Signature: d0f8a56c2dcd3d19998116a1a9edd94e
  7. Keywords: updated software
  8. Sender: kent@sparky.sterling.com (Kent Landfield)
  9. Organization: QMS Inc., Imagen Division
  10. Date: Tue, 2 Nov 1993 23:46:38 GMT
  11. Approved: kent@sparky.sterling.com
  12.  
  13. Submitted-by: pomeranz@aqm.com (Hal Pomeranz)
  14. Posting-number: Volume 40, Issue 83
  15. Archive-name: plod/part01
  16. Environment: Perl
  17. Supersedes: plod: Volume 35, Issue 85
  18.  
  19. PLOD is a Perl program designed to help folks keep a record of the
  20. work they do.  Good journals help you solve recurring problems more
  21. quickly and impress the hell out of management around performance
  22. review time.
  23.  
  24. The interface for PLOD looks a lot like Berkeley mail (tilde escapes
  25. and all).  There's tons of customization switches, so check out
  26. the documentation.  
  27.  
  28. This version contains some enhancements based on feedback I received from 
  29. the initial release, as well as a couple of Emacs modes for PLOD.  
  30.  
  31. Hal Pomeranz
  32. ------
  33. #! /bin/sh
  34. # This is a shell archive.  Remove anything before this line, then feed it
  35. # into a shell via "sh file" or similar.  To overwrite existing files,
  36. # type "sh file -c".
  37. # Contents:  README plod plod.el.v1 plod.el.v2 plod.man
  38. # Wrapped by kent@sparky on Tue Nov  2 17:39:16 1993
  39. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  40. echo If this archive is complete, you will see the following message:
  41. echo '          "shar: End of archive 1 (of 1)."'
  42. if test -f 'README' -a "${1}" != "-c" ; then 
  43.   echo shar: Will not clobber existing file \"'README'\"
  44. else
  45.   echo shar: Extracting \"'README'\" \(4069 characters\)
  46.   sed "s/^X//" >'README' <<'END_OF_FILE'
  47. XPLOD is a tool designed to help administrators (and others) keep track
  48. Xof their daily activities.  Since your management will typically have
  49. Xno idea what you are doing to justify such an exorbitant salary (any
  50. Xamount of money they may be paying you being classified as
  51. X"exorbitant"), and since most people forget what they do themselves,
  52. Xit's good to keep a record.  Trot your logs out around performance
  53. Xreview time, and show them to your management (after suitable
  54. Xsanitization) on a regular basis.
  55. X
  56. XThe interface is designed to make it quick to dash off a simple note
  57. Xto yourself.  Since most folks who are going to use PLOD also use
  58. Xemail, I've based the interface on Berkeley mail-- tilde escapes and
  59. Xall (for a list of escapes, try ~h or ~?).  By default, your logs will
  60. Xbe encrypted using the /bin/crypt command-- not secure in the least,
  61. Xbut marginally safe from casual browsing (I tend to vent into my logs
  62. Xsometimes rather than at those who might be offended and fire me).
  63. XYou can turn off the encryption if you find it more a hassle than a
  64. Xcomfort.
  65. X
  66. XWhich brings us to the subject of customization.  Many escape
  67. Xsequences and variables have already been defined, but you can make
  68. Xyour own changes using your ~/.plodrc file.  This file is interpreted
  69. Xusing eval(), so any valid Perl syntax is acceptable.  Variables may
  70. Xbe customized by editing this script directly, setting an environment
  71. Xvariable with the same name as the PLOD variable, or by doing an
  72. Xassignment in your .plodrc (.plodrc value supersedes environment value
  73. Xwhich beats default value in script).  New tilde escapes may be
  74. Xdefined by assigning a type glob, say *foo, to the global array
  75. X%funcs-- the index of the type glob in the array being the character
  76. X(single chars only!) of the escape sequence.  &foo should be a
  77. Xfunction which performs the escape (any arguments after the escape are
  78. Xpassed in as a single string in @_), and $foo can be a descriptive
  79. Xhelp string (see &helpuser()).  Your functions may reference any of
  80. Xthe PLOD customization variables as well as the list @lines, which
  81. Xcontains all information in the current log entry (including the
  82. Xdate/time stamp PLOD adds to the beginning of each entry).  For
  83. Xexamples, consult the PLOD source code or the manual page.
  84. X
  85. XPLOD is a living, growing entity.  If you have suggestions for
  86. Ximprovements or new features, or find any bugs, please send them to me
  87. Xvia email.  Share and enjoy!
  88. X
  89. XHal Pomeranz, pomeranz@aqm.com
  90. X
  91. X===============================================================================
  92. X
  93. XHistory:
  94. X
  95. Xv1.0 (Original release to comp.lang.perl)
  96. X
  97. X
  98. Xv1.1 (Second release to comp.lang.perl)
  99. X** &pipetocmd() unlinks all temporary files it creates (Pomeranz)
  100. X
  101. X** Variable assignment idiom cleaned up (Rantapaa)
  102. X
  103. X** LOGDIR and HOME are only prepended to LOGFILE and DEADLOG after
  104. X   .plodrc has been eval-ed and if LOGFILE and DEADLOG are relative
  105. X   paths.  This means that you can change LOGDIR in your .plodrc and
  106. X   really affect where the log files go. (Rantapaa)
  107. X
  108. X** eval of .plodrc is done with "do" rather than "cat" (Rantapaa)
  109. X
  110. X** You can now do quick one-liner entries on the command line, e.g.
  111. X   "plod Completed modifications to PLOD" (Rantapaa)
  112. X
  113. X** Time/date stamp only printed if user is entering info directly from
  114. X   a tty (Rantapaa)
  115. X
  116. X** PLOD attempts to create logging directory if it does not exist (Ellis)
  117. X
  118. X
  119. Xv1.2 (not publicly released)
  120. X** Page/Edit/Visual log files from interactive mode or from the shell
  121. X   (Tizard)
  122. X
  123. X
  124. Xv1.3 (comp.lang.perl again, and also comp.sources.misc)
  125. X** Multi-line Perl input function, ~M (Crabb)
  126. X
  127. X** Manual page generated (Pomeranz)
  128. X
  129. X
  130. Xv1.4 (not publicly released)
  131. X** Trap for empty log entries and don't add them to log file (Pomeranz)
  132. X
  133. X** -C flag to cat logfile to STDOUT (Prestemon)
  134. X
  135. X** /etc/plodrc (Lachowski)
  136. X
  137. X** $STAMP customization variable (Lachowski/Pomeranz)
  138. X
  139. X
  140. Xv1.5 (not publicly released)
  141. X** Trap for non-existant/zero size/non-executable CRYPTCMD
  142. X
  143. X
  144. Xv1.6 (current)
  145. X** Minor fix to above trap.  Would have been part of v1.5 but I had already
  146. X   distributed v1.5 to a few people.
  147. END_OF_FILE
  148.   if test 4069 -ne `wc -c <'README'`; then
  149.     echo shar: \"'README'\" unpacked with wrong size!
  150.   fi
  151.   # end of 'README'
  152. fi
  153. if test -f 'plod' -a "${1}" != "-c" ; then 
  154.   echo shar: Will not clobber existing file \"'plod'\"
  155. else
  156.   echo shar: Extracting \"'plod'\" \(16947 characters\)
  157.   sed "s/^X//" >'plod' <<'END_OF_FILE'
  158. X#!/usr/local/bin/perl
  159. X#
  160. X#    PLOD-- Personal LOgging Device, v1.6
  161. X#    Copyright (C), 1993, Hal Pomeranz (pomeranz@aqm.com)
  162. X#    All rights reserved.  No warranty expressed or implied.
  163. X#    PLOD is freely distributable under the same terms as Perl.
  164. X#    Inspired by Bill Mendyka (mendyka@dg-rtp.dg.com)
  165. X#    Suggestions/Bugfixes: 
  166. X#    David W Crabb (crabb@phoenix.Princeton.EDU)
  167. X#    John Ellis (ellis@rtsg.mot.com)
  168. X#    Mike Lachowski (mlachow@erenj.com)
  169. X#    Eric Prestemon (ecprest@pocorvares.er.usgs.GOV)
  170. X#    Erik E. Rantapaa (rantapaa@math.umn.edu)
  171. X#    James Tizard (james@ringo.ssn.flinders.edu.au)
  172. X#
  173. X######################### Begin Variable Declarations #########################
  174. X#
  175. X# All variables have default values which will be superceded by environment
  176. X# variables of the same name.  The user's .plodrc is read after all other
  177. X# variable assignments, so any assignments there take precedence.
  178. X#
  179. X# Note that $LOGFILE and $DEADLOG are used as absolute pathnames.  After
  180. X# the .plodrc has been evaluated, $LOGDIR or $HOME will be prepended to
  181. X# $LOGFILE and $DEADLOG respectively if either of these variables does not
  182. X# begin with a '/'.
  183. X#
  184. X# Set $CRYPTCMD to null if you don't want encryption to be performed.
  185. X#
  186. X# KEYVAL    key value used by CRYPTCMD
  187. X# CRYPTCMD    encryption command, set this to null for no encryption
  188. X# TMPFILE    file name to use for temporary holding
  189. X# EDITOR    editor called by ~e
  190. X# VISUAL    editor called by ~v
  191. X# PAGER         used by ~p and ~h when output longer than one page (see LINES)
  192. X# LINES        number of lines on the screen
  193. X# LOGDIR    directory containing log files
  194. X# LOGFILE    absolute path of log file
  195. X# HOME        user's home directory
  196. X# DEADLOG    place to drop dead.log file on abort or ~q, also used by ~d
  197. X# STAMP        time/date stamp printed at the top of each entry
  198. X
  199. X# Some variable values use date/time information
  200. X#
  201. X($ss, $mm, $hh, $DD, $MM, $YY) = localtime($^T); $MM++; 
  202. X
  203. X$KEYVAL = sprintf("pl%d%dod", $YY, $MM);
  204. X$CRYPTCMD = "/bin/crypt";
  205. X$TMPFILE = "/tmp/plodtmp$$";
  206. X$HOME = (getpwuid($<))[7];
  207. X$EDITOR = "/usr/local/bin/emacs";
  208. X$VISUAL = "/usr/local/bin/emacs";
  209. X$PAGER =  "/usr/local/bin/less";
  210. X$LINES = 24;
  211. X$LOGDIR = "$HOME/.logdir";
  212. X$LOGFILE = sprintf("%02d%02d", $YY, $MM);
  213. X$DEADLOG = "dead.log";
  214. X$STAMP = sprintf("%02d/%02d/%02d, %02d:%02d --", $MM, $DD, $YY, $hh, $mm);
  215. X
  216. X
  217. X########################## End Variable Declarations ##########################
  218. X######################### Begin Function Declarations #########################
  219. X
  220. X
  221. X# Printvar (~=): Output the value of one or more variables.
  222. X#
  223. Xsub printvar {
  224. X   local($vars) = @_;
  225. X   $, = ','; print eval "($vars)"; $, = '';
  226. X   print "\n";
  227. X   print "(continue composing note)\n";
  228. X}
  229. X$printvar = "\$var[, ...]\tOutput value of variables";
  230. X$funcs{'='} = *printvar;
  231. X
  232. X
  233. X# Bang (~!): Execute a command in the shell and then return to plod.
  234. X#
  235. Xsub bang {
  236. X   local($cmdline) = @_;
  237. X   system "$cmdline";
  238. X   print "(continue composing note)\n";
  239. X}
  240. X$bang = "cmdline\tExecute system command and return";
  241. X$funcs{'!'} = *bang;
  242. X
  243. X
  244. X# Redirect (~>): Pipe the output of a command into the current buffer.
  245. X#
  246. Xsub redirect {
  247. X   local($cmdline) = @_;
  248. X   local($count);
  249. X   if (!open(CMD, "$cmdline |")) {
  250. X      warn "*** Unable to execute: $cmdline\n";
  251. X      return;
  252. X   }
  253. X   &readit(CMD);
  254. X}
  255. X$redirect = "cmdline\tAdd output of given command to buffer";
  256. X$funcs{'>'} = *redirect;
  257. X
  258. X
  259. X# Pipetocmd (~|): Pipe the contents of the current buffer through a UNIX
  260. X# command line and replace the buffer with the result.
  261. X#
  262. Xsub pipetocmd {
  263. X   local($cmdline) = @_;
  264. X   local($header);
  265. X   if (!open(PIPELN, "| $cmdline >$TMPFILE 2>&1")) {    # output to tmp file
  266. X      warn "*** Unable to execute: $cmdline\n";
  267. X      return;
  268. X   }
  269. X   $header = shift @lines if ($STAMP);            # don't include stamp
  270. X   print PIPELN @lines;
  271. X   close(PIPELN);
  272. X   if (!open(INP, "<$TMPFILE")) {
  273. X      warn "*** Unable to get command output\n";
  274. X      unshift(@lines, $header);
  275. X      unlink "$TMPFILE";
  276. X      return;
  277. X   }
  278. X   undef @lines;                    # replace buffer with
  279. X   @lines = <INP>;                    # contents of tmp file
  280. X   close(INP);
  281. X   unlink "$TMPFILE";
  282. X   unshift(@lines, $header) if ($STAMP);
  283. X   print "(continue composing note)\n";   
  284. X}
  285. X$pipetocmd = "cmdline\tPipe contents of buffer through cmdline";
  286. X$funcs{'|'} = *pipetocmd;
  287. X
  288. X
  289. X# Perlit (~X): Execute Perl code.
  290. X#
  291. Xsub perlit {
  292. X   local($code) = @_;
  293. X   eval "$code";
  294. X   warn $@ if $@;
  295. X   print "(continue composing note)\n";   
  296. X}
  297. X$perlit = "code\t\tExecute a line of Perl code";
  298. X$funcs{'X'} = *perlit;
  299. X
  300. X
  301. X# Longperl (~M): Edit then eval a multi-line Perl fragment
  302. X#
  303. Xsub longperl {
  304. X   local($bogus) = @_;
  305. X   return(&mistake) if ($bogus);
  306. X   if (@code) {
  307. X      if (!open(TMP, "> $TMPFILE")) {
  308. X         warn "*** Unable to create temporary file\n";
  309. X         return;
  310. X      }
  311. X      print TMP @code;
  312. X      close(TMP);
  313. X   }
  314. X   system("$EDITOR $TMPFILE");
  315. X   if (!open(TMP, "< $TMPFILE")) {
  316. X      warn "*** Unable to read buffer\n";
  317. X      return;
  318. X   }
  319. X   undef @code;
  320. X   @code = <TMP>;
  321. X   close(TMP);
  322. X   system("/bin/rm -f $TMPFILE*");
  323. X   eval "@code";
  324. X   warn $@ if $@;
  325. X   print "(continue composing note)\n";   
  326. X}
  327. X$longperl = "\t\tInvoke \$EDITOR on command buffer, then execute as Perl code";
  328. X$funcs{'M'} = *longperl;
  329. X
  330. X
  331. X# Appendfl (~a): Append contents of buffer to a file and return to plod.
  332. X# To overwrite a file with the contents of the buffer, see &writefl().
  333. X#
  334. Xsub appendfl {
  335. X   local($file) = @_;
  336. X   if (!open(OUTP, ">> $file")) {
  337. X      warn "*** Could not append to file $file\n";
  338. X      return;
  339. X   }
  340. X   print OUTP @lines;
  341. X   close(OUTP);
  342. X   print "Wrote ", scalar(@lines), " lines to file $file\n";
  343. X   print "(continue composing note)\n";
  344. X}
  345. X$appendfl = "file\t\tAppend contents of buffer to file";
  346. X$funcs{'a'} = *appendfl;
  347. X
  348. X
  349. X# Getdead (~d): Suck contents of DEADLOG file into buffer.
  350. X#
  351. Xsub getdead {
  352. X   local($bogus) = @_;
  353. X   return(&mistake) if ($bogus);
  354. X   if (!open(DEAD, "<$DEADLOG")) {
  355. X      warn "*** Unable to open $home/dead.log.\n";
  356. X      return;
  357. X   }
  358. X   &readit(DEAD, "$DEADLOG");
  359. X}
  360. X$getdead = "\t\tIncorporate contents of \$DEADLOG into buffer";
  361. X$funcs{'d'} = *getdead;
  362. X
  363. X
  364. X# Editbuf (~e) and Visualbuf (~v): Call appropriate editor on buffer.
  365. X#
  366. Xsub editbuf {
  367. X   local($bogus) = @_;
  368. X   return(&mistake) if ($bogus);
  369. X   &calledit($EDITOR);
  370. X}
  371. Xsub visualbuf {
  372. X   local($bogus) = @_;
  373. X   return(&mistake) if ($bogus);
  374. X   &calledit($VISUAL);
  375. X}
  376. X$editbuf = "\t\tEdit buffer with \$EDITOR";
  377. X$visualbuf = "\t\tEdit buffer with \$VISUAL";
  378. X$funcs{'e'} = *editbuf;
  379. X$funcs{'v'} = *visualbuf;
  380. X
  381. X
  382. X# Editlog (~E) and Visuallog (~V): Call appropriate editor on LOGFILE.
  383. X#
  384. Xsub editlog {
  385. X   local($args) = @_;
  386. X   &logedit($EDITOR, $args);
  387. X   print "(continue composing note)\n";
  388. X}
  389. Xsub visuallog {
  390. X   local($args) = @_;
  391. X   &logedit($VISUAL, $args);
  392. X   print "(continue composing note)\n";
  393. X}
  394. X$editlog = "[file [key]]\tEdit LOGFILE [or older log] with \$EDITOR";
  395. X$visuallog = "[file [key]]\tEdit LOGFILE [or older log] with \$VISUAL";
  396. X$funcs{'E'} = *editlog;
  397. X$funcs{'l'} = *editlog;
  398. X$funcs{'V'} = *visuallog;
  399. X
  400. X
  401. X# Helpuser (~h or ~?): Output a list of tilde escapes with associated
  402. X# help messages (found in the scalar values of the type globs in %funcs).
  403. X# Use the defined PAGER if the output would be more than LINES long.
  404. X#
  405. Xsub helpuser {
  406. X   $long = (scalar(keys %funcs) >= $LINES) && open(TMP, ">$TMPFILE");
  407. X   for (sort keys %funcs) {
  408. X      *info = $funcs{$_};
  409. X      if ($long) {
  410. X         print TMP "~$_ $info\n";
  411. X      }
  412. X      else { print "~$_ $info\n"; }
  413. X   }
  414. X   if ($long) {
  415. X      close(TMP);
  416. X      system("/bin/cat $TMPFILE | $PAGER");
  417. X      unlink "$TMPFILE";
  418. X   }
  419. X}
  420. X$helpuser = "\t\tPrint this message";
  421. X$funcs{'h'} = *helpuser;
  422. X$funcs{'?'} = *helpuser;
  423. X
  424. X
  425. X# Printout (~p):  cat back the current buffer for review.  Use PAGER if
  426. X# the buffer is longer than LINES.
  427. X#
  428. Xsub printout {
  429. X   local($bogus) = @_;
  430. X   return(&mistake) if ($bogus);
  431. X   if (@lines < $LINES-1 || !open(TMP, ">$TMPFILE")) {
  432. X      print "-----\n";
  433. X      print @lines;
  434. X   }
  435. X   else {
  436. X      print TMP @lines;
  437. X      close(TMP);
  438. X      system("/bin/cat $TMPFILE | $PAGER");
  439. X      unlink "$TMPFILE";
  440. X   }
  441. X   print "(continue composing note)\n";
  442. X}
  443. X$printout = "\t\tView contents of buffer, one page at a time";
  444. X$funcs{'p'} = *printout;
  445. X
  446. X
  447. X# Pagelog (~P): Page contents of LOGFILE.
  448. X#
  449. Xsub pagelog {
  450. X   local($args) = @_;
  451. X   &pageit($args);
  452. X   print "(continue composing note)\n";
  453. X}
  454. X$pagelog = "[file [key]]\tView contents of LOGFILE [or older log] with PAGER";
  455. X$funcs{'P'} = *pagelog;
  456. X$funcs{'L'} = *pagelog;
  457. X
  458. X
  459. X# Quitit (~q): Quit plod and attempt to save buffer in DEADLOG.  Also
  460. X# called on SIGINT and SIGQUIT via &trapit().
  461. X#
  462. Xsub quitit {
  463. X   local($bogus) = @_;
  464. X   return(&mistake) if ($bogus);
  465. X   open(DEAD, ">> $DEADLOG") || die "Can't open $DEADLOG\n";
  466. X   print DEAD @lines;
  467. X   close(DEAD);
  468. X   exit;
  469. X}
  470. X$quitit = "\t\tQuit, attempts to save buffer in \$DEADLOG";
  471. X$funcs{'q'} = *quitit;
  472. X
  473. X
  474. X# Readfile (~r): Append contents of file into buffer.
  475. X#
  476. Xsub readfile {
  477. X   local($file) = @_;
  478. X   if (!open(INPT, "<$file")) {
  479. X      warn "*** Unable to open $file.\n";
  480. X      return;
  481. X   }
  482. X   &readit(INPT, $file);
  483. X}
  484. X$readfile = "file\t\tRead contents of file into buffer";
  485. X$funcs{'r'} = *readfile;
  486. X
  487. X
  488. X# Writefl (~w): Overwrite file with contents of buffer.  To append to a
  489. X# given file, see &appendfl().
  490. X#
  491. Xsub writefl {
  492. X   local($file) = @_;
  493. X   if (!open(OUTP, "> $file")) {
  494. X      warn "*** Could not write to file $file\n";
  495. X      return;
  496. X   }
  497. X   print OUTP @lines;
  498. X   close(OUTP);
  499. X   print "Wrote ", scalar(@lines), " lines to file $file\n";
  500. X   print "(continue composing note)\n";
  501. X}
  502. X$writefl = "file\t\tOverwrite file with contents of buffer";
  503. X$funcs{'w'} = *writefl;
  504. X
  505. X
  506. X# Exitnow (~x): Exit plod without writing to DEADLOG or LOGFILE.
  507. X#
  508. Xsub exitnow {
  509. X   local($bogus) = @_;
  510. X   return(&mistake) if ($bogus);
  511. X   exit;
  512. X}
  513. X$exitnow = "\t\tExit without saving buffer";
  514. X$funcs{'x'} = *exitnow;
  515. X
  516. X
  517. X########################## End Function Declarations ##########################
  518. X############################# Begin Main Program ##############################
  519. X
  520. X
  521. X# Check for /etc/plodrc and ~/.plodrc and eval() contents.  Exit with an
  522. X# error message if eval() complains for any reason.  Environment supercedes
  523. X# /etc/plodrc but is overridden by ~/.plodrc.
  524. X#
  525. Xif (-e "/etc/plodrc") {
  526. X   eval { do "/etc/plodrc"; };
  527. X   die "*** Error in /etc/plodrc:\n$@" if $@;
  528. X}
  529. X
  530. X$CRYPTCMD = $ENV{'CRYPTCMD'} if (defined($ENV{'CRYPTCMD'}));
  531. X$DEADLOG = $ENV{'DEADLOG'} if ($ENV{'DEADLOG'});
  532. X$EDITOR = $ENV{'EDITOR'} if ($ENV{'EDITOR'});
  533. X$HOME = $ENV{'HOME'} if ($ENV{'HOME'});
  534. X$KEYVAL = $ENV{'KEYVAL'} if ($ENV{'KEYVAL'});
  535. X$LINES = $ENV{'LINES'} if ($ENV{'LINES'});
  536. X$LOGDIR = $ENV{'LOGDIR'} if ($ENV{'LOGDIR'});
  537. X$LOGFILE = $ENV{'LOGFILE'} if ($ENV{'LOGFILE'});
  538. X$PAGER = $ENV{'PAGER'} if ($ENV{'PAGER'});
  539. X$STAMP = $ENV{'STAMP'} if (defined($ENV{'STAMP'}));
  540. X$TMPFILE = $ENV{'TMPFILE'}if ($ENV{'TMPFILE'});
  541. X$VISUAL = $ENV{'VISUAL'} if ($ENV{'VISUAL'});
  542. X
  543. Xif (-e "$HOME/.plodrc") {
  544. X   eval { do "$HOME/.plodrc"; };
  545. X   die "*** Error in $HOME/.plodrc:\n$@" if $@;
  546. X}
  547. X
  548. X# You can lose your log file if CRYPTCMD is set, but the executable
  549. X# doesn't actually exist.
  550. X#
  551. Xdie "There's something wrong with $CRYPTCMD-- I can't deal!\n"
  552. X  if ($CRYPTCMD && !(-e "$CRYPTCMD" && -x _ && -f _ && -s _));
  553. X
  554. X# Prepend parent directories unless we have explicit pathnames
  555. X#
  556. X$LOGFILE = "$LOGDIR/$LOGFILE" unless ($LOGFILE =~ /^\//);
  557. X$DEADLOG = "$HOME/$DEADLOG" unless ($DEADLOG =~ /^\//);
  558. X
  559. X# Extract dirname from $LOGFILE and make sure it exists
  560. X#
  561. X($dirname = $LOGFILE) =~ s,/[^/]*$,,;
  562. Xif (!(-d $dirname)) {
  563. X   warn "Attempting to create logging directory, $dirname\n";
  564. X   die "Attempt failed!\n" unless (mkdir($dirname, 0700));
  565. X}
  566. X
  567. X# Jam time/date stamp into buffer...
  568. X#
  569. Xpush(@lines, "$STAMP\n") if ($STAMP);
  570. X
  571. X# Log entry can appear on the command line, otherwise loop until end of
  572. X# STDIN or '.' recognized on a line by itself.
  573. X#
  574. Xif ($ARGV[0] eq "-P") { shift @ARGV; &pageit("@ARGV"); exit; }
  575. Xelsif ($ARGV[0] eq "-E") { shift @ARGV; &logedit($EDITOR, "@ARGV"); exit; }
  576. Xelsif ($ARGV[0] eq "-V") { shift @ARGV; &logedit($VISUAL, "@ARGV"); exit; }
  577. Xelsif ($ARGV[0] eq "-C") {
  578. X   shift @ARGV;
  579. X   $file = (shift @ARGV) || $LOGFILE;
  580. X   $file = "$LOGDIR/$file" unless ($file =~ /^\//);
  581. X   $key = (shift @ARGV) || $KEYVAL;
  582. X   $cmd = $CRYPTCMD ? "$CRYPTCMD $key < $file" : "/bin/cat $file";
  583. X   system("$cmd");
  584. X   exit;
  585. X}
  586. Xelsif (@ARGV) { push(@lines, "@ARGV\n"); }
  587. Xelse {
  588. X   if (-t STDIN) {
  589. X      print "$STAMP\n" if ($STAMP);
  590. X      $SIG{'QUIT'} = trapit;
  591. X      $SIG{'INT'} = trapit;
  592. X   }
  593. X   while (<STDIN>) {
  594. X      if (/^~/) {                    # escape sequence:
  595. X         ($esc, $args) = /^~(\S)\s*(.*)$/;        # 1) parse line
  596. X         *glob = $funcs{$esc};                # 2) unpack type glob
  597. X         if (!defined(&glob)) {                # 3) check defined()
  598. X        warn "Unrecognized escape sequence: ~$esc\n";
  599. X            next;
  600. X         }
  601. X         &glob($args);                    # 4) call func w/ args
  602. X      }
  603. X      elsif (/^\.\s*$/) {                # lone dot means end 
  604. X         print "(eot)\n";                # of log entry
  605. X         last;
  606. X      }
  607. X      else {                        # else append line to
  608. X         push(@lines, $_);                # log buffer
  609. X      }
  610. X   }
  611. X}
  612. X
  613. X# Drop out if buffer is empty.  Append a final newline if one isn't there.
  614. X#
  615. Xif (!@lines || (@lines == 1 && $STAMP)) {
  616. X   warn "*** Empty log entry not added to log file\n";
  617. X   exit;
  618. X}
  619. X$lines[$#lines] = "$lines[$#lines]\n" unless ($lines[$#lines] =~ /\n$/);
  620. X
  621. X# Completed log entry now in @lines.  If using encryption, call encryption
  622. X# command to decrypt previous log entries (if present).  If not encrypting,
  623. X# simply open log file to append.
  624. X#
  625. Xif ($CRYPTCMD) {                    # encrypting
  626. X   if (-e "$LOGFILE") {
  627. X      system "$CRYPTCMD $KEYVAL <$LOGFILE >$TMPFILE";
  628. X   }
  629. X   if (!open(LOGFILE, ">> $TMPFILE")) {
  630. X      unlink "$TMPFILE";
  631. X      warn "*** Unable to append new log entry\n";
  632. X      &quitit();
  633. X   }
  634. X}
  635. Xelse {                             # not encyrpting
  636. X   if (!open(LOGFILE, ">> $LOGFILE")) {
  637. X      warn "*** Unable to append new log entry\n";
  638. X      &quitit();
  639. X   }
  640. X}
  641. X
  642. X# Dump contents of buffer into plain text file.
  643. X#
  644. Xprint LOGFILE "-----\n";
  645. Xprint LOGFILE @lines;
  646. Xclose(LOGFILE);
  647. X
  648. X# If encrypting, replace old log file with new version.  Unlink plain
  649. X# text temporary file when done.
  650. X#
  651. Xif ($CRYPTCMD) {
  652. X   unlink "$LOGFILE";
  653. X   system "$CRYPTCMD $KEYVAL <$TMPFILE >$LOGFILE";
  654. X   chmod 0600, "$LOGFILE";
  655. X   unlink "$TMPFILE";
  656. X}
  657. X
  658. X
  659. X############################## End Main Program ###############################
  660. X########################### Miscellaneous Functions ###########################
  661. X
  662. X
  663. X# Append contents of file $fname (associated with file handle $fh) to buffer.
  664. X# Assume $fh is a pipe if $fname is null.  This function called by many tilde
  665. X# escapes.
  666. X#
  667. Xsub readit {
  668. X   local($fh, $fname) = @_;
  669. X   push(@lines, <$fh>);
  670. X   print STDOUT ($fname) ? "$fname: " : "Added ";
  671. X   print STDOUT "$. lines";
  672. X   print STDOUT ($fname) ? "\n" : " to buffer.\n";
  673. X   print STDOUT "(continue composing note)\n";
  674. X   close($fh);
  675. X}
  676. X
  677. X
  678. X# Call the editor $_[0] on the contents of the buffer.  Used by &editbuf()
  679. X# and &visualbuf().
  680. X#
  681. Xsub calledit {
  682. X   local($edit) = @_;
  683. X   if (!open(EDIT, ">$TMPFILE")) {
  684. X      warn "*** Unable to create file for editing\n";
  685. X      return;
  686. X   }
  687. X   print EDIT @lines;
  688. X   close(EDIT);
  689. X   chmod 0600, "$TMPFILE";
  690. X   system "$edit $TMPFILE";
  691. X   if (!open(EDIT, "<$TMPFILE")) {
  692. X      warn "*** Unable to read changes, returning to previous state.\n";
  693. X      system "/bin/rm -f $TMPFILE*";
  694. X      return;
  695. X   }
  696. X   undef @lines;
  697. X   @lines = <EDIT>;
  698. X   close(EDIT);
  699. X   system "/bin/rm -f $TMPFILE*";
  700. X   print "(continue composing note)\n";
  701. X}
  702. X
  703. X
  704. X# Call the appropriate editor on a log file.  Used by &editlog and &visualedit.
  705. X#
  706. Xsub logedit {
  707. X   local($edit, $args) = @_;
  708. X   local($file, $key) = split(/\s+/, $args);
  709. X   $key = $key || $KEYVAL;
  710. X   $file = $file || $LOGFILE;
  711. X   $file = "$LOGDIR/$file" unless ($file =~ /^\//);
  712. X   if ($CRYPTCMD) {
  713. X      if (!(-e "$file")) {
  714. X     warn "*** $file does not exist\n";
  715. X     return;
  716. X      }
  717. X      system("$CRYPTCMD $key <$file >$TMPFILE");
  718. X      chmod 0600, "$TMPFILE";
  719. X      system("$edit $TMPFILE");
  720. X      if (!(-e "$TMPFILE") || -z _) {
  721. X         warn "*** Modified file is empty-- restoring old version\n";
  722. X     unlink "$TMPFILE";
  723. X     return;
  724. X      }
  725. X      unlink "$file";
  726. X      system "$CRYPTCMD $key <$TMPFILE >$file";
  727. X      chmod 0600, "$file";
  728. X      unlink "$TMPFILE";
  729. X   }
  730. X   else { system("$edit $file"); }
  731. X}
  732. X
  733. X
  734. X# Page a log file.
  735. X#
  736. Xsub pageit {
  737. X   local($args) = @_;
  738. X   local($file, $key) = split(/\s+/, $args);
  739. X   local($cmd);
  740. X   $key = $key || $KEYVAL;
  741. X   $file = $file || $LOGFILE;
  742. X   $file = "$LOGDIR/$file" unless ($file =~ /^\//);
  743. X   $cmd = $CRYPTCMD ? "$CRYPTCMD $key < $file" : "/bin/cat $file";
  744. X   system("$cmd | $PAGER");
  745. X}
  746. X
  747. X
  748. X# Generic warning message called by all escapes that do not expect arguments
  749. X# when @_ is not empty.
  750. X#
  751. Xsub mistake {
  752. X   warn "*** Arguments are not expected for this escape.\n";
  753. X}
  754. X
  755. X
  756. X# Wrapper for &quitit()-- called on SIGINT and SIGQUIT.  Wrapper required
  757. X# because signal handlers get the signal as an argument and &quitit() does
  758. X# not appreciate arguments.
  759. X#
  760. Xsub trapit {
  761. X   &quitit();
  762. X}
  763. END_OF_FILE
  764.   if test 16947 -ne `wc -c <'plod'`; then
  765.     echo shar: \"'plod'\" unpacked with wrong size!
  766.   fi
  767.   chmod +x 'plod'
  768.   # end of 'plod'
  769. fi
  770. if test -f 'plod.el.v1' -a "${1}" != "-c" ; then 
  771.   echo shar: Will not clobber existing file \"'plod.el.v1'\"
  772. else
  773.   echo shar: Extracting \"'plod.el.v1'\" \(3523 characters\)
  774.   sed "s/^X//" >'plod.el.v1' <<'END_OF_FILE'
  775. XNewsgroups: comp.lang.perl
  776. XFrom: paul@ascent.com (Paul Foley)
  777. XSubject: Emacs interface to PLOD
  778. XMessage-ID: <PAUL.93Jan21125701@MountRushmore.ascent.com>
  779. XDate: 21 Jan 93 12:57:01
  780. XOrganization: Ascent Technology, Inc., Cambridge Massachusetts
  781. XLines: 119
  782. X
  783. XHere is an emacs-lisp interface to PLOD --- the Personal LOgging
  784. XDevice posted to comp.lang.perl a few days ago.
  785. X
  786. XSimplest way to use is M-x plod.
  787. X
  788. XThere is also an "alarm" interface that will switch you to a PLOD
  789. Xbuffer every so often, in case you forget to invoke it yourself.
  790. X
  791. XEnjoy.
  792. X
  793. X------------------------------------------------------------------
  794. X
  795. X;;;;
  796. X;;;; plod.el
  797. X;;;;
  798. X;;;; Emacs interface to PLOD --- A (Perl) tool to keep track of the work you do
  799. X;;;; PLOD was written by pomeranz@aqm.com (Hal R. Pomeranz).
  800. X;;;;
  801. X;;;; This software is FREE to all and may be used for any purpose as long as this 
  802. X;;;; notice remains intact.  The author does not assume responsibility for anything.
  803. X;;;; 
  804. X;;;; Suggested addition to .emacs:
  805. X;;;;     (load-library "plod")
  806. X;;;;     (plod-alarm-on 60) ; once an hour
  807. X;;;;
  808. X;;;; When you are tired of PLODding use "M-x plod-alarm-off"
  809. X;;;; 
  810. X;;;; Alternately, use "M-x plod" whenever you want to log something.
  811. X;;;; 
  812. X;;;; paul@ascent.com (Paul Foley)    Wednesday January 20, 1993
  813. X
  814. X(require 'shell)
  815. X
  816. X;;;
  817. X;;; Variables
  818. X;;;
  819. X
  820. X;; Name of executable --- should be in your $PATH
  821. X(defvar plod-program-name "plod")
  822. X(defvar plod-buffer-name "*PLOD*")
  823. X
  824. X;;;
  825. X;;; Manual Interface
  826. X;;;
  827. X
  828. X(defvar plod-buffer-process nil)
  829. X
  830. X;; Interactive command to invoke PLOD in a shell-mode buffer.
  831. X;;
  832. X
  833. X(defun plod ()
  834. X  "Invoke PLOD."
  835. X  (interactive)
  836. X  ; restart PLOD if necessary
  837. X  (if (not (get-buffer-process plod-buffer-name))
  838. X      (setq plod-buffer-process (start-process "plod-process" plod-buffer-name plod-program-name)))
  839. X  (switch-to-buffer plod-buffer-name t)
  840. X  (if (not (eq major-mode 'shell-mode)) (shell-mode)))
  841. X
  842. X
  843. X;;;
  844. X;;; Alarm interface
  845. X;;;
  846. X
  847. X(defvar plod-alarm-on-p nil)        ; t if alarm is on
  848. X(defvar plod-alarm-process nil)
  849. X
  850. X;; run when plod-alarm-process is killed
  851. X(defun plod-alarm-sentinel (proc reason)
  852. X  (or (eq (process-status proc) 'run)
  853. X      (setq plod-alarm-on-p nil)
  854. X      (ding) 
  855. X      (message "PLOD alarm off")))
  856. X
  857. X;; run every interval & at initial call to plod-alarm-on
  858. X(defun plod-alarm-filter (proc string)
  859. X  (if plod-alarm-on-p
  860. X      (plod)
  861. X    (setq plod-alarm-on-p t)))
  862. X
  863. X;; Set alarm to call PLOD every so often
  864. X;;
  865. X(defun plod-alarm-on (interval)
  866. X  "Turn the Emacs PLOD alarm on.  The alarm goes off every INTERVAL minutes
  867. Xand you will be switched to the PLOD buffer automatically.  
  868. XUse plod-alarm-off to stop this behaviour."
  869. X  (interactive "nEnter PLOD alarm interval (in minutes): ")
  870. X  (let ((live (and plod-alarm-process
  871. X           (eq (process-status plod-alarm-process) 'run))))
  872. X    (if (not live)
  873. X    (progn
  874. X      (setq plod-alarm-on-p nil)
  875. X      (if plod-alarm-process
  876. X          (delete-process plod-alarm-process))
  877. X      (let ((process-connection-type nil))
  878. X        (setq plod-alarm-process
  879. X          (start-process "plod-alarm" nil 
  880. X                 (concat exec-directory "wakeup")
  881. X                 ; convert minutes -> seconds for wakeup
  882. X                 (int-to-string (* 60 interval)))))
  883. X      (process-kill-without-query plod-alarm-process)
  884. X      (set-process-sentinel plod-alarm-process 'plod-alarm-sentinel)
  885. X      (set-process-filter plod-alarm-process 'plod-alarm-filter)))))
  886. X
  887. X;; Turn PLOD alarm off
  888. X;;
  889. X(defun plod-alarm-off ()
  890. X  "Turn the Emacs PLOD alarm off."
  891. X  (interactive)
  892. X  (if plod-alarm-on-p (kill-process plod-alarm-process)))
  893. X
  894. X;;; End
  895. X--
  896. Xpaul@ascent.com
  897. X...!uunet!ascent!paul
  898. X
  899. X
  900. X
  901. X
  902. X
  903. X
  904. END_OF_FILE
  905.   if test 3523 -ne `wc -c <'plod.el.v1'`; then
  906.     echo shar: \"'plod.el.v1'\" unpacked with wrong size!
  907.   fi
  908.   # end of 'plod.el.v1'
  909. fi
  910. if test -f 'plod.el.v2' -a "${1}" != "-c" ; then 
  911.   echo shar: Will not clobber existing file \"'plod.el.v2'\"
  912. else
  913.   echo shar: Extracting \"'plod.el.v2'\" \(5558 characters\)
  914.   sed "s/^X//" >'plod.el.v2' <<'END_OF_FILE'
  915. X;; Plod sending commands for Emacs.
  916. X
  917. X;; This file is not part of GNU Emacs.
  918. X
  919. X;; GNU Emacs is free software; you can redistribute it and/or modify
  920. X;; it under the terms of the GNU General Public License as published by
  921. X;; the Free Software Foundation; either version 1, or (at your option)
  922. X;; any later version.
  923. X
  924. X;; GNU Emacs is distributed in the hope that it will be useful,
  925. X;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  926. X;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  927. X;; GNU General Public License for more details.
  928. X
  929. X;; You should have received a copy of the GNU General Public License
  930. X;; along with GNU Emacs; see the file COPYING.  If not, write to
  931. X;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  932. X
  933. X;; Suggested addition to .emacs:
  934. X;;     (load-library "plod-mode")
  935. X;;     (plod-alarm-on 60) ; once an hour
  936. X;;
  937. X;; When you are tired of PLODding use "M-x plod-alarm-off"
  938. X;; 
  939. X;; Alternately, use "M-x plod" whenever you want to log something.
  940. X;; 
  941. X;; paul@ascent.com (Paul Foley)    Wednesday January 20, 1993
  942. X;; paulh@harlequin.com (Paul Hudson) Later in 1993 (I forget when :-)
  943. X
  944. X
  945. X(provide 'plod)
  946. X
  947. X(defvar send-plod-function 'plod-send-it
  948. X  "Function to call to send the current buffer as plod.")
  949. X
  950. X(defvar plod-mode-map nil)
  951. X
  952. X(defun plod-mode ()
  953. X  "Major mode for editing text to be sent to plod.
  954. XLike Text Mode but with these additional commands:
  955. XC-c C-s  plod-send (send the message)    C-c C-c  plod-send-and-exit"
  956. X  (interactive)
  957. X  (kill-all-local-variables)
  958. X  (make-local-variable 'plod-reply-buffer)
  959. X  (setq plod-reply-buffer nil)
  960. X  (set-syntax-table text-mode-syntax-table)
  961. X  (use-local-map plod-mode-map)
  962. X  (setq local-abbrev-table text-mode-abbrev-table)
  963. X  (setq major-mode 'plod-mode)
  964. X  (setq mode-name "Plod")
  965. X  (setq buffer-offer-save t)
  966. X  (run-hooks 'text-mode-hook 'plod-mode-hook))
  967. X
  968. X(if plod-mode-map
  969. X    nil
  970. X  (setq plod-mode-map (make-sparse-keymap))
  971. X  (define-key plod-mode-map "\C-c?" 'describe-mode)
  972. X  (define-key plod-mode-map "\C-c\C-c" 'plod-send-and-exit)
  973. X  (define-key plod-mode-map "\C-c\C-s" 'plod-send))
  974. X
  975. X(defun plod-send-and-exit (arg)
  976. X  "Send message like plod-send, then, if no errors, exit from plod buffer.
  977. XPrefix arg means don't delete this window."
  978. X  (interactive "P")
  979. X  (plod-send)
  980. X  (bury-buffer (current-buffer))
  981. X  (if (and (not arg)
  982. X       (not (one-window-p)))
  983. X      (delete-window)
  984. X    (switch-to-buffer (other-buffer (current-buffer)))))
  985. X
  986. X(defun plod-send ()
  987. X  "Send the message in the current buffer to plod."
  988. X  (interactive)
  989. X  (message "Sending...")
  990. X  (funcall send-plod-function)
  991. X  (set-buffer-modified-p nil)
  992. X  (delete-auto-save-file-if-necessary)
  993. X  (message "Sending...done"))
  994. X
  995. X(defun plod-send-it ()
  996. X  (let ((tembuf (generate-new-buffer " plod temp"))
  997. X    (plodbuf (current-buffer)))
  998. X    (unwind-protect
  999. X      (call-process-region (point-min) (point-max)
  1000. X                   (if (boundp 'plod-program)
  1001. X                   plod-program
  1002. X                 "/usr/local/bin/plod")
  1003. X                   nil tembuf nil)
  1004. X      (kill-buffer tembuf))))
  1005. X
  1006. X
  1007. X(defun plod (&optional noerase)
  1008. X  "Edit a message to be sent.  Argument means resume editing (don't erase).
  1009. XReturns with message buffer selected; value t if message freshly initialized.
  1010. XWhile editing message, type C-c C-c to send the message and exit.
  1011. X
  1012. X\\{plod-mode-map}
  1013. X
  1014. XIf plod-setup-hook is bound, its value is called with no arguments
  1015. Xafter the message is initialized. "
  1016. X  (interactive "P")
  1017. X  (switch-to-buffer "*plod*")
  1018. X  (setq default-directory (expand-file-name "~/"))
  1019. X  (auto-save-mode auto-save-default)
  1020. X  (plod-mode)
  1021. X  (and (not noerase)
  1022. X       (or (not (buffer-modified-p))
  1023. X       (y-or-n-p "Unsent message being composed; erase it? "))
  1024. X       (progn (erase-buffer)
  1025. X          (set-buffer-modified-p nil)
  1026. X          (run-hooks 'plod-setup-hook)
  1027. X          t)))
  1028. X
  1029. X(defun plod-other-window (&optional noerase)
  1030. X  "Like `plod' command, but display plod buffer in another window."
  1031. X  (interactive "P")
  1032. X  (let ((pop-up-windows t))
  1033. X    (pop-to-buffer "*plod*"))
  1034. X  (plod noerase))
  1035. X
  1036. X
  1037. X;;;
  1038. X;;; Alarm interface
  1039. X;;;
  1040. X
  1041. X(defvar plod-alarm-on-p nil)        ; t if alarm is on
  1042. X(defvar plod-alarm-process nil)
  1043. X
  1044. X;; run when plod-alarm-process is killed
  1045. X(defun plod-alarm-sentinel (proc reason)
  1046. X  (or (eq (process-status proc) 'run)
  1047. X      (setq plod-alarm-on-p nil)
  1048. X      (ding) 
  1049. X      (message "PLOD alarm off")))
  1050. X
  1051. X;; run every interval & at initial call to plod-alarm-on
  1052. X(defun plod-alarm-filter (proc string)
  1053. X  (if plod-alarm-on-p
  1054. X      (plod)
  1055. X    (setq plod-alarm-on-p t)))
  1056. X
  1057. X;; Set alarm to call PLOD every so often
  1058. X;;
  1059. X(defun plod-alarm-on (interval)
  1060. X  "Turn the Emacs PLOD alarm on.  The alarm goes off every INTERVAL minutes
  1061. Xand you will be switched to the PLOD buffer automatically.  
  1062. XUse plod-alarm-off to stop this behaviour."
  1063. X  (interactive "nEnter PLOD alarm interval (in minutes): ")
  1064. X  (let ((live (and plod-alarm-process
  1065. X           (eq (process-status plod-alarm-process) 'run))))
  1066. X    (if (not live)
  1067. X    (progn
  1068. X      (setq plod-alarm-on-p nil)
  1069. X      (if plod-alarm-process
  1070. X          (delete-process plod-alarm-process))
  1071. X      (let ((process-connection-type nil))
  1072. X        (setq plod-alarm-process
  1073. X          (start-process "plod-alarm" nil 
  1074. X                 (concat exec-directory "wakeup")
  1075. X                 ; convert minutes -> seconds for wakeup
  1076. X                 (int-to-string (* 60 interval)))))
  1077. X      (process-kill-without-query plod-alarm-process)
  1078. X      (set-process-sentinel plod-alarm-process 'plod-alarm-sentinel)
  1079. X      (set-process-filter plod-alarm-process 'plod-alarm-filter)))))
  1080. X
  1081. X;; Turn PLOD alarm off
  1082. X;;
  1083. X(defun plod-alarm-off ()
  1084. X  "Turn the Emacs PLOD alarm off."
  1085. X  (interactive)
  1086. X  (if plod-alarm-on-p (kill-process plod-alarm-process)))
  1087. X
  1088. X;;; End
  1089. X
  1090. X
  1091. END_OF_FILE
  1092.   if test 5558 -ne `wc -c <'plod.el.v2'`; then
  1093.     echo shar: \"'plod.el.v2'\" unpacked with wrong size!
  1094.   fi
  1095.   # end of 'plod.el.v2'
  1096. fi
  1097. if test -f 'plod.man' -a "${1}" != "-c" ; then 
  1098.   echo shar: Will not clobber existing file \"'plod.man'\"
  1099. else
  1100.   echo shar: Extracting \"'plod.man'\" \(9043 characters\)
  1101.   sed "s/^X//" >'plod.man' <<'END_OF_FILE'
  1102. X.nh
  1103. X.de Sp
  1104. X.if t .sp .5v
  1105. X.if n .sp
  1106. X..
  1107. X.de Ip
  1108. X.br
  1109. X.ie \\n.$>=3 .ne \\$3
  1110. X.el .ne 3
  1111. X.IP "\\$1" \\$2
  1112. X..
  1113. X.TH PLOD 1 "2 February 1993" "PLOD"
  1114. X.SH NAME
  1115. XPLOD \- keep a log of your work
  1116. X.SH SYNOPSIS
  1117. X.B plod
  1118. X\ [\ \fIone line message\fR\ ]
  1119. X.br
  1120. X.B plod
  1121. X\ \fB-E\fR|\fB-P\fR|\fB-V\fR\ [\ \fIlogfile\fR\ [\ \fIkey\fR\ ]]
  1122. X.SH DESCRIPTION
  1123. X\fBPLOD\fR
  1124. Xis a tool developed to help System/Network Administrators (and others)
  1125. Xkeep track of the work that they do.  Good logs are useful both as a
  1126. Xpersonal reference and to show to your management on a regular basis
  1127. Xor around performance review time. By default, logs will be stored in
  1128. Xan encrypted format in the directory \fI$HOME/.logdir\fR, but this
  1129. Xbehavior is completely customizable (see \fBENVIRONMENT\fR and 
  1130. X\fBCUSTOMIZATION\fR below).
  1131. X
  1132. XThe first form of the command will enter a short message on the command
  1133. Xline into your log file.  If no message is present on the command line,
  1134. Xa date/time stamp will be printed and \fBPLOD\fR
  1135. Xwill go into an interactive mode reminiscent of BSD mail.  Many tilde
  1136. Xescape sequences are supported (see \fBCOMMANDS\fR below or type 
  1137. X\fI~h\fR or \fI~?\fR within interactive mode).  Enter a period on a
  1138. Xline by itself to end your log entry.
  1139. X
  1140. XThe second mode allows you to review or edit your old log files.  The
  1141. X\fB-P\fR option invokes the default \fBPAGER\fR defined in the \fBPLOD\fR
  1142. Xsource, or as defined in your environment, on the current log file.  The
  1143. X\fB-E\fR and \fB-V\fR flags invoke \fBEDITOR\fR and \fBVISUAL\fR respectively.
  1144. XOlder log files may be accessed by specifying a file name and optional
  1145. Xencryption key on the command line.
  1146. X
  1147. X.SH ENVIRONMENT
  1148. X\fBPLOD\fR supports a number of variables which can be modified to customize
  1149. Xits behavior.  The values of these variables may be changed by editing
  1150. X\fBPLOD\fR directly, by assignment in a system-wide startup file, 
  1151. Xby creating an environment variable, or by assignment
  1152. Xin the user's startup file (see \fBCUSTOMIZATION\fR below).  \fBPLOD\fR
  1153. Xrecognizes the following environment variables:
  1154. X.Ip "\fBSTAMP\fR" 4
  1155. XThe time/date stamp entered into every log entry.  Set this to null if you
  1156. Xdo not wish to datestamp your logs.  Default is \fIMM/DD/YY, HH:MM --\fR.
  1157. X.Sp
  1158. X.Ip "\fBEDITOR\fR" 4
  1159. XThe user's preferred editor (used by the \fB-E\fR command line flag and the
  1160. X\fB~e\fR, \fB~E\fR, and \fB~M\fR escape sequences).  Default is 
  1161. X\fI/usr/local/bin/emacs\fR.
  1162. X.Sp
  1163. X.Ip "\fBVISUAL\fR" 4
  1164. XThe user's preferred visual editor (used by \fB-V\fR, \fB~v\fR, and \fB~V\fR).
  1165. XDefault is \fI/usr/local/bin/emacs\fR.
  1166. X.Sp
  1167. X.Ip "\fBPAGER\fR" 4
  1168. XThe user's preferred pager (used by \fB-P\fR, \fB~p\fR, and \fB~P\fR).
  1169. XDefault is \fI/usr/local/bin/less\fR.
  1170. X.Sp
  1171. X.Ip "\fBLINES\fR" 4
  1172. XThe number of lines on the current display.  Used to determine when the
  1173. X\fBPAGER\fR needs to be invoked. Default is \fI24\fR.
  1174. X.Sp
  1175. X.Ip "\fBCRYPTCMD\fR" 4
  1176. XThe encryption command to be used.  If you do not wish to encrypt your
  1177. Xlog files, set this to null.  The standard UNIX \fBcrypt\fR command is
  1178. Xnot in the least secure, but does provide protection from casual browsing.
  1179. XDefault is \fI/bin/crypt\fR.
  1180. X.Sp
  1181. X.Ip "\fBKEYVAL\fR" 4
  1182. XThe key to be used with \fBCRYPTCMD\fR.  Default is \fIpl<yr><mn>od\fR.
  1183. X.Sp
  1184. X.Ip "\fBLOGDIR\fR" 4
  1185. XWhere log files are placed.  Default is \fI$HOME/.logdir\fR.
  1186. X.Sp
  1187. X.Ip "\fBLOGFILE\fR" 4
  1188. XThe name of the current log file.  \fBLOGDIR\fR will be prepended to this
  1189. Xvalue if \fBLOGFILE\fR does not begin with a \fI/\fR.  Default is
  1190. X\fI<yr><mn>\fR.
  1191. X.Sp
  1192. X.Ip "\fBHOME\fR" 4
  1193. XThe user's home directory.  Default taken from user's password entry.
  1194. X.Sp
  1195. X.Ip "\fBDEADLOG\fR" 4
  1196. XWhere interrupted log entries are placed.  \fBHOME\fR will be prepended
  1197. Xto this value if \fBDEADLOG\fR does not begin with a \fI/\fR.  Default
  1198. Xis \fIdead.log\fR.
  1199. X.Sp
  1200. X.Ip "\fBTMPFILE\fR" 4
  1201. XScratch file used throughout execution of program.  Default is 
  1202. X\fI/tmp/plodtmp<pid>\fR.
  1203. X.Sp
  1204. X
  1205. X.SH COMMANDS
  1206. XMany tilde escape sequences are supported under \fBPLOD\fR's interactive
  1207. Xmode.  Users may also define their own escape sequences in \fBPLOD\fR's
  1208. Xinitialization file (see \fBCUSTOMIZATION\fR below).  Currently defined
  1209. Xsequences are:
  1210. X.Ip "~h, ~?" 8
  1211. XShow a list of all escape sequences with a short usage message.
  1212. X.Sp
  1213. X.Ip "~= var[, ...]" 8
  1214. XDisplay the current value of one or more variables.
  1215. X.Ip ~e 8
  1216. XEdit the current buffer with \fB$EDITOR\fR.
  1217. X.Sp
  1218. X.Ip ~v 8
  1219. XEdit the current buffer with \fB$VISUAL\fR.
  1220. X.Sp
  1221. X.Ip ~p 8
  1222. XDisplay the contents of the current buffer (using \fB$PAGER\fR if necessary).
  1223. X.Sp
  1224. X.Ip "~V [\ logfile\ [\ key\ ]]" 8
  1225. XCall \fB$VISUAL\fR on the current log file, or on some other log file as
  1226. Xspecified.  An additional encryption key may also be supplied.
  1227. X.Sp
  1228. X.Ip "~E, ~l [\ logfile\ [\ key\ ]]" 8
  1229. XSimilar to ~E except that \fB$EDITOR\fR is used.
  1230. X.Sp
  1231. X.Ip "~P, ~L [\ logfile\ [\ key\ ]]" 8
  1232. XSame as ~E and ~V except that \fB$PAGER\fR is invoked.
  1233. X.Sp
  1234. X.Ip ~q 8
  1235. XQuit \fBPLOD\fR, saving contents of buffer into \fB$DEADLOG\fR.
  1236. X.Sp
  1237. X.Ip ~x 8
  1238. XQuit without attempting to save buffer.
  1239. X.Sp
  1240. X.Ip ~d 8
  1241. XAppend contents of \fB$DEADLOG\fR to current buffer.
  1242. X.Sp
  1243. X.Ip "~r somefile" 8
  1244. XAppend contents of file to current buffer.
  1245. X.Sp
  1246. X.Ip "~a somefile" 8
  1247. XAppend contents of current buffer to file.
  1248. X.Sp
  1249. X.Ip "~w somefile" 8
  1250. XOverwrite file with contents of current buffer.
  1251. X.Sp
  1252. X.Ip "~X Perl-code" 8
  1253. XExecute a line of Perl code.
  1254. X.Sp
  1255. X.Ip ~M 8
  1256. XInvoke \fB$EDITOR\fR and execute resulting file as Perl code.  Each successive
  1257. Xinvocation of this escape will edit the previously executed Perl code so as
  1258. Xto make it easier to go back and correct small errors.
  1259. X.Sp
  1260. X.Ip "~! command" 8
  1261. XExecute a command in the shell and return.
  1262. X.Sp
  1263. X.Ip "~> command" 8
  1264. XAppend the output of a command to the current buffer.
  1265. X.Sp
  1266. X.Ip "~| command" 8
  1267. XPipe the current buffer through a command and replace the buffer with the
  1268. Xresulting output.
  1269. X.Sp
  1270. X
  1271. X.SH CUSTOMIZATION
  1272. XLike most UNIX utilities, \fBPLOD\fR has an initialization file,
  1273. Xthe \fI\.plodrc\fR,
  1274. Xwhich is read at startup.  Unlike most UNIX utilities,
  1275. Xthis file is interpreted as Perl code.  Thus, if you wished to assign
  1276. Xa new value to a customization variable you would use the syntax
  1277. X.RS
  1278. X.PP
  1279. X$LOGDIR = "$HOME/mylogs";
  1280. X.RE
  1281. X.PP
  1282. X\fBPLOD\fR also looks for a system-wide customization file, \fI/etc/plodrc\fR.
  1283. XThe order of evaluation is: hard coded defaults in \fBPLOD\fR, then
  1284. Xthe \fI/etc/plodrc\fR file, then the user's environment, and finally the
  1285. Xuser's \fI\.plodrc\fR file.
  1286. X
  1287. XIt is also possible for the user to create their own tilde escapes.  First,
  1288. Xcreate a subroutine which performs the desired function.  Then assign the
  1289. Xtype glob which references that function to global array \fI%funcs\fR indexed
  1290. Xby the character of the escape sequence.  Any arguments that the user enters
  1291. Xafter the tilde escape will be passed into the function as a single string
  1292. Xin \fI@_\fR.  The list \fI@lines\fR contains the current buffer.
  1293. X
  1294. XAs an example, here is the append to file function (~a) from the \fBPLOD\fR
  1295. Xsource:
  1296. X.RS
  1297. X.PP
  1298. X.nf
  1299. Xsub appendfl {
  1300. X   local($file) = @_;
  1301. X   if (!open(OUTP, ">> $file")) {
  1302. X      warn "*** Could not append to file $file\\n";
  1303. X      return;
  1304. X   }
  1305. X   print OUTP @lines;
  1306. X   close(OUTP);
  1307. X   print "Wrote ", scalar(@lines), " lines to file $file\\n";
  1308. X   print "(continue composing note)\\n";
  1309. X}
  1310. X$appendfl = "file\\t\\tAppend contents of buffer to file";
  1311. X$funcs{'a'} = *appendfl;
  1312. X.fi
  1313. X.RE
  1314. X.PP
  1315. XThe scalar variable \fI$appendfl\fR is used by \fBPLOD\fR's help function
  1316. X(~h or ~?) to provide a descriptive message about the escape sequence.
  1317. XAs a further example, here is \fBPLOD\fR's help function
  1318. X.RS
  1319. X.PP
  1320. X.nf
  1321. Xsub helpuser {
  1322. X   $long = (scalar(keys %funcs) >= $LINES)
  1323. X           && open(TMP, ">$TMPFILE");
  1324. X   for (sort keys %funcs) {
  1325. X      *info = $funcs{$_};
  1326. X      if ($long) {
  1327. X         print TMP "~$_ $info\\n";
  1328. X      }
  1329. X      else { print "~$_ $info\\n"; }
  1330. X   }
  1331. X   if ($long) {
  1332. X      close(TMP);
  1333. X      system("/bin/cat $TMPFILE | $PAGER");
  1334. X      unlink "$TMPFILE";
  1335. X   }
  1336. X}
  1337. X$helpuser = "\\t\\tPrint this message";
  1338. X$funcs{'h'} = *helpuser;
  1339. X$funcs{'?'} = *helpuser;
  1340. X.fi
  1341. X.RE
  1342. X.PP
  1343. XNote the use of various customization variables as well as the assignment
  1344. Xof the type glob to two different indices of the \fI%funcs\fR array.
  1345. X
  1346. X.SH FILES
  1347. X.PP
  1348. X.Ip $HOME/.plodrc 24
  1349. XUsers' personal initialization files
  1350. X.Sp
  1351. X.Ip /etc/plodrc 24
  1352. XSystem-wide initialization file
  1353. X.Sp
  1354. X.PP
  1355. XVarious other customizable file locations.
  1356. X
  1357. X.SH SEE ALSO
  1358. X.BR perl (1)
  1359. X
  1360. X.SH AUTHORS
  1361. XThe original idea for \fBPLOD\fR comes from Bill Mendyka
  1362. X(\fBmendyka@dg-rtp.dg.com\fR).
  1363. X
  1364. XThe current Perl implementation was developed by Hal Pomeranz
  1365. X(\fBpomeranz@aqm.com\fR).
  1366. X
  1367. XAn Emacs mode for \fBPLOD\fR was developed by Paul Foley
  1368. X(\fBpaul@ascent.com\fR).
  1369. X
  1370. XAdditional improvements have been suggested/developed by:
  1371. XDavid W Crabb (\fBcrabb@phoenix.Princeton.EDU\fR),
  1372. XJohn Ellis (\fBellis@rtsg.mot.com\fR),
  1373. XMike Lachowski (\fBmlachow@erenj.com\fR),
  1374. XEric Prestemon (\fBecprest@pocorvares.er.usgs.GOV\fR),
  1375. XErik E. Rantapaa (\fBrantapaa@math.umn.edu\fR), and
  1376. XJames Tizard (\fBjames@ringo.ssn.flinders.edu.au\fR).
  1377. X
  1378. X.SH BUGS
  1379. XAny bug reports or suggestions for improvement should be submitted to
  1380. XHal Pomeranz via email at \fBpomeranz@aqm.com\fR.
  1381. END_OF_FILE
  1382.   if test 9043 -ne `wc -c <'plod.man'`; then
  1383.     echo shar: \"'plod.man'\" unpacked with wrong size!
  1384.   fi
  1385.   # end of 'plod.man'
  1386. fi
  1387. echo shar: End of archive 1 \(of 1\).
  1388. cp /dev/null ark1isdone
  1389. MISSING=""
  1390. for I in 1 ; do
  1391.     if test ! -f ark${I}isdone ; then
  1392.     MISSING="${MISSING} ${I}"
  1393.     fi
  1394. done
  1395. if test "${MISSING}" = "" ; then
  1396.     echo You have the archive.
  1397.     rm -f ark[1-9]isdone
  1398. else
  1399.     echo You still must unpack the following archives:
  1400.     echo "        " ${MISSING}
  1401. fi
  1402. exit 0
  1403. exit 0 # Just in case...
  1404.