/[cmucl]/src/code/string.lisp
ViewVC logotype

Contents of /src/code/string.lisp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (hide annotations) (vendor branch)
Wed Apr 11 17:15:21 1990 UTC (24 years ago) by wlott
Changes since 1.1: +26 -25 lines
Initial MIPS version.
1 ram 1.1 ;;; -*- Log: code.log; Package: Lisp -*-
2     ;;;
3     ;;; **********************************************************************
4     ;;; This code was written as part of the Spice Lisp project at
5     ;;; Carnegie-Mellon University, and has been placed in the public domain.
6     ;;; If you want to use this code or any part of Spice Lisp, please contact
7     ;;; Scott Fahlman (FAHLMAN@CMUC).
8     ;;; **********************************************************************
9     ;;;
10     ;;; Functions to implement strings for Spice Lisp
11     ;;; Written by David Dill
12     ;;; Rewritten and currently maintained by Skef Wholey
13     ;;;
14     ;;; Runs in the standard Spice Lisp environment.
15     ;;;
16     ;;; ****************************************************************
17     ;;;
18     (in-package 'lisp)
19     (export '(char schar string
20     string= string-equal string< string> string<= string>= string/=
21     string-lessp string-greaterp string-not-lessp string-not-greaterp
22     string-not-equal
23     make-string
24     string-trim string-left-trim string-right-trim
25     string-upcase
26     string-downcase string-capitalize nstring-upcase nstring-downcase
27     nstring-capitalize))
28    
29     (eval-when (compile)
30    
31     ;;; %String returns its arg if it is a string, otherwise calls String.
32     ;;;
33     (defmacro %string (thing)
34     `(if (stringp ,thing) ,thing (string ,thing)))
35     )
36    
37     (defun string (X)
38     "Coerces X into a string. If X is a string, X is returned. If X is a
39     symbol, X's pname is returned. If X is a character then a one element
40     string containing that character is returned. If X cannot be coerced
41     into a string, an error occurs."
42     (cond ((stringp x) x)
43     ((symbolp x) (symbol-name x))
44     ((characterp x)
45     (let ((res (make-string 1)))
46     (setf (schar res 0) x) res))
47     (t
48     (error "~S cannot be coerced to a string." x))))
49    
50    
51     ;;; With-One-String is used to set up some string hacking things. The keywords
52     ;;; are parsed, and the string is hacked into a simple-string.
53    
54     (eval-when (compile)
55    
56     (defmacro with-one-string (string start end cum-offset &rest forms)
57     (let ((data (gensym))
58     (data-start (gensym))
59     (data-end (gensym))
60     (offset (gensym)))
61     `(progn
62 wlott 1.1.1.1 (if (symbolp ,string)
63     (setf ,string (symbol-name ,string)))
64     (if (array-header-p ,string)
65     (with-array-data ((,data ,string :offset-var ,offset)
66     (,data-start ,start)
67     (,data-end (or ,end
68     (length (the simple-string
69     ,string)))))
70     (psetq ,string ,data
71     ,cum-offset ,offset
72     ,start ,data-start
73     ,end ,data-end))
74     (if (not ,end) (setq ,end (length (the simple-string ,string)))))
75 ram 1.1 ,@forms)))
76    
77     )
78    
79     ;;; With-String is like With-One-String, but doesn't parse keywords.
80    
81     (eval-when (compile)
82    
83     (defmacro with-string (string &rest forms)
84     `(let ((start 0)
85     (end ()))
86     (if (symbolp ,string) (setq ,string (symbol-name ,string)))
87     (if (array-header-p ,string)
88     (with-array-data ((data ,string)
89     (data-start start)
90 wlott 1.1.1.1 (data-end (length (the simple-string ,string))))
91 ram 1.1 (psetq ,string data
92     start data-start
93     end data-end))
94     (setq end (length (the simple-string ,string))))
95     ,@forms))
96    
97     )
98    
99     ;;; With-Two-Strings is used to set up string comparison operations. The
100     ;;; keywords are parsed, and the strings are hacked into simple-strings.
101    
102     (eval-when (compile)
103    
104     (defmacro with-two-strings (string1 string2 start1 end1 cum-offset-1
105     start2 end2 &rest forms)
106     (let ((data (gensym))
107     (data-start (gensym))
108     (data-end (gensym))
109     (offset (gensym)))
110     `(progn
111     (if (symbolp ,string1) (setq ,string1 (symbol-name ,string1)))
112     (if (symbolp ,string2) (setq ,string2 (symbol-name ,string2)))
113     (if (array-header-p ,string1)
114     (with-array-data ((,data ,string1 :offset-var ,offset)
115     (,data-start ,start1)
116     (,data-end (or ,end1
117 wlott 1.1.1.1 (length (the simple-string
118     ,string1)))))
119     (psetq ,string1 ,data
120     ,cum-offset-1 ,offset
121     ,start1 ,data-start
122     ,end1 ,data-end))
123 ram 1.1 (if (not ,end1) (setq ,end1 (length (the simple-string ,string1)))))
124     (if (array-header-p ,string2)
125     (with-array-data ((,data ,string2)
126     (,data-start ,start2)
127     (,data-end (or ,end2
128 wlott 1.1.1.1 (length (the simple-string
129     ,string2)))))
130     (psetq ,string2 ,data
131     ,start2 ,data-start
132     ,end2 ,data-end))
133 ram 1.1 (if (not ,end2) (setq ,end2 (length (the simple-string ,string2)))))
134     ,@forms)))
135    
136     )
137 wlott 1.1.1.1
138 ram 1.1
139     (defun char (string index)
140     "Given a string and a non-negative integer index less than the length of
141     the string, returns the character object representing the character at
142     that position in the string."
143     (char string index))
144    
145     (defun %charset (string index new-el)
146     (setf (char string index) new-el))
147    
148     (defun schar (string index)
149     "SCHAR returns the character object at an indexed position in a string
150     just as CHAR does, except the string must be a simple-string."
151     (schar string index))
152    
153     (defun %scharset (string index new-el)
154     (setf (schar string index) new-el))
155    
156     (defun string=* (string1 string2 start1 end1 start2 end2)
157     (let ((offset1 0))
158     (with-two-strings string1 string2 start1 end1 offset1 start2 end2
159     (not (%sp-string-compare string1 start1 end1 string2 start2 end2)))))
160    
161    
162     (defun string/=* (string1 string2 start1 end1 start2 end2)
163     (let ((offset1 0))
164     (with-two-strings string1 string2 start1 end1 offset1 start2 end2
165     (let ((comparison (%sp-string-compare string1 start1 end1
166     string2 start2 end2)))
167     (if comparison (- (the fixnum comparison) offset1))))))
168    
169     (eval-when (compile eval)
170    
171     ;;; Lessp is true if the desired expansion is for string<* or string<=*.
172     ;;; Equalp is true if the desired expansion is for string<=* or string>=*.
173     (defmacro string<>=*-body (lessp equalp)
174     (let ((offset1 (gensym)))
175     `(let ((,offset1 0))
176     (declare (fixnum ,offset1))
177     (with-two-strings string1 string2 start1 end1 ,offset1 start2 end2
178     (let ((index (%sp-string-compare string1 start1 end1
179     string2 start2 end2)))
180     (if index
181     (cond ((= (the fixnum index)
182     ,(if lessp `(the fixnum end1) `(the fixnum end2)))
183     (- (the fixnum index) ,offset1))
184     ((= (the fixnum index)
185     ,(if lessp `(the fixnum end2) `(the fixnum end1)))
186     nil)
187     ((,(if lessp 'char< 'char>)
188     (schar string1 index)
189     (schar string2 (+ (the fixnum index) (- start2 start1))))
190     (- (the fixnum index) ,offset1))
191     (t nil))
192     ,(if equalp `(- (the fixnum end1) ,offset1) 'nil)))))))
193     ) ; eval-when
194    
195     (defun string<* (string1 string2 start1 end1 start2 end2)
196     (declare (fixnum start1 start2))
197     (string<>=*-body t nil))
198    
199     (defun string>* (string1 string2 start1 end1 start2 end2)
200     (declare (fixnum start1 start2))
201     (string<>=*-body nil nil))
202    
203     (defun string<=* (string1 string2 start1 end1 start2 end2)
204     (declare (fixnum start1 start2))
205     (string<>=*-body t t))
206    
207     (defun string>=* (string1 string2 start1 end1 start2 end2)
208     (declare (fixnum start1 start2))
209     (string<>=*-body nil t))
210    
211    
212    
213     (defun string< (string1 string2 &key (start1 0) end1 (start2 0) end2)
214     "Given two strings, if the first string is lexicographically less than
215     the second string, returns the longest common prefix (using char=)
216     of the two strings. Otherwise, returns ()."
217     (string<* string1 string2 start1 end1 start2 end2))
218    
219     (defun string> (string1 string2 &key (start1 0) end1 (start2 0) end2)
220     "Given two strings, if the first string is lexicographically greater than
221     the second string, returns the longest common prefix (using char=)
222     of the two strings. Otherwise, returns ()."
223     (string>* string1 string2 start1 end1 start2 end2))
224    
225    
226     (defun string<= (string1 string2 &key (start1 0) end1 (start2 0) end2)
227     "Given two strings, if the first string is lexicographically less than
228     or equal to the second string, returns the longest common prefix
229     (using char=) of the two strings. Otherwise, returns ()."
230     (string<=* string1 string2 start1 end1 start2 end2))
231    
232     (defun string>= (string1 string2 &key (start1 0) end1 (start2 0) end2)
233     "Given two strings, if the first string is lexicographically greater
234     than or equal to the second string, returns the longest common prefix
235     (using char=) of the two strings. Otherwise, returns ()."
236     (string>=* string1 string2 start1 end1 start2 end2))
237    
238     (defun string= (string1 string2 &key (start1 0) end1 (start2 0) end2)
239     "Given two strings (string1 and string2), and optional integers start1,
240     start2, end1 and end2, compares characters in string1 to characters in
241     string2 (using char=)."
242     (string=* string1 string2 start1 end1 start2 end2))
243    
244     (defun string/= (string1 string2 &key (start1 0) end1 (start2 0) end2)
245     "Given two strings, if the first string is not lexicographically equal
246     to the second string, returns the longest common prefix (using char=)
247     of the two strings. Otherwise, returns ()."
248     (string/=* string1 string2 start1 end1 start2 end2))
249    
250    
251     (eval-when (compile eval)
252    
253     ;;; STRING-NOT-EQUAL-LOOP is used to generate character comparison loops for
254     ;;; STRING-EQUAL and STRING-NOT-EQUAL.
255     (defmacro string-not-equal-loop (end end-value
256     &optional (abort-value nil abortp))
257     (declare (fixnum end))
258     (let ((end-test (if (= end 1)
259     `(= index1 (the fixnum end1))
260     `(= index2 (the fixnum end2)))))
261     `(do ((index1 start1 (1+ index1))
262     (index2 start2 (1+ index2)))
263     (,(if abortp
264     end-test
265     `(or ,end-test
266     (not (char-equal (schar string1 index1)
267     (schar string2 index2)))))
268     ,end-value)
269     (declare (fixnum index1 index2))
270     ,@(if abortp
271     `((if (not (char-equal (schar string1 index1)
272     (schar string2 index2)))
273     (return ,abort-value)))))))
274    
275     ) ; eval-when
276    
277     (defun string-equal (string1 string2 &key (start1 0) end1 (start2 0) end2)
278     "Given two strings (string1 and string2), and optional integers start1,
279     start2, end1 and end2, compares characters in string1 to characters in
280     string2 (using char-equal)."
281     (declare (fixnum start1 start2))
282     (let ((offset1 0))
283     (with-two-strings string1 string2 start1 end1 offset1 start2 end2
284     (let ((slen1 (- (the fixnum end1) start1))
285     (slen2 (- (the fixnum end2) start2)))
286     (declare (fixnum slen1 slen2))
287     (if (or (minusp slen1) (minusp slen2))
288     ;;prevent endless looping later.
289     (error "Improper bounds for string comparison."))
290     (if (= slen1 slen2)
291     ;;return () immediately if lengths aren't equal.
292     (string-not-equal-loop 1 t nil))))))
293    
294     (defun string-not-equal (string1 string2 &key (start1 0) end1 (start2 0) end2)
295     "Given two strings, if the first string is not lexicographically equal
296     to the second string, returns the longest common prefix (using char-equal)
297     of the two strings. Otherwise, returns ()."
298     (let ((offset1 0))
299     (declare (fixnum offset1))
300     (with-two-strings string1 string2 start1 end1 offset1 start2 end2
301     (let ((slen1 (- end1 start1))
302     (slen2 (- end2 start2)))
303     (declare (fixnum slen1 slen2))
304     (if (or (minusp slen1) (minusp slen2))
305     ;;prevent endless looping later.
306     (error "Improper bounds for string comparison."))
307     (cond ((or (minusp slen1) (or (minusp slen2)))
308     (error "Improper substring for comparison."))
309     ((= slen1 slen2)
310     (string-not-equal-loop 1 nil (- index1 offset1)))
311     ((< slen1 slen2)
312     (string-not-equal-loop 1 (- index1 offset1)))
313     (t
314     (string-not-equal-loop 2 (- index1 offset1))))))))
315    
316    
317    
318     (eval-when (compile eval)
319    
320     ;;; STRING-LESS-GREATER-EQUAL-TESTS returns a test on the lengths of string1
321     ;;; and string2 and a test on the current characters from string1 and string2
322     ;;; for the following macro.
323     (defun string-less-greater-equal-tests (lessp equalp)
324     (if lessp
325     (if equalp
326     ;; STRING-NOT-GREATERP
327     (values '<= `(not (char-greaterp char1 char2)))
328     ;; STRING-LESSP
329     (values '< `(char-lessp char1 char2)))
330     (if equalp
331     ;; STRING-NOT-LESSP
332     (values '>= `(not (char-lessp char1 char2)))
333     ;; STRING-GREATERP
334     (values '> `(char-greaterp char1 char2)))))
335    
336     (defmacro string-less-greater-equal (lessp equalp)
337     (multiple-value-bind (length-test character-test)
338     (string-less-greater-equal-tests lessp equalp)
339     `(let ((offset1 0))
340     (declare (fixnum offset1))
341     (with-two-strings string1 string2 start1 end1 offset1 start2 end2
342     (let ((slen1 (- (the fixnum end1) start1))
343     (slen2 (- (the fixnum end2) start2)))
344     (declare (fixnum slen1 slen2))
345     (if (or (minusp slen1) (minusp slen2))
346     ;;prevent endless looping later.
347     (error "Improper bounds for string comparison."))
348     (do ((index1 start1 (1+ index1))
349     (index2 start2 (1+ index2))
350     (char1)
351     (char2))
352     ((or (= index1 (the fixnum end1)) (= index2 (the fixnum end2)))
353     (if (,length-test slen1 slen2) (- index1 offset1)))
354     (declare (fixnum index1 index2))
355     (setq char1 (schar string1 index1))
356     (setq char2 (schar string2 index2))
357     (if (not (char-equal char1 char2))
358     (if ,character-test
359     (return (- index1 offset1))
360     (return ())))))))))
361    
362     ) ; eval-when
363    
364     (defun string-lessp* (string1 string2 start1 end1 start2 end2)
365     (declare (fixnum start1 start2))
366     (string-less-greater-equal t nil))
367    
368     (defun string-greaterp* (string1 string2 start1 end1 start2 end2)
369     (declare (fixnum start1 start2))
370     (string-less-greater-equal nil nil))
371    
372     (defun string-not-lessp* (string1 string2 start1 end1 start2 end2)
373     (declare (fixnum start1 start2))
374     (string-less-greater-equal nil t))
375    
376     (defun string-not-greaterp* (string1 string2 start1 end1 start2 end2)
377     (declare (fixnum start1 start2))
378     (string-less-greater-equal t t))
379    
380     (defun string-lessp (string1 string2 &key (start1 0) end1 (start2 0) end2)
381     "Given two strings, if the first string is lexicographically less than
382     the second string, returns the longest common prefix (using char-equal)
383     of the two strings. Otherwise, returns ()."
384     (string-lessp* string1 string2 start1 end1 start2 end2))
385    
386     (defun string-greaterp (string1 string2 &key (start1 0) end1 (start2 0) end2)
387     "Given two strings, if the first string is lexicographically greater than
388     the second string, returns the longest common prefix (using char-equal)
389     of the two strings. Otherwise, returns ()."
390     (string-greaterp* string1 string2 start1 end1 start2 end2))
391    
392     (defun string-not-lessp (string1 string2 &key (start1 0) end1 (start2 0) end2)
393     "Given two strings, if the first string is lexicographically greater
394     than or equal to the second string, returns the longest common prefix
395     (using char-equal) of the two strings. Otherwise, returns ()."
396     (string-not-lessp* string1 string2 start1 end1 start2 end2))
397    
398     (defun string-not-greaterp (string1 string2 &key (start1 0) end1 (start2 0)
399     end2)
400     "Given two strings, if the first string is lexicographically less than
401     or equal to the second string, returns the longest common prefix
402     (using char-equal) of the two strings. Otherwise, returns ()."
403     (string-not-greaterp* string1 string2 start1 end1 start2 end2))
404    
405    
406     (defun make-string (count &key ((:initial-element fill-char)))
407     "Given a character count and an optional fill character, makes and returns
408     a new string Count long filled with the fill character."
409     (declare (fixnum count))
410     (if fill-char
411     (do ((i 0 (1+ i))
412     (string (make-string count)))
413     ((= i count) string)
414     (declare (fixnum i))
415     (setf (schar string i) fill-char))
416     (make-string count)))
417    
418     (defun string-upcase (string &key (start 0) end)
419     "Given a string, returns a new string that is a copy of it with
420     all lower case alphabetic characters converted to uppercase."
421     (declare (fixnum start))
422     (if (symbolp string) (setq string (symbol-name string)))
423     (let ((slen (length string))
424     (offset 0))
425     (declare (fixnum slen offset))
426     (with-one-string string start end offset
427     (let ((offset-slen (+ slen offset))
428     (newstring (make-string slen)))
429     (declare (fixnum offset-slen))
430     (do ((index offset (1+ index))
431     (new-index 0 (1+ new-index)))
432     ((= index start))
433     (declare (fixnum index new-index))
434     (setf (schar newstring new-index) (schar string index)))
435     (do ((index start (1+ index))
436     (new-index (- start offset) (1+ new-index)))
437     ((= index (the fixnum end)))
438     (declare (fixnum index new-index))
439     (setf (schar newstring new-index)
440     (char-upcase (schar string index))))
441     (do ((index end (1+ index))
442     (new-index (- (the fixnum end) offset) (1+ new-index)))
443     ((= index offset-slen))
444     (declare (fixnum index new-index))
445     (setf (schar newstring new-index) (schar string index)))
446     newstring))))
447    
448     (defun string-downcase (string &key (start 0) end)
449     "Given a string, returns a new string that is a copy of it with
450     all upper case alphabetic characters converted to lowercase."
451     (declare (fixnum start))
452     (if (symbolp string) (setq string (symbol-name string)))
453     (let ((slen (length string))
454     (offset 0))
455     (declare (fixnum slen offset))
456     (with-one-string string start end offset
457     (let ((offset-slen (+ slen offset))
458     (newstring (make-string slen)))
459     (declare (fixnum offset-slen))
460     (do ((index offset (1+ index))
461     (new-index 0 (1+ new-index)))
462     ((= index start))
463     (declare (fixnum index new-index))
464     (setf (schar newstring new-index) (schar string index)))
465     (do ((index start (1+ index))
466     (new-index (- start offset) (1+ new-index)))
467     ((= index (the fixnum end)))
468     (declare (fixnum index new-index))
469     (setf (schar newstring new-index)
470     (char-downcase (schar string index))))
471     (do ((index end (1+ index))
472     (new-index (- (the fixnum end) offset) (1+ new-index)))
473     ((= index offset-slen))
474     (declare (fixnum index new-index))
475     (setf (schar newstring new-index) (schar string index)))
476     newstring))))
477    
478     (defun string-capitalize (string &key (start 0) end)
479     "Given a string, returns a copy of the string with the first
480     character of each ``word'' converted to upper-case, and remaining
481     chars in the word converted to lower case. A ``word'' is defined
482     to be a string of case-modifiable characters delimited by
483     non-case-modifiable chars."
484     (declare (fixnum start))
485     (if (symbolp string) (setq string (symbol-name string)))
486     (let ((slen (length string))
487     (offset 0))
488     (declare (fixnum slen offset))
489     (with-one-string string start end offset
490     (let ((offset-slen (+ slen offset))
491     (newstring (make-string slen)))
492     (declare (fixnum offset-slen))
493     (do ((index offset (1+ index))
494     (new-index 0 (1+ new-index)))
495     ((= index start))
496     (declare (fixnum index new-index))
497     (setf (schar newstring new-index) (schar string index)))
498     (do ((index start (1+ index))
499     (new-index (- start offset) (1+ new-index))
500     (newword t)
501     (char ()))
502     ((= index (the fixnum end)))
503     (declare (fixnum index new-index))
504     (setq char (schar string index))
505     (cond ((not (alphanumericp char))
506     (setq newword t))
507     (newword
508     ;;char is first case-modifiable after non-case-modifiable
509     (setq char (char-upcase char))
510     (setq newword ()))
511     ;;char is case-modifiable, but not first
512     (t (setq char (char-downcase char))))
513     (setf (schar newstring new-index) char))
514     (do ((index end (1+ index))
515     (new-index (- (the fixnum end) offset) (1+ new-index)))
516     ((= index offset-slen))
517     (declare (fixnum index new-index))
518     (setf (schar newstring new-index) (schar string index)))
519     newstring))))
520    
521     (defun nstring-upcase (string &key (start 0) end)
522     "Given a string, returns that string with all lower case alphabetic
523     characters converted to uppercase."
524     (declare (fixnum start))
525     (let ((save-header string)
526     offset)
527     (with-one-string string start end offset
528     (do ((index start (1+ index)))
529     ((= index (the fixnum end)))
530     (declare (fixnum index))
531     (setf (schar string index) (char-upcase (schar string index)))))
532     save-header))
533    
534     (defun nstring-downcase (string &key (start 0) end)
535     "Given a string, returns that string with all upper case alphabetic
536     characters converted to lowercase."
537     (declare (fixnum start))
538     (let ((save-header string)
539     offset)
540     (with-one-string string start end offset
541     (do ((index start (1+ index)))
542     ((= index (the fixnum end)))
543     (declare (fixnum index))
544     (setf (schar string index) (char-downcase (schar string index)))))
545     save-header)))
546    
547     (defun nstring-capitalize (string &key (start 0) end)
548     "Given a string, returns that string with the first
549     character of each ``word'' converted to upper-case, and remaining
550     chars in the word converted to lower case. A ``word'' is defined
551     to be a string of case-modifiable characters delimited by
552     non-case-modifiable chars."
553     (declare (fixnum start))
554     (let ((save-header string)
555     offset)
556     (with-one-string string start end offset
557     (do ((index start (1+ index))
558     (newword t)
559     (char ()))
560     ((= index (the fixnum end)))
561     (declare (fixnum index))
562     (setq char (schar string index))
563     (cond ((not (alphanumericp char))
564     (setq newword t))
565     (newword
566     ;;char is first case-modifiable after non-case-modifiable
567     (setf (schar string index) (char-upcase char))
568     (setq newword ()))
569     (t
570     (setf (schar string index) (char-downcase char))))))
571     save-header))
572    
573     (defun string-left-trim (char-bag string)
574     "Given a set of characters (a list or string) and a string, returns
575     a copy of the string with the characters in the set removed from the
576     left end."
577     (with-string string
578     (do ((index start (1+ index)))
579     ((or (= index (the fixnum end))
580     (not (find (schar string index) char-bag)))
581     (subseq (the simple-string string) index end))
582     (declare (fixnum index)))))
583    
584     (defun string-right-trim (char-bag string)
585     "Given a set of characters (a list or string) and a string, returns
586     a copy of the string with the characters in the set removed from the
587     right end."
588     (with-string string
589     (do ((index (1- (the fixnum end)) (1- index)))
590     ((or (< index start) (not (find (schar string index) char-bag)))
591     (subseq (the simple-string string) start (1+ index)))
592     (declare (fixnum index)))))
593    
594     (defun string-trim (char-bag string)
595     "Given a set of characters (a list or string) and a string, returns a
596     copy of the string with the characters in the set removed from both
597     ends."
598     (with-string string
599     (let* ((left-end (do ((index start (1+ index)))
600     ((or (= index (the fixnum end))
601     (not (find (schar string index) char-bag)))
602     index)
603     (declare (fixnum index))))
604     (right-end (do ((index (1- (the fixnum end)) (1- index)))
605     ((or (< index left-end)
606     (not (find (schar string index) char-bag)))
607     (1+ index))
608     (declare (fixnum index)))))
609     (subseq (the simple-string string) left-end right-end))))

  ViewVC Help
Powered by ViewVC 1.1.5