acinclude.m4 (LIBGFOR_CHECK_ATTRIBUTE_VISIBILITY): New.
[gcc.git] / libgfortran / runtime / select.c
1 /* Implement the SELECT statement for character variables.
2 Contributed by Andy Vaught
3
4 This file is part of the GNU Fortran 95 runtime library (libgfor).
5
6 Libgfor 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 Libgfor 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 libgfor; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 #include "libgfortran.h"
22
23 typedef struct
24 {
25 char *low;
26 int low_len;
27 char *high;
28 int high_len;
29 void *address;
30 }
31 select_struct;
32
33 extern void * select_string (select_struct *table, int table_len,
34 void *default_jump, const char *selector,
35 int selector_len);
36 export_proto(select_string);
37
38
39 /* select_string()-- Given a selector string and a table of
40 * select_struct structures, return the address to jump to. */
41
42 void *
43 select_string (select_struct *table, int table_len, void *default_jump,
44 const char *selector, int selector_len)
45 {
46 select_struct *t;
47 int i, low, high, mid;
48
49 if (table_len == 0)
50 return default_jump;
51
52 /* Record the default address if present */
53
54 if (table->low == NULL && table->high == NULL)
55 {
56 default_jump = table->address;
57
58 table++;
59 table_len--;
60 if (table_len == 0)
61 return default_jump;
62 }
63
64 /* Try the high and low bounds if present. */
65
66 if (table->low == NULL)
67 {
68 if (compare_string (table->high_len, table->high,
69 selector_len, selector) >= 0)
70 return table->address;
71
72 table++;
73 table_len--;
74 if (table_len == 0)
75 return default_jump;
76 }
77
78 t = table + table_len - 1;
79
80 if (t->high == NULL)
81 {
82 if (compare_string (t->low_len, t->low,
83 selector_len, selector) <= 0)
84 return t->address;
85
86 table_len--;
87 if (table_len == 0)
88 return default_jump;
89 }
90
91 /* At this point, the only table entries are bounded entries. Find
92 the right entry with a binary chop. */
93
94 low = -1;
95 high = table_len;
96
97 while (low + 1 < high)
98 {
99 mid = (low + high) / 2;
100
101 t = table + mid;
102 i = compare_string (t->low_len, t->low, selector_len, selector);
103
104 if (i == 0)
105 return t->address;
106
107 if (i < 0)
108 low = mid;
109 else
110 high = mid;
111 }
112
113 /* The string now lies between the low indeces of the now-adjacent
114 high and low entries. Because it is less than the low entry of
115 'high', it can't be that one. If low is still -1, then no
116 entries match. Otherwise, we have to check the high entry of
117 'low'. */
118
119 if (low == -1)
120 return default_jump;
121
122 t = table + low;
123 if (compare_string (selector_len, selector,
124 t->high_len, t->high) <= 0)
125 return t->address;
126
127 return default_jump;
128 }