882cfac9cc02f501e02dfa8d5f7555da0fc8b7ae
[pspp] / src / data / spreadsheet-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2007, 2009, 2010, 2011, 2013 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "spreadsheet-reader.h"
20
21 #include "gnumeric-reader.h"
22 #include "ods-reader.h"
23
24 #include <libpspp/str.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <gl/xalloc.h>
28 #include <gl/c-xvasprintf.h>
29 #include <stdlib.h>
30
31 struct spreadsheet * 
32 spreadsheet_open (const char *filename)
33 {
34   struct spreadsheet *ss = NULL;
35
36   ss = ods_probe (filename, true);
37   
38   return ss;
39 }
40
41 void 
42 spreadsheet_close (UNUSED struct spreadsheet *spreadsheet)
43 {
44 }
45
46 #define RADIX 26
47
48 static void
49 reverse (char *s, int len)
50 {
51   int i;
52   for (i = 0; i < len / 2; ++i)
53     {
54       char tmp = s[len - i - 1];
55       s[len - i -1] = s[i];
56       s[i] = tmp;
57     }
58 }
59
60
61 /* Convert a string, which is an integer encoded in base26
62    IE, A=0, B=1, ... Z=25 to the integer it represents.
63    ... except that in this scheme, digits with an exponent
64    greater than 1 are implicitly incremented by 1, so
65    AA  = 0 + 1*26, AB = 1 + 1*26,
66    ABC = 2 + 2*26 + 1*26^2 ....
67 */
68 int
69 ps26_to_int (const char *str)
70 {
71   int i;
72   int multiplier = 1;
73   int result = 0;
74   int len = strlen (str);
75
76   for (i = len - 1 ; i >= 0; --i)
77     {
78       int mantissa = (str[i] - 'A');
79
80       assert (mantissa >= 0);
81       assert (mantissa < RADIX);
82
83       if (i != len - 1)
84         mantissa++;
85
86       result += mantissa * multiplier;
87       multiplier *= RADIX;
88     }
89
90   return result;
91 }
92
93 char *
94 int_to_ps26 (int i)
95 {
96   char *ret = NULL;
97
98   int lower = 0;
99   long long int base = RADIX;
100   int exp = 1;
101
102   assert (i >= 0);
103
104   while (i > lower + base - 1)
105     {
106       lower += base;
107       base *= RADIX;      
108       assert (base > 0);
109       exp++;
110     }
111
112   i -= lower;
113   i += base;
114
115   ret = xmalloc (exp + 1);
116
117   exp = 0;
118   do
119     {
120       ret[exp++] = (i % RADIX) + 'A';
121       i /= RADIX;
122     }
123   while (i > 1);
124
125   ret[exp]='\0';
126
127   reverse (ret, exp);
128   return ret;
129 }
130
131 char *
132 create_cell_ref (int col0, int row0, int coli, int rowi)
133 {
134   char *cs0 ;
135   char *csi ;
136   char *s ;
137
138   if ( col0 < 0) return NULL;
139   if ( rowi < 0) return NULL;
140   if ( coli < 0) return NULL;
141   if ( row0 < 0) return NULL;
142
143   cs0 =  int_to_ps26 (col0);
144   csi =  int_to_ps26 (coli);
145   s =  c_xasprintf ("%s%d:%s%d",
146                          cs0, row0 + 1,
147                          csi, rowi + 1);
148   free (cs0);
149   free (csi);
150
151   return s;
152 }
153
154
155 /* Convert a cell reference in the form "A1:B2", to
156    integers.  A1 means column zero, row zero.
157    B1 means column 1 row 0. AA1 means column 26, row 0.
158 */
159 bool
160 convert_cell_ref (const char *ref,
161                   int *col0, int *row0,
162                   int *coli, int *rowi)
163 {
164   char startcol[5];
165   char stopcol [5];
166
167   int startrow;
168   int stoprow;
169
170   int n = sscanf (ref, "%4[a-zA-Z]%d:%4[a-zA-Z]%d",
171               startcol, &startrow,
172               stopcol, &stoprow);
173   if ( n != 4)
174     return false;
175
176   str_uppercase (startcol);
177   *col0 = ps26_to_int (startcol);
178   str_uppercase (stopcol);
179   *coli = ps26_to_int (stopcol);
180   *row0 = startrow - 1;
181   *rowi = stoprow - 1 ;
182
183   return true;
184 }
185