1 /* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
2 Contributed by Andy Vaught
4 This file is part of the GNU Fortran 95 runtime library (libgfortran).
6 Libgfortran 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)
11 Libgfortran 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.
16 You should have received a copy of the GNU General Public License
17 along with Libgfortran; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
24 #include "libgfortran.h"
28 /* Subroutines related to units */
32 static gfc_unit internal_unit
, *unit_cache
[CACHE_SIZE
];
35 /* This implementation is based on Stefan Nilsson's article in the
36 * July 1997 Doctor Dobb's Journal, "Treaps in Java". */
38 /* pseudo_random()-- Simple linear congruential pseudorandom number
39 * generator. The period of this generator is 44071, which is plenty
40 * for our purposes. */
47 x0
= (22611 * x0
+ 10) % 44071;
52 /* rotate_left()-- Rotate the treap left */
55 rotate_left (gfc_unit
* t
)
60 t
->right
= t
->right
->left
;
67 /* rotate_right()-- Rotate the treap right */
70 rotate_right (gfc_unit
* t
)
75 t
->left
= t
->left
->right
;
84 compare (int a
, int b
)
95 /* insert()-- Recursive insertion function. Returns the updated treap. */
98 insert (gfc_unit
* new, gfc_unit
* t
)
105 c
= compare (new->unit_number
, t
->unit_number
);
109 t
->left
= insert (new, t
->left
);
110 if (t
->priority
< t
->left
->priority
)
111 t
= rotate_right (t
);
116 t
->right
= insert (new, t
->right
);
117 if (t
->priority
< t
->right
->priority
)
122 internal_error ("insert(): Duplicate key found!");
128 /* insert_unit()-- Given a new node, insert it into the treap. It is
129 * an error to insert a key that already exists. */
132 insert_unit (gfc_unit
* new)
134 new->priority
= pseudo_random ();
135 g
.unit_root
= insert (new, g
.unit_root
);
140 delete_root (gfc_unit
* t
)
146 if (t
->right
== NULL
)
149 if (t
->left
->priority
> t
->right
->priority
)
151 temp
= rotate_right (t
);
152 temp
->right
= delete_root (t
);
156 temp
= rotate_left (t
);
157 temp
->left
= delete_root (t
);
164 /* delete_treap()-- Delete an element from a tree. The 'old' value
165 * does not necessarily have to point to the element to be deleted, it
166 * must just point to a treap structure with the key to be deleted.
167 * Returns the new root node of the tree. */
170 delete_treap (gfc_unit
* old
, gfc_unit
* t
)
177 c
= compare (old
->unit_number
, t
->unit_number
);
180 t
->left
= delete_treap (old
, t
->left
);
182 t
->right
= delete_treap (old
, t
->right
);
190 /* delete_unit()-- Delete a unit from a tree */
193 delete_unit (gfc_unit
* old
)
195 g
.unit_root
= delete_treap (old
, g
.unit_root
);
199 /* find_unit()-- Given an integer, return a pointer to the unit
200 * structure. Returns NULL if the unit does not exist. */
208 for (c
= 0; c
< CACHE_SIZE
; c
++)
209 if (unit_cache
[c
] != NULL
&& unit_cache
[c
]->unit_number
== n
)
218 c
= compare (n
, p
->unit_number
);
229 for (c
= 0; c
< CACHE_SIZE
- 1; c
++)
230 unit_cache
[c
] = unit_cache
[c
+ 1];
232 unit_cache
[CACHE_SIZE
- 1] = p
;
238 /* get_unit()-- Returns the unit structure associated with the integer
239 * unit or the internal file. */
242 get_unit (int read_flag
)
244 if (ioparm
.internal_unit
!= NULL
)
247 open_internal (ioparm
.internal_unit
, ioparm
.internal_unit_len
);
249 /* Set flags for the internal unit */
251 internal_unit
.flags
.access
= ACCESS_SEQUENTIAL
;
252 internal_unit
.flags
.action
= ACTION_READWRITE
;
253 internal_unit
.flags
.form
= FORM_FORMATTED
;
254 internal_unit
.flags
.delim
= DELIM_NONE
;
256 return &internal_unit
;
259 /* Has to be an external unit */
261 return find_unit (ioparm
.unit
);
265 /* is_internal_unit()-- Determine if the current unit is internal or
271 return current_unit
== &internal_unit
;
276 /*************************/
277 /* Initialize everything */
286 if (options
.stdin_unit
>= 0)
288 u
= get_mem (sizeof (gfc_unit
));
290 u
->unit_number
= options
.stdin_unit
;
291 u
->s
= input_stream ();
293 u
->flags
.action
= ACTION_READ
;
295 u
->flags
.access
= ACCESS_SEQUENTIAL
;
296 u
->flags
.form
= FORM_FORMATTED
;
297 u
->flags
.status
= STATUS_OLD
;
298 u
->flags
.blank
= BLANK_ZERO
;
299 u
->flags
.position
= POSITION_ASIS
;
301 u
->recl
= options
.default_recl
;
302 u
->endfile
= NO_ENDFILE
;
307 if (options
.stdout_unit
>= 0)
309 u
= get_mem (sizeof (gfc_unit
));
311 u
->unit_number
= options
.stdout_unit
;
312 u
->s
= output_stream ();
314 u
->flags
.action
= ACTION_WRITE
;
316 u
->flags
.access
= ACCESS_SEQUENTIAL
;
317 u
->flags
.form
= FORM_FORMATTED
;
318 u
->flags
.status
= STATUS_OLD
;
319 u
->flags
.blank
= BLANK_ZERO
;
320 u
->flags
.position
= POSITION_ASIS
;
322 u
->recl
= options
.default_recl
;
323 u
->endfile
= AT_ENDFILE
;
328 /* Calculate the maximum file offset in a portable manner.
329 * max will be the largest signed number for the type gfc_offset.
331 * set a 1 in the LSB and keep a running sum, stopping at MSB-1 bit. */
334 for (i
=0; i
< sizeof(g
.max_offset
) * 8 - 1; i
++)
335 g
.max_offset
= g
.max_offset
+ ((gfc_offset
) 1 << i
);
340 /* close_unit()-- Close a unit. The stream is closed, and any memory
341 * associated with the stream is freed. Returns nonzero on I/O error. */
344 close_unit (gfc_unit
* u
)
348 for (i
= 0; i
< CACHE_SIZE
; i
++)
349 if (unit_cache
[i
] == u
)
350 unit_cache
[i
] = NULL
;
352 rc
= (u
->s
== NULL
) ? 0 : sclose (u
->s
) == FAILURE
;
361 /* close_units()-- Delete units on completion. We just keep deleting
362 * the root of the treap until there is nothing left. */
367 while (g
.unit_root
!= NULL
)
368 close_unit (g
.unit_root
);