Remove the old VMS linker option file creator for shlibs
Reviewed-by: Tim Hudson <tjh@openssl.org>
Richard Levitte
8 years ago
0 | $! MKSHARED.COM -- Create shareable images. | |
1 | $! | |
2 | $! P1: "64" for 64-bit pointers. | |
3 | $! | |
4 | $! P2: Zlib object library path (optional). | |
5 | $! | |
6 | $! Input: [.UTIL]LIBEAY.NUM,[.xxx.EXE.CRYPTO]SSL_LIBCRYPTO[32].OLB | |
7 | $! [.UTIL]SSLEAY.NUM,[.xxx.EXE.SSL]SSL_LIBSSL[32].OLB | |
8 | $! [.CRYPTO.xxx]OPENSSLCONF.H | |
9 | $! Output: [.xxx.EXE.CRYPTO]SSL_LIBCRYPTO_SHR[32].OPT,.MAP,.EXE | |
10 | $! [.xxx.EXE.SSL]SSL_LIBSSL_SRH[32].OPT,.MAP,.EXE | |
11 | $! | |
12 | $! So far, tests have only been made on VMS for Alpha. VAX will come in time. | |
13 | $! =========================================================================== | |
14 | $! | |
15 | $! Announce/identify. | |
16 | $! | |
17 | $ proc = f$environment( "procedure") | |
18 | $ write sys$output "@@@ "+ - | |
19 | f$parse( proc, , , "name")+ f$parse( proc, , , "type") | |
20 | $! | |
21 | $! Save the original default device:[directory]. | |
22 | $! | |
23 | $ def_orig = f$environment( "default") | |
24 | $ on error then goto tidy | |
25 | $ on control_c then goto tidy | |
26 | $! | |
27 | $! SET DEFAULT to the main kit directory. | |
28 | $! | |
29 | $ proc = f$environment("procedure") | |
30 | $ proc = f$parse( "A.;", proc)- "A.;" | |
31 | $ set default 'proc' | |
32 | $ set default [-] | |
33 | $! | |
34 | $! ----- Prepare info for processing: version number and file info | |
35 | $ gosub read_version_info | |
36 | $ if libver .eqs. "" | |
37 | $ then | |
38 | $ write sys$error "ERROR: Couldn't find any library version info..." | |
39 | $ go to tidy: | |
40 | $ endif | |
41 | $ | |
42 | $ if (f$getsyi("cpu") .lt. 128) | |
43 | $ then | |
44 | $ arch_vax = 1 | |
45 | $ arch = "VAX" | |
46 | $ else | |
47 | $ arch_vax = 0 | |
48 | $ arch = f$edit( f$getsyi( "ARCH_NAME"), "UPCASE") | |
49 | $ if (arch .eqs. "") then arch = "UNK" | |
50 | $ endif | |
51 | $! | |
52 | $ archd = arch | |
53 | $ lib32 = "32" | |
54 | $ shr = "SHR32" | |
55 | $! | |
56 | $ if (p1 .nes. "") | |
57 | $ then | |
58 | $ if (p1 .eqs. "64") | |
59 | $ then | |
60 | $ archd = arch+ "_64" | |
61 | $ lib32 = "" | |
62 | $ shr = "SHR" | |
63 | $ else | |
64 | $ if (p1 .nes. "32") | |
65 | $ then | |
66 | $ write sys$output "Second argument invalid." | |
67 | $ write sys$output "It should be "32", "64", or nothing." | |
68 | $ exit | |
69 | $ endif | |
70 | $ endif | |
71 | $ endif | |
72 | $! | |
73 | $! ----- Prepare info for processing: disabled algorithms info | |
74 | $ gosub read_disabled_algorithms_info | |
75 | $! | |
76 | $ ZLIB = p2 | |
77 | $ zlib_lib = "" | |
78 | $ if (ZLIB .nes. "") | |
79 | $ then | |
80 | $ file2 = f$parse( ZLIB, "libz.olb", , , "syntax_only") | |
81 | $ if (f$search( file2) .eqs. "") | |
82 | $ then | |
83 | $ write sys$output "" | |
84 | $ write sys$output "The Option ", ZLIB, " Is Invalid." | |
85 | $ write sys$output " Can't find library: ''file2'" | |
86 | $ write sys$output "" | |
87 | $ goto tidy | |
88 | $ endif | |
89 | $ zlib_lib = ", ''file2' /library" | |
90 | $ endif | |
91 | $! | |
92 | $ if (arch_vax) | |
93 | $ then | |
94 | $ libtit = "CRYPTO_TRANSFER_VECTOR" | |
95 | $ libid = "Crypto" | |
96 | $ libnum = "[.UTIL]LIBEAY.NUM" | |
97 | $ libdir = "[.''ARCHD'.EXE.CRYPTO]" | |
98 | $ libmar = "''libdir'SSL_LIBCRYPTO_''shr'.MAR" | |
99 | $ libolb = "''libdir'SSL_LIBCRYPTO''lib32'.OLB" | |
100 | $ libopt = "''libdir'SSL_LIBCRYPTO_''shr'.OPT" | |
101 | $ libobj = "''libdir'SSL_LIBCRYPTO_''shr'.OBJ" | |
102 | $ libmap = "''libdir'SSL_LIBCRYPTO_''shr'.MAP" | |
103 | $ libgoal= "''libdir'SSL_LIBCRYPTO_''shr'.EXE" | |
104 | $ libref = "" | |
105 | $ libvec = "LIBCRYPTO" | |
106 | $ if f$search( libolb) .nes. "" then gosub create_vax_shr | |
107 | $ libtit = "SSL_TRANSFER_VECTOR" | |
108 | $ libid = "SSL" | |
109 | $ libnum = "[.UTIL]SSLEAY.NUM" | |
110 | $ libdir = "[.''ARCHD'.EXE.SSL]" | |
111 | $ libmar = "''libdir'SSL_LIBSSL_''shr'.MAR" | |
112 | $ libolb = "''libdir'SSL_LIBSSL''lib32'.OLB" | |
113 | $ libopt = "''libdir'SSL_LIBSSL_''shr'.OPT" | |
114 | $ libobj = "''libdir'SSL_LIBSSL_''shr'.OBJ" | |
115 | $ libmap = "''libdir'SSL_LIBSSL_''shr'.MAP" | |
116 | $ libgoal= "''libdir'SSL_LIBSSL_''shr'.EXE" | |
117 | $ libref = "[.''ARCHD'.EXE.CRYPTO]SSL_LIBCRYPTO_''shr'.EXE" | |
118 | $ libvec = "LIBSSL" | |
119 | $ if f$search( libolb) .nes. "" then gosub create_vax_shr | |
120 | $ else | |
121 | $ libid = "Crypto" | |
122 | $ libnum = "[.UTIL]LIBEAY.NUM" | |
123 | $ libdir = "[.''ARCHD'.EXE.CRYPTO]" | |
124 | $ libolb = "''libdir'SSL_LIBCRYPTO''lib32'.OLB" | |
125 | $ libopt = "''libdir'SSL_LIBCRYPTO_''shr'.OPT" | |
126 | $ libmap = "''libdir'SSL_LIBCRYPTO_''shr'.MAP" | |
127 | $ libgoal= "''libdir'SSL_LIBCRYPTO_''shr'.EXE" | |
128 | $ libref = "" | |
129 | $ if f$search( libolb) .nes. "" then gosub create_nonvax_shr | |
130 | $ libid = "SSL" | |
131 | $ libnum = "[.UTIL]SSLEAY.NUM" | |
132 | $ libdir = "[.''ARCHD'.EXE.SSL]" | |
133 | $ libolb = "''libdir'SSL_LIBSSL''lib32'.OLB" | |
134 | $ libopt = "''libdir'SSL_LIBSSL_''shr'.OPT" | |
135 | $ libmap = "''libdir'SSL_LIBSSL_''shr'.MAP" | |
136 | $ libgoal= "''libdir'SSL_LIBSSL_''shr'.EXE" | |
137 | $ libref = "[.''ARCHD'.EXE.CRYPTO]SSL_LIBCRYPTO_''shr'.EXE" | |
138 | $ if f$search( libolb) .nes. "" then gosub create_nonvax_shr | |
139 | $ endif | |
140 | $! | |
141 | $ tidy: | |
142 | $! | |
143 | $! Close any open files. | |
144 | $! | |
145 | $ if (f$trnlnm( "libnum", "LNM$PROCESS", 0, "SUPERVISOR") .nes. "") then - | |
146 | close libnum | |
147 | $! | |
148 | $ if (f$trnlnm( "mar", "LNM$PROCESS", 0, "SUPERVISOR") .nes. "") then - | |
149 | close mar | |
150 | $! | |
151 | $ if (f$trnlnm( "opt", "LNM$PROCESS", 0, "SUPERVISOR") .nes. "") then - | |
152 | close opt | |
153 | $! | |
154 | $ if (f$trnlnm( "vf", "LNM$PROCESS", 0, "SUPERVISOR") .nes. "") then - | |
155 | close vf | |
156 | $! | |
157 | $! Restore the original default device:[directory]. | |
158 | $! | |
159 | $ set default 'def_orig' | |
160 | $ exit | |
161 | $ | |
162 | $! ----- Subroutines to build the shareable libraries | |
163 | $! For each supported architecture, there's a main shareable library | |
164 | $! creator, which is called from the main code above. | |
165 | $! The creator will define a number of variables to tell the next levels of | |
166 | $! subroutines what routines to use to write to the option files, call the | |
167 | $! main processor, read_func_num, and when that is done, it will write version | |
168 | $! data at the end of the .opt file, close it, and link the library. | |
169 | $! | |
170 | $! read_func_num reads through a .num file and calls the writer routine for | |
171 | $! each line. It's also responsible for checking that order is properly kept | |
172 | $! in the .num file, check that each line applies to VMS and the architecture, | |
173 | $! and to fill in "holes" with dummy entries. | |
174 | $! | |
175 | $! The creator routines depend on the following variables: | |
176 | $! libnum The name of the .num file to use as input | |
177 | $! libolb The name of the object library to build from | |
178 | $! libid The identification string of the shareable library | |
179 | $! libopt The name of the .opt file to write | |
180 | $! libtit The title of the assembler transfer vector file (VAX only) | |
181 | $! libmar The name of the assembler transfer vector file (VAX only) | |
182 | $! libmap The name of the map file to write | |
183 | $! libgoal The name of the shareable library to write | |
184 | $! libref The name of a shareable library to link in | |
185 | $! | |
186 | $! read_func_num depends on the following variables from the creator: | |
187 | $! libwriter The name of the writer routine to call for each .num file line | |
188 | $! ----- | |
189 | $ | |
190 | $! ----- Subroutines for non-VAX | |
191 | $! ----- | |
192 | $! The creator routine | |
193 | $ create_nonvax_shr: | |
194 | $ open /write opt 'libopt' | |
195 | $ write opt "identification=""",libid," ",libverstr,"""" | |
196 | $ write opt libolb, " /library" | |
197 | $ if libref .nes. "" then write opt libref,"/SHARE" | |
198 | $ write opt "SYMBOL_VECTOR=(-" | |
199 | $ libfirstentry := true | |
200 | $ libwrch := opt | |
201 | $ libwriter := write_nonvax_transfer_entry | |
202 | $ textcount = 0 | |
203 | $ gosub read_func_num | |
204 | $ write opt ")" | |
205 | $ write opt "GSMATCH=",libvmatch,",",libver | |
206 | $ close opt | |
207 | $ link /map = 'libmap' /full /share = 'libgoal' 'libopt' /options - | |
208 | 'zlib_lib' | |
209 | $ return | |
210 | $ | |
211 | $! The record writer routine | |
212 | $ write_nonvax_transfer_entry: | |
213 | $ if libentry .eqs. ".dummy" then return | |
214 | $ if info_kind .eqs. "VARIABLE" | |
215 | $ then | |
216 | $ pr:=DATA | |
217 | $ else | |
218 | $ pr:=PROCEDURE | |
219 | $ endif | |
220 | $ textcount_this = f$length(pr) + f$length(libentry) + 5 | |
221 | $ if textcount + textcount_this .gt. 1024 | |
222 | $ then | |
223 | $ write opt ")" | |
224 | $ write opt "SYMBOL_VECTOR=(-" | |
225 | $ textcount = 16 | |
226 | $ libfirstentry := true | |
227 | $ endif | |
228 | $ if libfirstentry | |
229 | $ then | |
230 | $ write 'libwrch' " ",libentry,"=",pr," -" | |
231 | $ else | |
232 | $ write 'libwrch' " ,",libentry,"=",pr," -" | |
233 | $ endif | |
234 | $ libfirstentry := false | |
235 | $ textcount = textcount + textcount_this | |
236 | $ return | |
237 | $ | |
238 | $! ----- Subroutines for VAX | |
239 | $! ----- | |
240 | $! The creator routine | |
241 | $ create_vax_shr: | |
242 | $ open /write mar 'libmar' | |
243 | $ type sys$input:/out=mar: | |
244 | ; | |
245 | ; Transfer vector for VAX shareable image | |
246 | ; | |
247 | $ write mar " .TITLE ",libtit | |
248 | $ write mar " .IDENT /",libid,"/" | |
249 | $ type sys$input:/out=mar: | |
250 | ; | |
251 | ; Define macro to assist in building transfer vector entries. Each entry | |
252 | ; should take no more than 8 bytes. | |
253 | ; | |
254 | .MACRO FTRANSFER_ENTRY routine | |
255 | .ALIGN QUAD | |
256 | .TRANSFER routine | |
257 | .MASK routine | |
258 | JMP routine+2 | |
259 | .ENDM FTRANSFER_ENTRY | |
260 | ; | |
261 | ; Place entries in own program section. | |
262 | ; | |
263 | $ write mar " .PSECT $$",libvec,",QUAD,PIC,USR,CON,REL,LCL,SHR,EXE,RD,NOWRT" | |
264 | $ write mar libvec,"_xfer:" | |
265 | $ libwrch := mar | |
266 | $ libwriter := write_vax_ftransfer_entry | |
267 | $ gosub read_func_num | |
268 | $ type sys$input:/out=mar: | |
269 | ; | |
270 | ; Allocate extra storage at end of vector to allow for expansion. | |
271 | ; | |
272 | $ write mar " .BLKB 32768-<.-",libvec,"_xfer> ; 64 pages total." | |
273 | $! libwriter := write_vax_vtransfer_entry | |
274 | $! gosub read_func_num | |
275 | $ write mar " .END" | |
276 | $ close mar | |
277 | $ open /write opt 'libopt' | |
278 | $ write opt "identification=""",libid," ",libverstr,"""" | |
279 | $ write opt libobj | |
280 | $ write opt libolb, " /library" | |
281 | $ if libref .nes. "" then write opt libref,"/SHARE" | |
282 | $ type sys$input:/out=opt: | |
283 | ! | |
284 | ! Ensure transfer vector is at beginning of image | |
285 | ! | |
286 | CLUSTER=FIRST | |
287 | $ write opt "COLLECT=FIRST,$$",libvec | |
288 | $ write opt "GSMATCH=",libvmatch,",",libver | |
289 | $ type sys$input:/out=opt: | |
290 | ! | |
291 | ! make psects nonshareable so image can be installed. | |
292 | ! | |
293 | PSECT_ATTR=$CHAR_STRING_CONSTANTS,NOWRT | |
294 | $ libwrch := opt | |
295 | $ libwriter := write_vax_psect_attr | |
296 | $ gosub read_func_num | |
297 | $ close opt | |
298 | $ macro/obj='libobj' 'libmar' | |
299 | $ link /map = 'libmap' /full /share = 'libgoal' 'libopt' /options - | |
300 | 'zlib_lib' | |
301 | $ return | |
302 | $ | |
303 | $! The record writer routine for VAX functions | |
304 | $ write_vax_ftransfer_entry: | |
305 | $ if info_kind .nes. "FUNCTION" then return | |
306 | $ if libentry .eqs ".dummy" | |
307 | $ then | |
308 | $ write 'libwrch' " .BLKB 8" ! Dummy is zeroes... | |
309 | $ else | |
310 | $ write 'libwrch' " FTRANSFER_ENTRY ",libentry | |
311 | $ endif | |
312 | $ return | |
313 | $! The record writer routine for VAX variables (should never happen!) | |
314 | $ write_vax_psect_attr: | |
315 | $ if info_kind .nes. "VARIABLE" then return | |
316 | $ if libentry .eqs ".dummy" then return | |
317 | $ write 'libwrch' "PSECT_ATTR=",libentry,",NOSHR" | |
318 | $ return | |
319 | $ | |
320 | $! ----- Common subroutines | |
321 | $! ----- | |
322 | $! The .num file reader. This one has great responsibility. | |
323 | $ read_func_num: | |
324 | $ open /read libnum 'libnum' | |
325 | $ goto read_nums | |
326 | $ | |
327 | $ read_nums: | |
328 | $ libentrynum=0 | |
329 | $ liblastentry:=false | |
330 | $ entrycount=0 | |
331 | $ loop: | |
332 | $ read /end=loop_end /err=loop_end libnum line | |
333 | $ lin = f$edit( line, "COMPRESS,TRIM") | |
334 | $! Skip a "#" comment line. | |
335 | $ if (f$extract( 0, 1, lin) .eqs. "#") then goto loop | |
336 | $ entrynum = f$int(f$element( 1, " ", lin)) | |
337 | $ entryinfo = f$element( 2, " ", lin) | |
338 | $ curentry = f$element( 0, " ", lin) | |
339 | $ info_exist = f$element( 0, ":", entryinfo) | |
340 | $ info_platforms = ","+ f$element(1, ":", entryinfo)+ "," | |
341 | $ info_kind = f$element( 2, ":", entryinfo) | |
342 | $ info_algorithms = ","+ f$element( 3, ":", entryinfo)+ "," | |
343 | $ if info_exist .eqs. "NOEXIST" then goto loop | |
344 | $ truesum = 0 | |
345 | $ falsesum = 0 | |
346 | $ negatives = 1 | |
347 | $ plat_i = 0 | |
348 | $ loop1: | |
349 | $ plat_entry = f$element( plat_i, ",", info_platforms) | |
350 | $ plat_i = plat_i + 1 | |
351 | $ if plat_entry .eqs. "" then goto loop1 | |
352 | $ if plat_entry .nes. "," | |
353 | $ then | |
354 | $ if f$extract(0,1,plat_entry) .nes. "!" then negatives = 0 | |
355 | $ if (arch_vax) | |
356 | $ then | |
357 | $ if plat_entry .eqs. "EXPORT_VAR_AS_FUNCTION" then - | |
358 | $ truesum = truesum + 1 | |
359 | $ if plat_entry .eqs. "!EXPORT_VAR_AS_FUNCTION" then - | |
360 | $ falsesum = falsesum + 1 | |
361 | $ endif | |
362 | $! | |
363 | $ if ((plat_entry .eqs. "VMS") .or. - | |
364 | ((plat_entry .eqs. "ZLIB") .and. (ZLIB .nes. "")) .or. - | |
365 | (arch_vax .and. (plat_entry .eqs. "VMSVAX"))) then - | |
366 | truesum = truesum + 1 | |
367 | $! | |
368 | $ if ((plat_entry .eqs. "!VMS") .or. - | |
369 | (arch_vax .and. (plat_entry .eqs. "!VMSVAX"))) then - | |
370 | falsesum = falsesum + 1 | |
371 | $! | |
372 | $ goto loop1 | |
373 | $ endif | |
374 | $ endloop1: | |
375 | $!DEBUG!$ if info_platforms - "EXPORT_VAR_AS_FUNCTION" .nes. info_platforms | |
376 | $!DEBUG!$ then | |
377 | $!DEBUG!$ write sys$output line | |
378 | $!DEBUG!$ write sys$output " truesum = ",truesum,- | |
379 | $!DEBUG! ", negatives = ",negatives,", falsesum = ",falsesum | |
380 | $!DEBUG!$ endif | |
381 | $ if falsesum .ne. 0 then goto loop | |
382 | $ if truesum+negatives .eq. 0 then goto loop | |
383 | $ alg_i = 0 | |
384 | $ loop2: | |
385 | $ alg_entry = f$element(alg_i,",",info_algorithms) | |
386 | $ alg_i = alg_i + 1 | |
387 | $ if alg_entry .eqs. "" then goto loop2 | |
388 | $ if alg_entry .nes. "," | |
389 | $ then | |
390 | $ if disabled_algorithms - ("," + alg_entry + ",") .nes disabled_algorithms then goto loop | |
391 | $ if f$trnlnm("OPENSSL_NO_"+alg_entry) .nes. "" then goto loop | |
392 | $ goto loop2 | |
393 | $ endif | |
394 | $ endloop2: | |
395 | $ if info_platforms - "EXPORT_VAR_AS_FUNCTION" .nes. info_platforms | |
396 | $ then | |
397 | $!DEBUG!$ write sys$output curentry," ; ",entrynum," ; ",entryinfo | |
398 | $ endif | |
399 | $ redo: | |
400 | $ next:=loop | |
401 | $ tolibentry=curentry | |
402 | $ if libentrynum .ne. entrynum | |
403 | $ then | |
404 | $ entrycount=entrycount+1 | |
405 | $ if entrycount .lt. entrynum | |
406 | $ then | |
407 | $!DEBUG!$ write sys$output "Info: entrycount: ''entrycount', entrynum: ''entrynum' => 0" | |
408 | $ tolibentry=".dummy" | |
409 | $ next:=redo | |
410 | $ endif | |
411 | $ if entrycount .gt. entrynum | |
412 | $ then | |
413 | $ write sys$error "Decreasing library entry numbers! Can't continue" | |
414 | $ write sys$error """",line,"""" | |
415 | $ close libnum | |
416 | $ return | |
417 | $ endif | |
418 | $ libentry=tolibentry | |
419 | $!DEBUG!$ write sys$output entrycount," ",libentry," ",entryinfo | |
420 | $ if libentry .nes. "" .and. libwriter .nes. "" then gosub 'libwriter' | |
421 | $ else | |
422 | $ write sys$error "Info: ""''curentry'"" is an alias for ""''libentry'"". Overriding..." | |
423 | $ endif | |
424 | $ libentrynum=entrycount | |
425 | $ goto 'next' | |
426 | $ loop_end: | |
427 | $ close libnum | |
428 | $ return | |
429 | $ | |
430 | $! The version number reader | |
431 | $ read_version_info: | |
432 | $ libver = "" | |
433 | $ open /read vf [.CRYPTO]OPENSSLV.H | |
434 | $ loop_rvi: | |
435 | $ read/err=endloop_rvi/end=endloop_rvi vf rvi_line | |
436 | $ if rvi_line - "SHLIB_VERSION_NUMBER """ .eqs. rvi_line then - | |
437 | goto loop_rvi | |
438 | $ libverstr = f$element(1,"""",rvi_line) | |
439 | $ libvmajor = f$element(0,".",libverstr) | |
440 | $ libvminor = f$element(1,".",libverstr) | |
441 | $ libvedit = f$element(2,".",libverstr) | |
442 | $ libvpatch = f$cvui(0,8,f$extract(1,1,libvedit)+"@")-f$cvui(0,8,"@") | |
443 | $ libvedit = f$extract(0,1,libvedit) | |
444 | $ libver = f$string(f$int(libvmajor)*100)+","+- | |
445 | f$string(f$int(libvminor)*100+f$int(libvedit)*10+f$int(libvpatch)) | |
446 | $ if libvmajor .eqs. "0" | |
447 | $ then | |
448 | $ libvmatch = "EQUAL" | |
449 | $ else | |
450 | $ ! Starting with the 1.0 release, backward compatibility should be | |
451 | $ ! kept, so switch over to the following | |
452 | $ libvmatch = "LEQUAL" | |
453 | $ endif | |
454 | $ endloop_rvi: | |
455 | $ close vf | |
456 | $ return | |
457 | $ | |
458 | $! The disabled algorithms reader | |
459 | $ read_disabled_algorithms_info: | |
460 | $ disabled_algorithms = "," | |
461 | $ open /read cf [.CRYPTO.'ARCH']OPENSSLCONF.H | |
462 | $ loop_rci: | |
463 | $ read/err=endloop_rci/end=endloop_rci cf rci_line | |
464 | $ rci_line = f$edit(rci_line,"TRIM,COMPRESS") | |
465 | $ rci_ei = 0 | |
466 | $ if f$extract(0,9,rci_line) .eqs. "# define " then rci_ei = 2 | |
467 | $ if f$extract(0,8,rci_line) .eqs. "#define " then rci_ei = 1 | |
468 | $ if rci_ei .eq. 0 then goto loop_rci | |
469 | $ rci_e = f$element(rci_ei," ",rci_line) | |
470 | $ if f$extract(0,11,rci_e) .nes. "OPENSSL_NO_" then goto loop_rci | |
471 | $ disabled_algorithms = disabled_algorithms + f$extract(11,999,rci_e) + "," | |
472 | $ goto loop_rci | |
473 | $ endloop_rci: | |
474 | $ close cf | |
475 | $ return |