]>
Commit | Line | Data |
---|---|---|
16d6b8e4 | 1 | /* Implement the SELECT statement for character variables. |
f1717362 | 2 | Copyright (C) 2008-2016 Free Software Foundation, Inc. |
16d6b8e4 | 3 | |
4 | This file is part of the GNU Fortran runtime library (libgfortran). | |
5 | ||
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 | |
6bc9506f | 8 | the Free Software Foundation; either version 3, or (at your option) |
16d6b8e4 | 9 | any later version. |
10 | ||
16d6b8e4 | 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. | |
15 | ||
6bc9506f | 16 | Under Section 7 of GPL version 3, you are granted additional |
17 | permissions described in the GCC Runtime Library Exception, version | |
18 | 3.1, as published by the Free Software Foundation. | |
16d6b8e4 | 19 | |
6bc9506f | 20 | You should have received a copy of the GNU General Public License and |
21 | a copy of the GCC Runtime Library Exception along with this program; | |
22 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | <http://www.gnu.org/licenses/>. */ | |
16d6b8e4 | 24 | |
25 | #define select_string SUFFIX(select_string) | |
26 | #define select_struct SUFFIX(select_struct) | |
27 | #define compare_string SUFFIX(compare_string) | |
28 | ||
29 | typedef struct | |
30 | { | |
31 | CHARTYPE *low; | |
32 | gfc_charlen_type low_len; | |
33 | CHARTYPE *high; | |
34 | gfc_charlen_type high_len; | |
35 | int address; | |
36 | } | |
37 | select_struct; | |
38 | ||
39 | extern int select_string (select_struct *table, int table_len, | |
40 | const CHARTYPE *selector, | |
41 | gfc_charlen_type selector_len); | |
42 | export_proto(select_string); | |
43 | ||
44 | ||
45 | /* select_string()-- Given a selector string and a table of | |
46 | * select_struct structures, return the address to jump to. */ | |
47 | ||
48 | int | |
49 | select_string (select_struct *table, int table_len, const CHARTYPE *selector, | |
50 | gfc_charlen_type selector_len) | |
51 | { | |
52 | select_struct *t; | |
53 | int i, low, high, mid; | |
54 | int default_jump = -1; | |
55 | ||
56 | if (table_len == 0) | |
57 | return -1; | |
58 | ||
59 | /* Record the default address if present */ | |
60 | ||
61 | if (table->low == NULL && table->high == NULL) | |
62 | { | |
63 | default_jump = table->address; | |
64 | ||
65 | table++; | |
66 | table_len--; | |
67 | if (table_len == 0) | |
68 | return default_jump; | |
69 | } | |
70 | ||
71 | /* Try the high and low bounds if present. */ | |
72 | ||
73 | if (table->low == NULL) | |
74 | { | |
75 | if (compare_string (table->high_len, table->high, | |
76 | selector_len, selector) >= 0) | |
77 | return table->address; | |
78 | ||
79 | table++; | |
80 | table_len--; | |
81 | if (table_len == 0) | |
82 | return default_jump; | |
83 | } | |
84 | ||
85 | t = table + table_len - 1; | |
86 | ||
87 | if (t->high == NULL) | |
88 | { | |
89 | if (compare_string (t->low_len, t->low, selector_len, selector) <= 0) | |
90 | return t->address; | |
91 | ||
92 | table_len--; | |
93 | if (table_len == 0) | |
94 | return default_jump; | |
95 | } | |
96 | ||
97 | /* At this point, the only table entries are bounded entries. Find | |
98 | the right entry with a binary chop. */ | |
99 | ||
100 | low = -1; | |
101 | high = table_len; | |
102 | ||
103 | while (low + 1 < high) | |
104 | { | |
105 | mid = (low + high) / 2; | |
106 | ||
107 | t = table + mid; | |
108 | i = compare_string (t->low_len, t->low, selector_len, selector); | |
109 | ||
110 | if (i == 0) | |
111 | return t->address; | |
112 | ||
113 | if (i < 0) | |
114 | low = mid; | |
115 | else | |
116 | high = mid; | |
117 | } | |
118 | ||
119 | /* The string now lies between the low indeces of the now-adjacent | |
120 | high and low entries. Because it is less than the low entry of | |
121 | 'high', it can't be that one. If low is still -1, then no | |
122 | entries match. Otherwise, we have to check the high entry of | |
123 | 'low'. */ | |
124 | ||
125 | if (low == -1) | |
126 | return default_jump; | |
127 | ||
128 | t = table + low; | |
129 | if (compare_string (selector_len, selector, t->high_len, t->high) <= 0) | |
130 | return t->address; | |
131 | ||
132 | return default_jump; | |
133 | } |