OSDN Git Service

2004-10-18 Revital Eres <eres@il.ibm.com>
[pf3gnuchains/gcc-fork.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
34 #define select_string prefix(select_string)
35
36
37 /* select_string()-- Given a selector string and a table of
38  * select_struct structures, return the address to jump to. */
39
40 void *select_string (select_struct *table, int table_len, void *default_jump,
41                     const char *selector, int selector_len)
42 {
43   select_struct *t;
44   int i, low, high, mid;
45
46   if (table_len == 0)
47     return default_jump;
48
49   /* Record the default address if present */
50
51   if (table->low == NULL && table->high == NULL)
52     {
53       default_jump = table->address;
54
55       table++;
56       table_len--;
57       if (table_len == 0)
58         return default_jump;
59     }
60
61   /* Try the high and low bounds if present. */
62
63   if (table->low == NULL)
64     {
65       if (compare_string (table->high_len, table->high,
66                                 selector_len, selector) >= 0)
67         return table->address;
68
69       table++;
70       table_len--;
71       if (table_len == 0)
72         return default_jump;
73     }
74
75   t = table + table_len - 1;
76
77   if (t->high == NULL)
78     {
79       if (compare_string (t->low_len, t->low,
80                                 selector_len, selector) <= 0)
81         return t->address;
82
83       table_len--;
84       if (table_len == 0)
85         return default_jump;
86     }
87
88   /* At this point, the only table entries are bounded entries.  Find
89      the right entry with a binary chop. */
90
91   low = -1;
92   high = table_len;
93
94   while (low + 1 < high)
95     {
96       mid = (low + high) / 2;
97
98       t = table + mid;
99       i = compare_string (t->low_len, t->low, selector_len, selector);
100
101       if (i == 0)
102         return t->address;
103
104       if (i < 0)
105         low = mid;
106       else
107         high = mid;
108     }
109
110   /* The string now lies between the low indeces of the now-adjacent
111      high and low entries.  Because it is less than the low entry of
112      'high', it can't be that one.  If low is still -1, then no
113      entries match.  Otherwise, we have to check the high entry of
114      'low'. */
115
116   if (low == -1)
117     return default_jump;
118
119   t = table + low;
120   if (compare_string (selector_len, selector,
121                             t->high_len, t->high) <= 0)
122     return t->address;
123
124   return default_jump;
125 }