Mercurial > emacs
annotate src/ecrt0.c @ 88123:375f2633d815
New directory
author | Kenichi Handa <handa@m17n.org> |
---|---|
date | Mon, 08 Sep 2003 11:56:09 +0000 |
parents | 695cf19ef79e |
children | 68c22ea6027c |
rev | line source |
---|---|
25844 | 1 /* C code startup routine. |
2 Copyright (C) 1985, 1986, 1992 Free Software Foundation, Inc. | |
3 | |
4 This file is part of GNU Emacs. | |
5 | |
6 GNU Emacs is free software; you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation; either version 2, or (at your option) | |
9 any later version. | |
10 | |
11 GNU Emacs is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with GNU Emacs; see the file COPYING. If not, write to | |
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 Boston, MA 02111-1307, USA. */ | |
20 | |
21 | |
22 /* The standard Vax 4.2 Unix crt0.c cannot be used for Emacs | |
23 because it makes `environ' an initialized variable. | |
24 It is easiest to have a special crt0.c on all machines | |
25 though I don't know whether other machines actually need it. */ | |
26 | |
27 /* On the vax and 68000, in BSD4.2 and USG5.2, | |
28 this is the data format on startup: | |
29 (vax) ap and fp are unpredictable as far as I know; don't use them. | |
30 sp -> word containing argc | |
31 word pointing to first arg string | |
32 [word pointing to next arg string]... 0 or more times | |
33 0 | |
34 Optionally: | |
35 [word pointing to environment variable]... 1 or more times | |
36 ... | |
37 0 | |
38 And always: | |
39 first arg string | |
40 [next arg string]... 0 or more times | |
41 */ | |
42 | |
43 /* On the 16000, at least in the one 4.2 system I know about, | |
44 the initial data format is | |
45 sp -> word containing argc | |
46 word containing argp | |
47 word pointing to first arg string, and so on as above | |
48 */ | |
49 | |
50 #ifdef emacs | |
51 #include <config.h> | |
52 #endif | |
53 | |
54 /* ******** WARNING ******** | |
55 Do not insert any data definitions before data_start! | |
56 Since this is the first file linked, the address of the following | |
57 variable should correspond to the start of initialized data space. | |
58 On some systems this is a constant that is independent of the text | |
59 size for shared executables. On others, it is a function of the | |
60 text size. In short, this seems to be the most portable way to | |
61 discover the start of initialized data space dynamically at runtime, | |
62 for either shared or unshared executables, on either swapping or | |
63 virtual systems. It only requires that the linker allocate objects | |
64 in the order encountered, a reasonable model for most Unix systems. | |
65 Similarly, note that the address of _start() should be the start | |
66 of text space. Fred Fish, UniSoft Systems Inc. */ | |
67 | |
68 int data_start = 0; | |
69 | |
70 #ifdef NEED_ERRNO | |
71 int errno; | |
72 #endif | |
73 | |
74 #ifndef DONT_NEED_ENVIRON | |
75 char **environ; | |
76 #endif | |
77 | |
78 #ifndef static | |
79 /* On systems where the static storage class is usable, this function | |
80 should be declared as static. Otherwise, the static keyword has | |
81 been defined to be something else, and code for those systems must | |
82 take care of this declaration appropriately. */ | |
83 static start1 (); | |
84 #endif | |
85 | |
86 #ifdef APOLLO | |
87 extern char *malloc(), *realloc(), *(*_libc_malloc) (), *(*_libc_realloc)(); | |
88 extern void free(), (*_libc_free) (); extern int main(); | |
89 std_$call void unix_$main(); | |
90 | |
91 _start() | |
92 { | |
93 _libc_malloc = malloc; | |
94 _libc_realloc = realloc; | |
95 _libc_free = free; | |
96 unix_$main(main); /* no return */ | |
97 } | |
98 #endif /* APOLLO */ | |
99 | |
100 #if defined(orion) || defined(pyramid) || defined(celerity) || defined(ALLIANT) || defined(clipper) || defined(sps7) | |
101 | |
102 #if defined(sps7) && defined(V3x) | |
103 asm(" section 10"); | |
104 asm(" ds.b 0xb0"); | |
105 #endif | |
106 | |
107 #ifdef ALLIANT | |
108 /* _start must initialize _curbrk and _minbrk on the first startup; | |
109 when starting up after dumping, it must initialize them to what they were | |
110 before the dumping, since they are in the shared library and | |
111 are not dumped. See ADJUST_EXEC_HEADER in m-alliant.h. */ | |
112 extern unsigned char *_curbrk, *_minbrk; | |
113 extern unsigned char end; | |
114 unsigned char *_setbrk = &end; | |
115 #ifdef ALLIANT_2800 | |
116 unsigned char *_end = &end; | |
117 #endif | |
118 #endif | |
119 | |
120 #ifndef DUMMIES | |
121 #define DUMMIES | |
122 #endif | |
123 | |
124 _start (DUMMIES argc, argv, envp) | |
125 int argc; | |
126 char **argv, **envp; | |
127 { | |
128 #ifdef ALLIANT | |
129 #ifdef ALLIANT_2800 | |
130 _curbrk = _end; | |
131 _minbrk = _end; | |
132 #else | |
133 _curbrk = _setbrk; | |
134 _minbrk = _setbrk; | |
135 #endif | |
136 #endif | |
137 | |
138 environ = envp; | |
139 | |
140 exit (main (argc, argv, envp)); | |
141 } | |
142 | |
143 #endif /* orion or pyramid or celerity or alliant or clipper */ | |
144 | |
145 #if defined (ns16000) && !defined (sequent) && !defined (UMAX) && !defined (CRT0_DUMMIES) | |
146 | |
147 _start () | |
148 { | |
149 /* On 16000, _start pushes fp onto stack */ | |
150 start1 (); | |
151 } | |
152 | |
153 /* ignore takes care of skipping the fp value pushed in start. */ | |
154 static | |
155 start1 (ignore, argc, argv) | |
156 int ignore; | |
157 int argc; | |
158 register char **argv; | |
159 { | |
160 environ = argv + argc + 1; | |
161 | |
162 if (environ == *argv) | |
163 environ--; | |
164 exit (main (argc, argv, environ)); | |
165 } | |
166 #endif /* ns16000, not sequent and not UMAX, and not the CRT0_DUMMIES method */ | |
167 | |
168 #ifdef UMAX | |
169 _start() | |
170 { | |
171 asm(" exit [] # undo enter"); | |
172 asm(" .set exitsc,1"); | |
173 asm(" .set sigcatchall,0x400"); | |
174 | |
175 asm(" .globl _exit"); | |
176 asm(" .globl start"); | |
177 asm(" .globl __start"); | |
178 asm(" .globl _main"); | |
179 asm(" .globl _environ"); | |
180 asm(" .globl _sigvec"); | |
181 asm(" .globl sigentry"); | |
182 | |
183 asm("start:"); | |
184 asm(" br .xstart"); | |
185 asm(" .org 0x20"); | |
186 asm(" .double p_glbl,0,0xf00000,0"); | |
187 asm(" .org 0x30"); | |
188 asm(".xstart:"); | |
189 asm(" adjspb $8"); | |
190 asm(" movd 8(sp),0(sp) # argc"); | |
191 asm(" addr 12(sp),r0"); | |
192 asm(" movd r0,4(sp) # argv"); | |
193 asm("L1:"); | |
194 asm(" movd r0,r1"); | |
195 asm(" addqd $4,r0"); | |
196 asm(" cmpqd $0,0(r1) # null args term ?"); | |
197 asm(" bne L1"); | |
198 asm(" cmpd r0,0(4(sp)) # end of 'env' or 'argv' ?"); | |
199 asm(" blt L2"); | |
200 asm(" addqd $-4,r0 # envp's are in list"); | |
201 asm("L2:"); | |
202 asm(" movd r0,8(sp) # env"); | |
203 asm(" movd r0,@_environ # indir is 0 if no env ; not 0 if env"); | |
204 asm(" movqd $0,tos # setup intermediate signal handler"); | |
205 asm(" addr @sv,tos"); | |
206 asm(" movzwd $sigcatchall,tos"); | |
207 asm(" jsr @_sigvec"); | |
208 asm(" adjspb $-12"); | |
209 asm(" jsr @_main"); | |
210 asm(" adjspb $-12"); | |
211 asm(" movd r0,tos"); | |
212 asm(" jsr @_exit"); | |
213 asm(" adjspb $-4"); | |
214 asm(" addr @exitsc,r0"); | |
215 asm(" svc"); | |
216 asm(" .align 4 # sigvec arg"); | |
217 asm("sv:"); | |
218 asm(" .double sigentry"); | |
219 asm(" .double 0"); | |
220 asm(" .double 0"); | |
221 | |
222 asm(" .comm p_glbl,1"); | |
223 } | |
224 #endif /* UMAX */ | |
225 | |
226 #ifdef CRT0_DUMMIES | |
227 | |
228 /* Define symbol "start": here; some systems want that symbol. */ | |
229 #ifdef DOT_GLOBAL_START | |
230 asm(" .text "); | |
231 asm(" .globl start "); | |
232 asm(" start: "); | |
233 #endif /* DOT_GLOBAL_START */ | |
234 | |
235 #ifdef NODOT_GLOBAL_START | |
236 asm(" text "); | |
237 asm(" global start "); | |
238 asm(" start: "); | |
239 #endif /* NODOT_GLOBAL_START */ | |
240 | |
241 #ifdef m68000 | |
242 | |
243 /* GCC 2.1, when optimization is turned off, seems to want to push a | |
244 word of garbage on the stack, which screws up the CRT0_DUMMIES | |
245 hack. So we hand-code _start in assembly language. */ | |
246 asm(".text "); | |
247 asm(" .even "); | |
248 asm(".globl __start "); | |
249 asm("__start: "); | |
250 asm(" link a6,#0 "); | |
251 asm(" jbsr _start1 "); | |
252 asm(" unlk a6 "); | |
253 asm(" rts "); | |
254 | |
255 #else /* not m68000 */ | |
256 | |
257 _start () | |
258 { | |
259 /* On vax, nothing is pushed here */ | |
260 /* On sequent, bogus fp is pushed here */ | |
261 start1 (); | |
262 } | |
263 | |
264 #endif /* possibly m68000 */ | |
265 | |
266 static | |
267 start1 (CRT0_DUMMIES argc, xargv) | |
268 int argc; | |
269 char *xargv; | |
270 { | |
271 register char **argv = &xargv; | |
272 environ = argv + argc + 1; | |
273 | |
274 if ((char *)environ == xargv) | |
275 environ--; | |
276 exit (main (argc, argv, environ)); | |
277 | |
278 /* Refer to `start1' so GCC will not think it is never called | |
279 and optimize it out. */ | |
280 (void) &start1; | |
281 } | |
282 #else /* not CRT0_DUMMIES */ | |
283 | |
284 /* "m68k" and "m68000" both stand for m68000 processors, | |
285 but with different program-entry conventions. | |
286 This is a kludge. Now that the CRT0_DUMMIES mechanism above exists, | |
287 most of these machines could use the vax code above | |
288 with some suitable definition of CRT0_DUMMIES. | |
289 Then the symbol m68k could be flushed. | |
290 But I don't want to risk breaking these machines | |
291 in a version 17 patch release, so that change is being put off. */ | |
292 | |
293 #ifdef m68k /* Can't do it all from C */ | |
294 asm (" global _start"); | |
295 asm (" text"); | |
296 asm ("_start:"); | |
297 #ifndef NU | |
298 #ifdef STRIDE | |
299 asm (" comm havefpu%,2"); | |
300 #else /* m68k, not STRIDE */ | |
301 asm (" comm splimit%,4"); | |
302 #endif /* STRIDE */ | |
303 asm (" global exit"); | |
304 asm (" text"); | |
305 #ifdef STRIDE | |
306 asm (" trap &3"); | |
307 asm (" mov.w %d0,havefpu%"); | |
308 #else /* m68k, not STRIDE */ | |
309 asm (" mov.l %d0,splimit%"); | |
310 #endif /* STRIDE */ | |
311 #endif /* not NU */ | |
312 asm (" jsr start1"); | |
313 asm (" mov.l %d0,(%sp)"); | |
314 asm (" jsr exit"); | |
315 asm (" mov.l &1,%d0"); /* d0 = 1 => exit */ | |
316 asm (" trap &0"); | |
317 #else /* m68000, not m68k */ | |
318 | |
319 #ifdef m68000 | |
320 | |
321 #ifdef ISI68K | |
322 /* Added by ESM Sun May 24 12:44:02 1987 to get new ISI library to work */ | |
323 /* Edited by Ray Mon May 15 15:59:56 EST 1989 so we can compile with gcc */ | |
324 #if defined(BSD4_3) && !defined(__GNUC__) | |
325 static foo () { | |
326 #endif | |
327 asm (" .globl is68020"); | |
328 asm ("is68020:"); | |
329 #ifndef BSD4_3 | |
330 asm (" .long 0x00000000"); | |
331 asm (" .long 0xffffffff"); | |
332 /* End of stuff added by ESM */ | |
333 #endif | |
334 asm (" .text"); | |
335 asm (" .globl __start"); | |
336 asm ("__start:"); | |
337 asm (" .word 0"); | |
338 asm (" link a6,#0"); | |
339 asm (" jbsr _start1"); | |
340 asm (" unlk a6"); | |
341 asm (" rts"); | |
342 #if defined(BSD4_3) && !defined(__GNUC__) | |
343 } | |
344 #endif | |
345 #else /* not ISI68K */ | |
346 | |
347 _start () | |
348 { | |
349 #ifdef sun | |
350 finitfp_(); | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
27727
diff
changeset
|
351 #endif |
25844 | 352 /* On 68000, _start pushes a6 onto stack */ |
353 start1 (); | |
354 } | |
355 #endif /* not ISI68k */ | |
356 #endif /* m68000 */ | |
357 #endif /* m68k */ | |
358 | |
359 #if defined(m68k) || defined(m68000) | |
360 /* ignore takes care of skipping the a6 value pushed in start. */ | |
361 static | |
362 #if defined(m68k) | |
363 start1 (argc, xargv) | |
364 #else | |
365 start1 (ignore, argc, xargv) | |
366 #endif | |
367 int argc; | |
368 char *xargv; | |
369 { | |
370 register char **argv = &xargv; | |
371 environ = argv + argc + 1; | |
372 | |
373 if ((char *)environ == xargv) | |
374 environ--; | |
375 #ifdef sun_68881 | |
376 asm(" jsr f68881_used"); | |
377 #endif | |
378 #ifdef sun_fpa | |
379 asm(" jsr ffpa_used"); | |
380 #endif | |
381 #ifdef sun_soft | |
382 asm(" jsr start_float"); | |
383 #endif | |
384 exit (main (argc, argv, environ)); | |
385 } | |
386 | |
387 #endif /* m68k or m68000 */ | |
388 | |
389 #endif /* not CRT0_DUMMIES */ | |
390 | |
391 #ifdef hp9000s300 | |
392 int argc_value; | |
393 char **argv_value; | |
394 #ifdef OLD_HP_ASSEMBLER | |
395 asm(" text"); | |
396 asm(" globl __start"); | |
397 asm(" globl _exit"); | |
398 asm(" globl _main"); | |
399 asm("__start"); | |
400 asm(" dc.l 0"); | |
401 asm(" subq.w #0x1,d0"); | |
402 asm(" move.w d0,float_soft"); | |
403 asm(" move.l 0x4(a7),d0"); | |
404 asm(" beq.s skip_1"); | |
405 asm(" move.l d0,a0"); | |
406 asm(" clr.l -0x4(a0)"); | |
407 asm("skip_1"); | |
408 asm(" move.l a7,a0"); | |
409 asm(" subq.l #0x8,a7"); | |
410 asm(" move.l (a0),(a7)"); | |
411 asm(" move.l (a0),_argc_value"); | |
412 asm(" addq.l #0x4,a0"); | |
413 asm(" move.l a0,0x4(a7)"); | |
414 asm(" move.l a0,_argv_value"); | |
415 asm("incr_loop"); | |
416 asm(" tst.l (a0)+"); | |
417 asm(" bne.s incr_loop"); | |
418 asm(" move.l 0x4(a7),a1"); | |
419 asm(" cmp.l (a1),a0"); | |
420 asm(" blt.s skip_2"); | |
421 asm(" subq.l #0x4,a0"); | |
422 asm("skip_2"); | |
423 asm(" move.l a0,0x8(a7)"); | |
424 asm(" move.l a0,_environ"); | |
425 asm(" jsr _main"); | |
426 asm(" addq.l #0x8,a7"); | |
427 asm(" move.l d0,-(a7)"); | |
428 asm(" jsr _exit"); | |
429 asm(" move.w #0x1,d0"); | |
430 asm(" trap #0x0"); | |
431 asm(" comm float_soft,4"); | |
432 /* float_soft is allocated in this way because C would | |
433 put an underscore character in its name otherwise. */ | |
434 | |
435 #else /* new hp assembler */ | |
436 | |
437 asm(" text"); | |
438 asm(" global float_loc"); | |
439 asm(" set float_loc,0xFFFFB000"); | |
440 asm(" global fpa_loc"); | |
441 asm(" set fpa_loc,0xfff08000"); | |
442 asm(" global __start"); | |
443 asm(" global _exit"); | |
444 asm(" global _main"); | |
445 asm("__start:"); | |
446 asm(" byte 0,0,0,0"); | |
447 asm(" subq.w &1,%d0"); | |
448 asm(" mov.w %d0,float_soft"); | |
449 asm(" mov.w %d1,flag_68881"); | |
450 #ifndef HPUX_68010 | |
451 asm(" beq.b skip_float"); | |
452 asm(" fmov.l &0x7400,%fpcr"); | |
453 /* asm(" fmov.l &0x7480,%fpcr"); */ | |
454 #endif /* HPUX_68010 */ | |
455 asm("skip_float:"); | |
456 asm(" mov.l %a0,%d0"); | |
457 asm(" add.l %d0,%d0"); | |
458 asm(" subx.w %d1,%d1"); | |
459 asm(" mov.w %d1,flag_68010"); | |
460 asm(" add.l %d0,%d0"); | |
461 asm(" subx.w %d1,%d1"); | |
462 asm(" mov.w %d1,flag_fpa"); | |
463 asm(" tst.l %d2"); | |
464 asm(" ble.b skip_3"); | |
465 asm(" lsl flag_68881"); | |
466 asm(" lsl flag_fpa"); | |
467 asm("skip_3:"); | |
468 asm(" mov.l 4(%a7),%d0"); | |
469 asm(" beq.b skip_1"); | |
470 asm(" mov.l %d0,%a0"); | |
471 asm(" clr.l -4(%a0)"); | |
472 asm("skip_1:"); | |
473 asm(" mov.l %a7,%a0"); | |
474 asm(" subq.l &8,%a7"); | |
475 asm(" mov.l (%a0),(%a7)"); | |
476 asm(" mov.l (%a0),_argc_value"); | |
477 asm(" addq.l &4,%a0"); | |
478 asm(" mov.l %a0,4(%a7)"); | |
479 asm(" mov.l %a0,_argv_value"); | |
480 asm("incr_loop:"); | |
481 asm(" tst.l (%a0)+"); | |
482 asm(" bne.b incr_loop"); | |
483 asm(" mov.l 4(%a7),%a1"); | |
484 asm(" cmp.l %a0,(%a1)"); | |
485 asm(" blt.b skip_2"); | |
486 asm(" subq.l &4,%a0"); | |
487 asm("skip_2:"); | |
488 asm(" mov.l %a0,8(%a7)"); | |
489 asm(" mov.l %a0,_environ"); | |
490 asm(" jsr _main"); | |
491 asm(" addq.l &8,%a7"); | |
492 asm(" mov.l %d0,-(%a7)"); | |
493 asm(" jsr _exit"); | |
494 asm(" mov.w &1,%d0"); | |
495 asm(" trap &0"); | |
496 asm(" comm float_soft, 4"); | |
497 asm(" comm flag_68881, 4"); | |
498 asm(" comm flag_68010, 4"); | |
499 asm(" comm flag_68040, 4"); | |
500 asm(" comm flag_fpa, 4"); | |
501 | |
502 #endif /* new hp assembler */ | |
503 #endif /* hp9000s300 */ | |
504 | |
505 #ifdef GOULD | |
506 | |
507 /* startup code has to be in near text rather | |
508 than fartext as allocated by the C compiler. */ | |
509 asm(" .text"); | |
510 asm(" .align 2"); | |
511 asm(" .globl __start"); | |
512 asm(" .text"); | |
513 asm("__start:"); | |
514 /* setup base register b1 (function base). */ | |
515 asm(" .using b1,."); | |
516 asm(" tpcbr b1"); | |
517 /* setup base registers b3 through b7 (data references). */ | |
518 asm(" file basevals,b3"); | |
519 /* setup base register b2 (stack pointer); it should be | |
520 aligned on a 8-word boundary; but because it is pointing | |
521 to argc, its value should be remembered (in r5). */ | |
522 asm(" movw b2,r4"); | |
523 asm(" movw b2,r5"); | |
524 asm(" andw #~0x1f,r4"); | |
525 asm(" movw r4,b2"); | |
526 /* allocate stack frame to do some work. */ | |
527 asm(" subea 16w,b2"); | |
528 /* initialize signal catching for UTX/32 1.2; this is | |
529 necessary to make restart from saved image work. */ | |
530 asm(" movea sigcatch,r1"); | |
531 asm(" movw r1,8w[b2]"); | |
532 asm(" svc #1,#150"); | |
533 /* setup address of argc for start1. */ | |
534 asm(" movw r5,8w[b2]"); | |
535 asm(" func #1,_start1"); | |
536 asm(" halt"); | |
537 /* space for ld to store base register initial values. */ | |
538 asm(" .align 5"); | |
539 asm("basevals:"); | |
540 asm(" .word __base3,__base4,__base5,__base6,__base7"); | |
541 | |
542 static | |
543 start1 (xargc) | |
544 int *xargc; | |
545 { | |
546 register int argc; | |
547 register char **argv; | |
548 | |
549 argc = *xargc; | |
550 argv = (char **)(xargc) + 1; | |
551 environ = argv + argc + 1; | |
552 | |
553 if (environ == argv) | |
554 environ--; | |
555 exit (main (argc, argv, environ)); | |
556 | |
557 } | |
558 | |
559 #endif /* GOULD */ | |
560 | |
561 #ifdef elxsi | |
562 #include <elxsi/argvcache.h> | |
563 | |
564 extern char **environ; | |
565 extern int errno; | |
566 extern void _init_doscan(), _init_iob(); | |
567 extern char end[]; | |
568 char *_init_brk = end; | |
569 | |
570 _start() | |
571 { | |
572 environ = exec_cache.ac_envp; | |
573 brk (_init_brk); | |
574 errno = 0; | |
575 _init_doscan (); | |
576 _init_iob (); | |
577 _exit (exit (main (exec_cache.ac_argc, | |
578 exec_cache.ac_argv, | |
579 exec_cache.ac_envp))); | |
580 } | |
581 #endif /* elxsi */ | |
582 | |
583 | |
584 #ifdef sparc | |
585 asm (".global __start"); | |
586 asm (".text"); | |
587 asm ("__start:"); | |
588 asm (" mov 0, %fp"); | |
589 asm (" ld [%sp + 64], %o0"); | |
590 asm (" add %sp, 68, %o1"); | |
591 asm (" sll %o0, 2, %o2"); | |
592 asm (" add %o2, 4, %o2"); | |
593 asm (" add %o1, %o2, %o2"); | |
594 asm (" sethi %hi(_environ), %o3"); | |
595 asm (" st %o2, [%o3+%lo(_environ)]"); | |
596 asm (" andn %sp, 7, %sp"); | |
597 asm (" call _main"); | |
598 asm (" sub %sp, 24, %sp"); | |
599 asm (" call __exit"); | |
600 asm (" nop"); | |
601 | |
602 #endif /* sparc */ | |
603 | |
604 #if __FreeBSD__ == 2 | |
605 char *__progname; | |
606 #endif | |
607 #ifdef __bsdi__ | |
608 #include <sys/param.h> /* for version number */ | |
609 #if defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199501) | |
610 char *__progname; | |
611 #endif | |
612 #endif /* __bsdi__ */ |