This file is indexed.

/usr/share/ircII/script/compl.mods is in ircii 20060725-1build1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
#	$eterna: compl.mods,v 1.3 2003/12/08 05:05:59 mrg Exp $
#
# Complete Modules by Ian Frechette
# Last updated 2-2-94
# example modules
# Don't let the size scare you.  This is a whole collection of 
# examples and comments about the design of modules
# meat of all this are the interface functions to 'complete'
# compl.add, and compl.list  (soon to be compl.del)
# the function that does the work is compl.parse  which is very small
#   and whatever parsing routine it calls.

# These should actually all be in their individual modules
# but this is just an example file..

# Note.. compl.list is internal to complete.. shoulnd't normally be used
if (compl.list == [])
{
# Note here.. Currently, if you compl.add /blah blahparse
# followed by  compl.add /blah otherparse    only the latter will
# called.  No conflict message is shown unless you replace the
# default 'null' and 'nomatch' parsers.
    compl.add -null -nomatch /m messparse
    compl.add /msg messparse
    compl.add /connect connparse
    compl.add /tr connparse
    compl.add /load loadparse
    compl.add /test testparse
    compl.add /con expand.con
    compl.add /conbunch expand.con
}


# message parser module..   Compatible with included tabscript
# currently calls the tabkey script under 3 conditions
# the input line has more than 2 argments on it.. '/msg bob thud<TAB>'
# the input line has nothing on it '<TAB>'
# the input line has only one argument and the character before the 
#   cursor is a space    '/msg bob <TAB>'
# plus it now does nickname completion
# /m D<TAB>   expands to   /m Daemon   and so on
alias messparse {
    if (([$1] != []) && ([$2] == []))
    {
        if (right(1 $*) != [ ])
        {
            # this is the simple match.. just match first occurance
            # and expand
            if (mp.cnt = match($(1)* $tk.msglist))
            {
                parsekey delete_previous_word
                # in case one does  /m =ni<TAB> it must delete the =
                if (index(#=% $1) >= 0) {parsekey backspace}
                type $word(${mp.cnt - 1} $tk.msglist)
                type ${[ ]}
            }
        }
        {
            ^tk.getmsg 1 $tk.msglist
        }
    }
    {
        ^tk.getmsg 1 $tk.msglist
    }
}


# connect module  for opers..    easily changeable to kicks, bans.. etc..
# simply use  /connect <TAB> for list or /connect <uniqid tag><TAB>
# eg.  /connect pen<TAB>  expands to  /connect penfold.ece.uiuc.edu 
# It always expands first matching string.  Look at testparse for
# a more intelligent way to do it.

@ connlist = [irc.uiuc.edu goren1.u.washington.edu ircserver.iastate.edu w6yx.stanford.edu hamblin.math.byu.edu freedom.nmsu.edu dreamtime.unm.edu ircserver.santafe.edu irc.netsys.com irc-2.mit.edu cs-mail.bu.edu]

alias connparse {
    if ([$1] != [])
	{
		@ cp.line = [$*]
		if ((right(1 $*) == [ ]) && ([$2] == [])&& ([$0] == [/connect]))
		{
			type 6667;type ${[ ]}
			# note.. if converted to use smartparse.. the port number must
			# be removed here.. the above logic conflicts with SP
		}
		{
			# expand only the first match found (See 'testparse' for better way
			if (cp.cnt = match($(${#cp.line -1})* $connlist))
			{
				delword
				type $word(${cp.cnt - 1} $connlist)
				type ${[ ]}
			}
			{
				echo *** connlist $connlist
			}
		}
    }
    {
        echo *** connlist $connlist
    }
}

# Load module
# /load net<TAB> expand to /load netsplit  and so on.
# Note the problem right now is that it only finds and expands the first
# name in the list  I think we can get around this.
@ loadlist = [netsplit ircgrep cut-paste compl.mods]
alias loadparse {
    if ([$1] != []) {
        if (lp.cnt = match($(1)* $loadlist))
        {
            parsekey delete_previous_word
            type $word(${lp.cnt - 1} $loadlist)
        }
    }
    {
        echo *** loadlist = $loadlist
    }
    ^assign -lp.cnt
}

# ############ stuff related to SMARTPARSE ###################
# The new testparse rewritten to use the
# extremely awsome smartparse routine.

if (!match(/test $compl.list)) {compl.add /test testparse}

# just a quick alias for making LINKS lists..  /makelist testlist *.edu
# will make a list of all *.edu servers..   Note that just * is 
# generally too big a list for ircII
alias makelist {
	if ([$1])
	{
		^on ^364 * push $0 $$1
		links $1-
		wait -cmd eval ^on 364 -\;echo *** makelist finished
	}
}

@ testlist = [aone atwo athree bone btwo bthree ircserver.iastate.edu ircserver.santafe.edu]

# testparse <cmd> <stuff....pat>
# this is called by the complete routines.
@ tp.tmp = [0 :]
# [0 :] represents a count of 0.. and a null pattern :<pat> 
alias testparse {
	# ignore this first line.. 
	@ tp.cnt = [$*]
	@ tp.cnt = #tp.cnt
	^assign -tp.pat 
	# all the cnt stuff is in case you do  /command word1 word2 pattern<tab>
	if (tp.cnt > 1)
	{
		@ tp.pat = [$(${tp.cnt - 1})]
		# '/command pattern ' leaves <pat> null
		# '/command pattern'  sets <pat> to a new pattern
		# important because smartparse may leave a space
		if (right(1 $L) != [ ]) {@ tp.tmp = [0 :$tp.pat]}

		# Uncomment the following line to see how it works from here.. debugging
		# echo smartparse\($tp.tmp testlist $tp.pat\)

		# call testparse with current cnt :<pat> <listname> <newpat>
		@ tp.tmp = smartparse($tp.tmp testlist $tp.pat)
		# note tp.tmp accounts for two arguments.. and is modified and saved

		if (left(1 $word(1 $tp.tmp)) == [,])
		{echo *** no match for pattern [$tp.pat] found in list} 
		{if (left(1 $word(1 $tp.tmp)) == [.])
		{echo *** testlist: $testlist}}
	}
	{
		echo *** testlist : $testlist
	}
}

alias test echo *** TEST: You've matched: $*

# test module
# Trying to make some sort of intelligent handling of the tab lists.
@ sp.cnt = 0

# call it with smartparse <cnt> :<pat> <listname> <newpat>
#                          $0    $1       $2        $3
# returns <counter> [:,.]<pattern>
#                    : == successful match   , == no match  . == null
#
#  Look at how testparse uses it.. you shouldn't have to touch any
# smartparse vars.. It's all handled through the interface.. basically
# you're telling it where to start looking in the list and how
# long the list is..   Each time smartparse is called it returns a counter
# value indicating where it left off last time.  You can save it
# or not..   testparse saves it.. and passes it back as the new
# starting position  <cnt>
#
# Assuming the counter, pattern, and list are maintained through each call
# it'll assume you're searching forward in the list from some place
# after the last word matched in the list..   
#
# If you feed it a <newpat> for which <pat> is not a subset, it'll reassign
# <pat> to <newpat> and restart the process.. 
# It defaults to expansion..  so..  <pat> = blah
# will match blahone, blahtwo etc. Works with wildcards.. *a* matches a lot
# Try it.

^assign -sp.tmp
alias smartparse {
# int sp.tmp     - index of last match found
# int sp.cnt     - position in list
# int sp.max     - max number of elements in list
# string sp.pat  - match pattern 
    if ([$3] != [])
    {
		# Extract <pat> from  :<pat>    Note.. It may be null
        @ sp.pat = mid(1 50 $1)
		@ sp.max = [$(#$2)]
		@ sp.cnt = [$0]
        # set pattern.   Determine if we've changed the base pattern or not
        if (sp.pat == [])
            {@ sp.pat = [$3]}
            { if (!match($(sp.pat)* $3)) {@sp.pat = [$3]} }
        @ sp.run = 1

        while (((sp.list = words($sp.cnt $sp.max $($2))) != []) && (!sp.tmp) && sp.run)
        {
			# look for match in list
            if (sp.tmp = match($(sp.pat)* $sp.list))
            {
                # sp.cnt is absolute position in list.  Jump over found item.
				# to set up for the next call to smartparse
                @ sp.cnt = sp.cnt + sp.tmp

                # parsekey delete_previous_word
                delword
                type $word(${sp.tmp - 1} $sp.list)
                type ${[ ]}
            }
            {
                # nothing found.. drop out of loop
				# for this condidtion to occur we must be at the beginning
				# of the loop... either first pass.. or just looped back
                if (!sp.cnt && !sp.tmp)
                {
					# notfound condition set for return value later
					@ sp.notfound = [$sp.cnt ,$sp.pat]
                    @ sp.run = 0
                    # echo *** smartparse: no matching pattern
                }
				# loop back
                @ sp.cnt = 0
            }
        }
        ^assign -sp.tmp
        if (!sp.list) {@sp.cnt = 0}
        ^assign -sp.list
        if (sp.notfound == [])
			{@ function_return = [$sp.cnt :$sp.pat]}
			{@ function_return = sp.notfound;^assign -sp.notfound}
    }
    {
	# echo *** sp NULL
        # echo *** $2: $($2)
        @ function_return = [$sp.cnt .$sp.pat]
    }
    ^assign -sp.run
}

# alias words.. usage   $word(<begin> <end> <words>)
# words(0 2 zero one two three ... ) ==  'zero one two'  and so on
alias words {
    @ function_return = [$(${[$0]+2}-${[$1] +2})]
}

# This is like  DELETE_PREVIOUS_WORD except that it delets to the
# previous space which is much more useful than the current
# behavior of deleting to the previos non- [a-zA-Z0-9] char. :-?
alias delword {
    parsekey erase_to_end_of_line
    if ((dw.char = right(1 $L)) != [ ]) {@ dw.nw = 0} {@dw.nw = 1}
    while (((dw.char != [ ]) || dw.nw) && (dw.char != []))
    {
        parsekey backspace
        if ((dw.char = right(1 $L)) != [ ]) {@ dw.nw = 0}
    }
    ^assign -dw.char;^assign -dw.nw
}


# it is of course possible to do command completion with something like
alias expand.con parsekey erase_to_beg_of_line;type /connect $()
# /con<tab> expands to /connect

# Be careful though.. note the $() at the end of the line.
# Without this 'complete' sends expand.con /con   and the above
# alias will add the '/con' back onto the end of the line resulting
# in /connect /con     on the input line when you're done


# # # # # # # # # # MODULE WRITING PHILOSOPHY # # # # # # # # # #
# Some thoughts about using complete and designing complete modules.
#
# Basically for any given time you hit TAB there are three states
# normal, null, and nomatch
# normal - there is something on the command line to process
#   and the command is in the command list maintained by 'complete'
#   The associated command parser is called with the contents of the
#   input line in its entirety as the arguments.
# null -  there is nothing at all on the command line and some
#   default action must be taken.  No parser need be called at all as well.
# nomatch - the command at the head of the input line is not
#   found in the list of commands maintained by 'complete'.
#   A default 'nomatch' parser may or may not be called but if it is called
#   it's passed the entire contents of the input line.
#
# This is not the end of the story however.
# If you're writing a completion module of some sort there are the same
# 3 states plus 1 more.  Let's say you want to write something to 
# find a match for a given keyword prefix out of a list when you hit
# TAB.  e.g. /eat ap<TAB>   looks for matching words that start with ap
# The 4 actions are
# normal - There is a single match for ap and it expands /eat apple
# multiple matches - There is more than one match for ap and thus
#   a choice must be made.  Possible choices include
#   1. do nothing
#   2. list possible matches   (like ^D) or set showmatch in tcsh shell
#      *** matches for prefix 'ap': apple apricot apendage
#   3. match only the first occurance  Currently what the /connect module
#      does    /eat apple
#   4. cycle through the possible matches for the keyword 'ap'.
#      The 'testparse' modules uses this scheme and it's my favorite
#      albiet a tad more expensive in terms of CPU cycles and responce
#      time. (I'm sure someone could see the diff.. I can't ;)
#      /eat ap<TAB> -> /eat apple<TAB> -> /eat apricot<TAB> etc.. 
#   5. display worthless error message
#      *** non-unique matches found
# nomatch - as as before, nomatching keywords are found, the choices are
#   limited to things like displaying the whole list or just cycling through
#   to the next item in the list like the 'tabkey' script's 'messparse' does.
# null - This one is more likely to happen only if 'complete' saw the
#   input line as null, but then the null action is ussually special anyway.
#   Otherwise this may occur when you say just /eat<TAB> and the obvious
#   thing to do here is just to display the list of items to choose from
#   in an appropriate format.

# Just remember.. the parsing routine can really do anything it wants.. 
# it could simply 'sendline' the line on to the server and push a
# button to start WWIII when you hit tab.. It doesn't have to mess with the
# command line but it's more useful that way.  Although.. you could write
# a tab completion module that when tab was hit.. it spell checked
# the line.. anything is possible..