/set savehist_version=$Id: savehist.tf,v 35000.5 2004/08/04 18:31:51 hawkeye Exp $
;;;; Save/restore world histories
;;;; Typical usage in .tfrc:
; /addworld ...
; ...
; /set savehist_dir=~/tf-hist
; /load_histories
; /repeat -0:10 i /save_histories
/loaded __TFLIB__/savehist.tf
/if (systype() !~ "unix") \
/echo -e %% Warning: savehist.tf may not work on non-unix systems.%; \
/endif
/require textutil.tf
/require textencode.tf
/require lisp.tf
/if (savehist_dir =~ "") /set savehist_dir=~/tf-hist%; /endif
;; /save_histories [-lig]
;; saves all world histories, and optionally local/input/global. If none of
;; -lig are given, -i is assumed.
/def -i save_histories = \
/if (!getopts("lig", 0)) /return 0%; /endif%; \
/if (!opt_l | !opt_i | !opt_g) /let opt_i=1%; /endif%; \
; %savehist may appear on status bar
/set savehist=H%; \
/if (opt_l) /save_history -l%; /endif%; \
/if (opt_i) /save_history -i%; /endif%; \
/if (opt_g) /save_history -g%; /endif%; \
; (unnamedN) worlds won't show up without /listworlds -u
/quote -S /~save_histories `/listworlds -s%; \
/unset savehist
/def -i ~save_histories = \
; /_echo %1%; \
/save_history -w%1
/def -i load_histories = \
/echo -e %% Loading all histories...%; \
; /let old_status_fields=%status_fields%; \
; /set _savehist=%; \
; /set status_fields=$[replace("@world", "_savehist", status_fields)]%; \
/set _loaded_histories=%; \
/let _histories=$(/quote -S -decho !\
cd $[filename(savehist_dir)] && echo `ls -1 l i g w* 2>/dev/null`)%; \
/if (_histories =~ "") \
/echo -e %% %0: no history files found in "%savehist_dir".%; \
/else \
/mapcar /~load_histories %_histories%; \
/echo -e %% Loaded histories: %_loaded_histories%; \
/endif%; \
; /set status_fields=%old_status_fields%; \
/unset _loaded_histories
/def -i ~load_histories = \
/let ehist=%1%; \
/let hist=$[textdecode(ehist)]%; \
; /set _savehist=%hist%; \
/let file=%savehist_dir/%ehist%; \
; Compatibility with optional cchan.tf
/if (regmatch("w(([^:]+):(.*))$", hist) & ismacro("cchan_addworld") & \
world_info({P1}, "name") =~ "" & \
world_info({P2}, "type") =/ "*.cchan.*") \
/cchan_addworld $(/listworlds -s %P2):%P3%; \
/endif%; \
; /echo -e - Loading history: %hist%; \
/if /load_history -%hist%; /then \
/set _loaded_histories=%_loaded_histories %hist%; \
/endif
;; /set_savehist_last <ehist> <hist>
/def -i set_savehist_last = \
/set savehist_last_%1=$[regmatch("^[0-9]+", $(/recall -%2 #/1)) & {P0}]
/def -i savehist_args = \
/if (!regmatch("^-([lig]|w(.+))$", {-1})) \
/echo -e %% usage: %1 {-l|-i|-g|-w<world>}%; \
/return 0%; \
/endif%; \
/set savehist_hist=%P1%; \
/let world=%P2%; \
/if (world !~ "" & world_info(world, "name") =~ "") \
/echo -e %% %1: no world %world%; \
/return 0%; \
/endif%; \
/return 1
/def -i _hist_write = \
/let _line=%; \
/while (tfread('i', _line) >= 0) \
/test tfwrite({1}, encode_attr(_line))%; \
/done
; /save_history {-l|-i|-g|-w<world>}
/def -i save_history = \
/if /!savehist_args %0 %*%; /then /return 0%; /endif%; \
/let hist=%savehist_hist%; \
/let ehist=$[textencode(hist)]%; \
/let dir=$[filename(savehist_dir)]%; \
/let file=%dir/%ehist%; \
/let first=%; \
/test first:=savehist_last_%ehist + 1%; \
/recall -%hist %{first}- %| /let count=%?%; \
/if (!count) /return 1%; /endif%; \
/setenv _file=%file%; \
/setenv _dir=%dir%; \
; if appending to file would give it more than 10% extra lines, truncate it
/let filesize=savehist_filesize_%ehist%; \
/histsize -%hist %| /let max=%{?}%; \
/if /test %{filesize}%; /then \
; The filesize is cached, and we'll assume the directory exists, avoiding
; potentially expensive shell calls.
/test %{filesize} := %{filesize} + count%; \
/else \
; Filesize is unknown; this must be the first call to save_history for
; this history. We must make sure the dir exists and get the filesize.
/set %{filesize}=0%; \
/quote -S -decho %% !test -d $$_dir || mkdir $$_dir%; \
/if ({?} != 0) \
/unset _dir%; \
/unset _file%; \
/return%; \
/endif%; \
/quote -S /test %{filesize}:=+"!"wc -l %_file""%; \
/endif%; \
/let mode=a%; \
/if /test %{filesize} + count > max * 1.1%; /then \
/if (count >= max) \
/test count := max%; \
/let mode=w%; \
/test %{filesize} := 0%; \
/else \
/setenv _tmp=%_dir/tfhist-$[getpid()]%; \
/quote -S -decho %% !touch $$_tmp && chmod go-rwx $$_tmp && \
tail -$[max-count] $$_file > $$_tmp && mv $$_tmp $$_file%; \
/if ({?} == 0) \
/test %{filesize} := max - count%; \
/endif%; \
/unset _tmp%; \
/endif%; \
/endif%; \
; append the new lines to the file
/let old_max_iter=%max_iter%; \
/set max_iter=0%; \
/let out=%; \
/if ((out := tfopen(_file, mode)) >= 0) \
/if /test !%{filesize}%; /then \
/quote -S -decho %% !chmod go-rwx $$_file%; \
/endif%; \
/test tfflush(out, 0)%; \
; "i" can't have attributes, so we don't bother encoding them.
/let opts=-%hist /%count%; \
/if (savehist_hist =~ "i") \
/quote -S -decho #-t'%%@ -' %opts %| /test copyio('i', out)%; \
/else \
/quote -S -decho #-t'%%@ -p -' %opts %| /test _hist_write(out)%; \
/endif%; \
/test tfclose(out)%; \
/set max_iter=%old_max_iter%; \
/test %{filesize} := %{filesize} + count%; \
/set_savehist_last %ehist %hist%; \
/else \
; Directory may be corrupt. Forget cached filesize.
/unset %{filesize}%; \
/endif%; \
/unset _dir%; \
/unset _file
; /load_history {-l|-i|-g|-w<world>}
/def -i load_history = \
/if /!savehist_args %0 %*%; /then /return 0%; /endif%; \
/let file=%savehist_dir/$[textencode(savehist_hist)]%; \
/quote -S /recordline -%savehist_hist -t'%file%; \
/set_savehist_last %ehist %hist%; \
/return 1