This file is indexed.

/usr/share/scsh-0.6/scsh/stringcoll.scm is in scsh-common-0.6 0.6.7-8.

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
;;; Copyright (c) 1994 by Olin Shivers

;;; String collectors
;;; ===========================================================================
;;; string-colllector
;;; (make-string-collector)
;;; (collect-string! SC S)
;;; (clear-string-collector! SC)
;;; (string-collector->string SC)
;;;
;;; A string collector is a data structure that reduces the overhead of
;;; accumulating a large string in bits and pieces. It is basically a 
;;; "chunk list," where a chunk is a string of at least 128 chars. In this
;;; way, the list overhead is kept under 2% of the whole data structure.
;;; When a new string is added to the collection, it is added to the current
;;; chunk. When the chunk reaches 128 chars, it is added to the chunk list,
;;; and a new chunk is started. If a large string is added to the collection, 
;;; it is added as a chunk itself, so large strings are not split into small 
;;; pieces. (Actually, a *copy* of the original large string is saved as a 
;;; single chunk, so the collector's chunks are not shared with client data.)
;;;
;;; MAKE-STRING-COLLECTOR allocates a new string collector data structure.
;;; COLLECT-STRING! appends a string to the current collection.
;;; CLEAR-STRING-COLLECTOR! clears out accumulated strings from a collector.
;;; STRING-COLLECTOR->STRING converts a collector into a contiguous string.
;;;
;;; This facility makes it reasonably efficient to accumulate strings
;;; of any size in increments of any size.

(define-record string-collector
  (len 0)		; How many chars have we accumulated?
  (chunks '())		; The chunk list.
  (chunk #f)		; The current chunk being filled, if any.
  (chunk-left  0))	; How many chars left to fill in the current chunk.

(define (clear-string-collector! sc)
  (set-string-collector:len    sc 0)
  (set-string-collector:chunks sc '())
  (set-string-collector:chunk  sc #f)
  sc)

;;; (COLLECT-STRING! sc s)
;;; ----------------------
;;; S is a string. Append it to the string being collected in the
;;; string-collector SC.
;;;
;;; The algorithm:
;;; First, do nothing if S is the empty string. Otherwise:
;;; If there is a current chunk:
;;;    Copy characters from S into it.
;;;    If we filled up the chunk
;;;        Put the chunk on the chunk list.
;;;        Look at the remaining chars from S we haven't copied yet.
;;;        If there a lot of characters left (>= 128)
;;;            Save them as a single chunk on the chunk list.
;;;            No current chunk.
;;;	   Else if there a just a few characters left (> 0, < 128)
;;;            Start a new current chunk, copy the chars left into it.
;;;        Else if there aren't any characters left
;;;            No current chunk.
;;;
;;; If there is no current chunk:
;;;     If there are a lot of characters in S (>= 128)
;;;         Save a copy of S as a single chunk on the chunk list.
;;;         Still no current chunk.
;;;     Else if there are a few characters in S (> 0, < 128)
;;;         Start a new current chunk, copy the S into it.

(define (collect-string! sc s)
  (let ((slen (string-length s))
	(chunk (string-collector:chunk sc))
	(chunk-left (string-collector:chunk-left sc))

	;; Add the chunk C to the collector's chunk list.
	(push-chunk! (lambda (c)
		       (set-string-collector:chunks sc
		           (cons c (string-collector:chunks sc)))))

	;; Copy nchars characters from src[j] to dest[i]
	;; *Way* too much bounds checking going on in this loop.
	(copy-substring! (lambda (dest i src j nchars)
	  (do ((i i (+ i 1))
	       (j j (+ j 1))
	       (nchars nchars (- nchars 1)))
	      ((zero? nchars))
	    (string-set! dest i (string-ref src j))))))

    (cond ((zero? slen)) ; Empty string, do nothing.
	  (chunk
	   (let ((ncopy (min slen chunk-left)))
	     (copy-substring! chunk (- 128 chunk-left) s 0 ncopy)
	     (if (> chunk-left slen)
		 (set-string-collector:chunk-left sc (- chunk-left slen))
		 ;; Current chunk is full.
		 (let ((s-left (- slen chunk-left)))
		   (push-chunk! chunk) ; Push the current chunk.
		   ;; Handle remaining chars from S that weren't copied into
		   ;; the current chunk we just pushed:
		   (cond ((>= s-left 128)
			  ;; A lot more chars left. Push them as one chunk.
			  (push-chunk! (substring s chunk-left slen))
			  (set-string-collector:chunk sc #f))
			 ((> s-left 0)
			  ;; A few more chars left. Start a new chunk.
			  (let ((new-chunk (make-string 128)))
			    (copy-substring! new-chunk 0 s chunk-left s-left)
			    (set-string-collector:chunk sc new-chunk)
			    (set-string-collector:chunk-left sc
							     (- 128 s-left))))
			 ;; No more chars left. No current chunk.
			 (else (set-string-collector:chunk sc #f)))))))

	  (else ; No current chunk.
	   (if (>= slen 128)  ; How many chars is S?
	       (push-chunk! (string-copy s))    ; A lot. Push as one chunk.
	       (let ((chunk (make-string 128))) ; Not many. Start a new chunk.
		    (set-string-collector:chunk sc chunk)
		    (copy-substring! chunk 0 s 0 slen)
		    (set-string-collector:chunk-left sc (- 128 slen))))))

  ;; We don't actually do anything with this, but we keep it updated anyway.
  (set-string-collector:len sc (+ (string-collector:len sc) slen))
  sc))
			      
		 
;;; A bummed version for collecting a single character.

(define (collect-char! sc c)
  (let ((chunk (string-collector:chunk sc))
	(chunk-left (string-collector:chunk-left sc)))

    (cond (chunk
	   (string-set! chunk (- 128 chunk-left) c)
	   (cond ((> chunk-left 1)
		  (set-string-collector:chunk-left sc (- chunk-left 1)))
		 (else
		  (set-string-collector:chunks sc
		       (cons chunk (string-collector:chunks sc)))
		  (set-string-collector:chunk sc #f))))
	  (else
	   (let ((new-chunk (make-string 128 c)))
	     (set-string-collector:chunk-left sc 127)
	     (set-string-collector:chunk sc new-chunk)))))

  ;; We don't actually do anything with this, but we keep it updated anyway.
  (set-string-collector:len sc (+ (string-collector:len sc) 1))
  sc)


;;; Convert the data in the string-collector SC to a single contiguous
;;; string and return it.

(define (string-collector->string sc)
  (let ((chunk  (string-collector:chunk sc))
	(chunks (string-collector:chunks sc)))
    (apply string-append
	   (reverse (if chunk
			(cons (substring chunk 0
					 (- 128
					    (string-collector:chunk-left sc)))
			      chunks)
			chunks)))))

;;; It's too bad we can't side-effect the string-collector's chunk list
;;; to be a single chunk after this coalescing operation, but we don't
;;; want to share the string we return -- the user might side-effect it.