Created wrappers for the ods/gnumeric functions
[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
47 struct casereader * 
48 spreadsheet_make_reader (struct spreadsheet *s, const struct spreadsheet_read_options *opts)
49 {
50   return ods_make_reader (s, opts);
51 }
52
53 const char * 
54 spreadsheet_get_sheet_name (struct spreadsheet *s, int n)
55 {
56   return ods_get_sheet_name (s, n);
57 }
58
59 char * 
60 spreadsheet_get_sheet_range (struct spreadsheet *s, int n)
61 {
62   return ods_get_sheet_range (s, n);
63 }
64
65
66 #define RADIX 26
67
68 static void
69 reverse (char *s, int len)
70 {
71   int i;
72   for (i = 0; i < len / 2; ++i)
73     {
74       char tmp = s[len - i - 1];
75       s[len - i -1] = s[i];
76       s[i] = tmp;
77     }
78 }
79
80
81 /* Convert a string, which is an integer encoded in base26
82    IE, A=0, B=1, ... Z=25 to the integer it represents.
83    ... except that in this scheme, digits with an exponent
84    greater than 1 are implicitly incremented by 1, so
85    AA  = 0 + 1*26, AB = 1 + 1*26,
86    ABC = 2 + 2*26 + 1*26^2 ....
87 */
88 int
89 ps26_to_int (const char *str)
90 {
91   int i;
92   int multiplier = 1;
93   int result = 0;
94   int len = strlen (str);
95
96   for (i = len - 1 ; i >= 0; --i)
97     {
98       int mantissa = (str[i] - 'A');
99
100       assert (mantissa >= 0);
101       assert (mantissa < RADIX);
102
103       if (i != len - 1)
104         mantissa++;
105
106       result += mantissa * multiplier;
107       multiplier *= RADIX;
108     }
109
110   return result;
111 }
112
113 char *
114 int_to_ps26 (int i)
115 {
116   char *ret = NULL;
117
118   int lower = 0;
119   long long int base = RADIX;
120   int exp = 1;
121
122   assert (i >= 0);
123
124   while (i > lower + base - 1)
125     {
126       lower += base;
127       base *= RADIX;      
128       assert (base > 0);
129       exp++;
130     }
131
132   i -= lower;
133   i += base;
134
135   ret = xmalloc (exp + 1);
136
137   exp = 0;
138   do
139     {
140       ret[exp++] = (i % RADIX) + 'A';
141       i /= RADIX;
142     }
143   while (i > 1);
144
145   ret[exp]='\0';
146
147   reverse (ret, exp);
148   return ret;
149 }
150
151 char *
152 create_cell_ref (int col0, int row0, int coli, int rowi)
153 {
154   char *cs0 ;
155   char *csi ;
156   char *s ;
157
158   if ( col0 < 0) return NULL;
159   if ( rowi < 0) return NULL;
160   if ( coli < 0) return NULL;
161   if ( row0 < 0) return NULL;
162
163   cs0 =  int_to_ps26 (col0);
164   csi =  int_to_ps26 (coli);
165   s =  c_xasprintf ("%s%d:%s%d",
166                          cs0, row0 + 1,
167                          csi, rowi + 1);
168   free (cs0);
169   free (csi);
170
171   return s;
172 }
173
174
175 /* Convert a cell reference in the form "A1:B2", to
176    integers.  A1 means column zero, row zero.
177    B1 means column 1 row 0. AA1 means column 26, row 0.
178 */
179 bool
180 convert_cell_ref (const char *ref,
181                   int *col0, int *row0,
182                   int *coli, int *rowi)
183 {
184   char startcol[5];
185   char stopcol [5];
186
187   int startrow;
188   int stoprow;
189
190   int n = sscanf (ref, "%4[a-zA-Z]%d:%4[a-zA-Z]%d",
191               startcol, &startrow,
192               stopcol, &stoprow);
193   if ( n != 4)
194     return false;
195
196   str_uppercase (startcol);
197   *col0 = ps26_to_int (startcol);
198   str_uppercase (stopcol);
199   *coli = ps26_to_int (stopcol);
200   *row0 = startrow - 1;
201   *rowi = stoprow - 1 ;
202
203   return true;
204 }
205