Susan's Lists

From Gwen Morse's Wiki
Jump to: navigation, search

Susan's Lists uses the array package called Susan's Arrays and borrows an altered command from Joe's Lists Library

;;; $Id: lists.txt,v 1.1 1998/03/03 22:32:11 dittmar Exp dittmar $
;;;
;;; coded by Susan Dittmar 
;;; (dittmar dot ph dash cip dot uni dash koeln dot de), October 1997,
;;; bigger changes January 1998
;;;
;;; I'll describe the usage of this little tinyfugue-library with the
;;; syntax of help files. This way, if you use your own help texts with
;;; tinyfugue (like with the /help command by Johan van Selst), you can
;;; just copy this part to your help file, you just have to remove the
;;; semicolons.

;;; The library requires tinyfugue Version 4.0 for the file handling part,
;;; the rest of the code will work with earlier versions too.

;;; &lists
;;;
;;; I wrote these commands to make some triggers much easier.
;;; The commands only keep track of variables which contain items
;;; seperated by '|'. These variables (lists) then can be used for
;;; global maching, like
;;;    /if /test {variable} =/ "{%{list}}" %; /then ...
;;;
;;; For each list there is a variable with the name <list>__count which
;;; counts the number of items in the list. If you only add and remove
;;; single items, this number will be up to date, else it can be computed.
;;;
;;; the commands are
;;; /addlist <list> <item>    adds <item> to the list if it does not exist
;;;                           yet
;;; /addlist <list>           echos the whole list
;;; addlist <arguments>       executes /addlist with it's arguments and
;;;                           writes the necessary commands to reproduce the
;;;                           list to the file you specified
;;; /remlist <list> <item>    removes <item> from the list if it exists.
;;; /remlist <list> -a        clears the whole list
;;; remlist <arguments>       executes /remlist with it's arguments and
;;;                           writes the necessary commands to reproduce the
;;;                           list to the file you specified
;;; /countlist <list>         counts the number of items in the list
;;; /changeListFile <filename>    changes the file for saving lists to a
;;;                           file called <filename>. In case such a file
;;;                           already exists, the new things will be appended,
;;;                           nothing in the file will be lost.
;;; /foreach <variable> <list name> <command>    executes a loop. In each
;;;                           turn one item of the list is assigned to the
;;;                           variable <variable>, then the command <command>
;;;                           (this can be a list of commands separated by %;
;;;                           if you need) is executed with this value of
;;;                           the variable <variable>
;;;
;;; /isamember(str, list, n)  return the item number of 'n'th item match that
;;;                           exactly string matches 'str' in 'list'. If no
;;;                           'n'th item match, return 0.
;;;
;;; #change
;;; #changes
;;; 5.1.1998:
;;;   * added the counter <list>__count
;;;   * added /countlist
;;; 22.1.1998:
;;;   * added writing to a file (addlist, remlist, /changeListFile)
;;;   * added command /foreach
;;; 28.1.1998:
;;;   * added the list __LIST, which contains the name of all lists
;;;     which were used
;;; 29.1.1998:
;;;   * added /sortlist <list> command
;;;   * added /saveAllLists command (sorts and then saves all lists stored
;;;     in __LIST)
;;;
;;; 20.2.2014:
;;;   * added Joe Pelkey's isamember() function. 
;;;   * Cleanup work by Jacob Finn (super aardvark at gmail) @ TF mailing list

;;;
;;; #author
;;; #bug
;;; #bugs
;;; #typo
;;; #typos
;;; #suggestion
;;; #suggestions
;;; The commands have been written by Susan Dittmar 
;;; An actual version can be obtained from 
;;; http://www.ph-cip.uni-koeln.de/~dittmar/tf. Please send bug reports 
;;; and suggestions to the author.
;;; 

;;; You can change the next line to /~loaded lists.tf if you want.
/~loadedlocal lists.tf
/require alias.tf
/requirelocal array.tf

/def addlist = \
    /let list=%1%;\
    /if (list =~ "") /echo %%% you must provide the list name %; /endif %;\
    /let item=%-1%;\
    /if ({list} !~ "__LIST") \
        /if /test {list} !/ "%{__LIST}" %; /then \
            /addlist __LIST %{list} %;\
        /endif %;\
    /endif %;\
    /if (item =~ "") \
        /eval /echo \% List %{list} contains %%{%{list}}%;\
;        /eval /echo /addlist %{list} %%{%{list}}%;\
        /break%;\
    /endif%;\
;    /eval /eval /echo item=%{item}, list=%%{%{list}} %;\
    /eval /eval /if (item =/ "{%%{%{list}}}") \
        /break%%%;\
    /elseif (%{list} =~ "") \
        /set %{list}=%{item}%%%;\
        /set %{list}__count=1%%%;\
    /else \
        /set %{list}=%%{%{list}}|%{item}%%%;\
        /set %{list}__count=$$$[%%{%{list}__count}+1]%%%;\
    /endif



/def remlist =\
    /let list=%1%;\
    /if (list =~ "") \
        /echo %%% you must provide the list name %;\
        /break %;\
    /endif %;\
    /let item=%-1%;\
    /if (item =~ "") \
        /echo \% Use /remlist <list> <item> or /remlist <list> -a for all.%;\
        /break%;\
    /endif%;\
    /eval /eval /if ((item =~ "-a")|(item =~ "%%{%{list}}")) \
        /set %{list}=%%%;\
        /set %{list}__count=0%%%;\
    /elseif (item =/ "{%%{%{list}}}") \
        /set %{list}=$$$(/_lists_remove %%%{item}| %%%{%%{list}})%%%;\
        /set %{list}=$$$(/_lists_remove |%%%{item} %%%{%%{list}})%%%;\
        /set %{list}__count=$$$[%%{%{list}__count}-1]%%%;\
    /endif

/def _lists_remove = \
    /let old=%1%;\
    /let left=%;\
    /let right=%-1%;\
    /while /let i=$[strstr(right, old)]%; /test i >= 0%; /do \
         /test left := strcat(left, substr(right, 0, i), new)%;\
         /test right := substr(right, i + strlen(old))%;\
    /done%;\
    /echo - %{left}%{right}


/def countlist =\
    /let list=%1%;\
    /if (list =~ "") \
        /echo %%% you must provide the list name %;\
        /break %;\
    /endif %;\
    /eval /if ({%{list}} =~ "") \
            /set %{list}__count=0%%;\
            /break %%;\
        /else \
            /set %{list}__count=1%%;\
        /endif %;\
    /eval /let right=%%{%{list}}%%;\
        /while /let i=$$[strchr(right, "|")]%%; /test i >= 0%%; /do \
             /test right := substr(right, i + 1)%%;\
             /eval /set %{list}__count=$$$[%%{%{list}__count}+1]%%;\
        /done

  
/def sortlist =\
    /let list=%1%;\
    /if (list =~ "") \
        /echo %%% you must provide the list name %;\
        /break %;\
    /endif %;\
    /countlist %{list}%;\
    /let countmax=$(/eval /echo - %%{%{list}__count})%;\
    /foreach j %{list} /append_array _list %%{j} %;\
    /sort_array _list %;\
    /remlist %{list} -a %;\
    /let j=1 %;\
    /while (j<=countmax) \
        /eval /addlist %{list} %%{_list__%{j}} %;\
        /test ++j %;\
    /done %;\
    /clear_array _list


/def changeListFile = \
    /if ({#} != 1) \
        /echo -e %%% usage: /changeListFile <filename> %;\
        /break %;\
    /endif %;\
    /test tfclose(_filehandle_lists) %;\
    /set _filehandle_lists=$[tfopen({1},"a")]
    

/alias addlist \
    /if ({#} = 1) \
        /test tfwrite({_filehandle_lists},strcat("/set ",{1},"=",{%{1}})) %;\
    /elseif ({#} > 1) \
        /test tfwrite({_filehandle_lists},strcat("/addlist ",{*})) %;\
    /endif %;\
    /addlist %{*}

/alias remlist \
    /if ({#} >= 2) \
        /test tfwrite({_filehandle_lists},strcat("/remlist ",{*})) %;\
    /endif %;\
    /remlist %{*}



/def foreach = \
    /if ({#} < 3) \
        /echo -e %%% usage: /foreach <variable> <list> <command> %;\
        /break %;\
    /endif %;\
    /if ({1} =~ "__i") \
        /echo -e %%% /foreach: don't use __i as variable %;\
        /break %;\
    /endif %;\
    /let variable=%{1}%;\
    /let list=$(/eval /echo - %%{%{2}})%;\
    /let command=%{-2}%;\
    /while ({list} !~ "") \
        /let __i=$[strstr({list},"|")] %;\
        /if (__i<0) \
            /let %{variable}=%{list} %;\
            /let list=%;\
        /else \
            /let %{variable}=$[substr({list},0,__i)] %;\
            /let list=$[substr({list},__i+1)] %;\
        /endif %;\
        /eval -s0 %{command} %;\
    /done



/def saveAllLists = \
    /sortlist __LIST %;\
    addlist __LIST %;\
    /foreach i __LIST /eval /sortlist %%{i} %%; addlist %%{i} %;\


;;; /isamember() function for pipe-delimited lists cribbed from
;;; a collection of list macros that were the work of Joe Pelkey
;
; isamember(str, list, n)    = return the item number of 'n'th item match that
;                             exactly string matches 'str' in 'list'. If no
;                             'n'th item match, return 0.

/def isamember = \
  /let _str=%; \
  /let _listin=%; \
  /let _nmatch=1%; \
  /let _listleft=%; \
  /test _str := {1}%; \
  /test _listin := {2}%; \
  /test ({#} >= 3) & (({3} > 0) & (_nmatch := trunc({3})))%; \
  /while /test _nmatch > 0%; /do \
     /if /test regmatch(strcat("(?-i)((?:^|\\\\|)", _str, ")(\\\\||$$)"), _listin)%; /then \
      /test (_listleft := strcat(_listleft, {PL}, {P1})), \
        (_listin := strcat({P2}, {PR}))%; \
    /else \
      /return 0%; \
    /endif%; \
    /test _nmatch := (_nmatch - 1)%; \
  /done%; \
  /return (strlen({_listleft}) - strlen(replace("|", "", {_listleft})) + 1)