Fixed a multitude of C89 compatibility warnings.
[pspp-builds.git] / src / language / stats / rank.q
1 /* PSPP - RANK. -*-c-*-
2
3 Copyright (C) 2005 Free Software Foundation, Inc.
4 Author: John Darrington 2005
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301, USA. */
20
21 #include <config.h>
22 #include <language/command.h>
23 #include <libpspp/compiler.h>
24 #include <data/dictionary.h>
25 #include <math/sort.h>
26 #include <data/variable.h>
27
28 #include "sort-criteria.h"
29
30 #include "gettext.h"
31 #define _(msgid) gettext (msgid)
32
33 /* (headers) */
34
35 /* (specification)
36    "RANK" (rank_):
37    *^variables=custom;
38    +rank=custom;
39    +normal=custom;
40    +percent=custom;
41    +ntiles=custom;
42    +rfraction=custom;
43    +proportion=custom;
44    +n=custom;
45    +savage=custom;
46    +print=print:!yes/no;
47    +missing=miss:!exclude/include.
48 */
49 /* (declarations) */
50 /* (functions) */
51
52
53
54 enum RANK_FUNC
55   {
56     RANK,
57     NORMAL,
58     PERCENT,
59     RFRACTION,
60     PROPORTION,
61     N,
62     NTILES,
63     SAVAGE,
64   };
65
66
67 struct rank_spec
68 {
69   enum RANK_FUNC rfunc;
70   struct variable **destvars;
71   struct variable *srcvar;
72 };
73
74
75 static struct rank_spec *rank_specs;
76 static size_t n_rank_specs;
77
78 static struct sort_criteria *sc;
79
80 static struct variable **group_vars;
81 static size_t n_group_vars;
82
83 static struct cmd_rank cmd;
84
85
86
87 int cmd_rank(void);
88
89 int
90 cmd_rank(void)
91 {
92   size_t i;
93   n_rank_specs = 0;
94
95   if ( !parse_rank(&cmd) )
96     return CMD_FAILURE;
97
98 #if 1
99   for (i = 0 ; i <  sc->crit_cnt ; ++i )
100     {
101       struct sort_criterion *crit = &sc->crits[i];
102       
103       printf("Dir: %d; Index: %d\n", crit->dir, crit->fv);
104     }
105
106   for (i = 0 ; i <  n_group_vars ; ++i )
107     printf("Group var: %s\n",group_vars[0]->name);
108
109   for (i = 0 ; i <  n_rank_specs ; ++i )
110     {
111       int j;
112       printf("Ranks spec %d; Func: %d\n",i, rank_specs[i].rfunc);
113       
114       for (j=0; j < sc->crit_cnt ; ++j )
115         printf("Dest var is \"%s\"\n", rank_specs[i].destvars[j]->name);
116     }
117 #endif 
118
119
120   free(group_vars);
121   
122   for (i = 0 ; i <  n_rank_specs ; ++i )
123     {
124       free(rank_specs[i].destvars);
125     }
126       
127   free(rank_specs);
128
129   sort_destroy_criteria(sc);
130
131   return CMD_SUCCESS;
132 }
133
134
135
136 /* Parser for the variables sub command  
137    Returns 1 on success */
138 static int
139 rank_custom_variables(struct cmd_rank *cmd UNUSED)
140 {
141   static const int terminators[2] = {T_BY, 0};
142
143   lex_match('=');
144
145   if ((token != T_ID || dict_lookup_var (default_dict, tokid) == NULL)
146       && token != T_ALL)
147       return 2;
148
149   sc = sort_parse_criteria (default_dict, 0, 0, 0, terminators);
150
151   if ( lex_match(T_BY)  )
152     {
153       if ((token != T_ID || dict_lookup_var (default_dict, tokid) == NULL))
154         {
155           return 2;
156         }
157
158       if (!parse_variables (default_dict, &group_vars, &n_group_vars,
159                             PV_NO_DUPLICATE | PV_NUMERIC | PV_NO_SCRATCH) )
160         {
161           free (group_vars);
162           return 0;
163         }
164     }
165
166   return 1;
167 }
168
169
170 /* Return a name for a new variable which ranks the variable VAR_NAME,
171    according to the ranking function F.
172    If IDX is non zero, then IDX is used as a disambiguating number.
173    FIXME: This is not very robust.
174 */
175 static char *
176 new_variable_name(const char *ranked_var_name, enum RANK_FUNC f, int idx)
177 {
178   static char new_name[SHORT_NAME_LEN + 1];
179   char temp[SHORT_NAME_LEN + 1];
180  
181   if ( idx == 0 ) 
182     {
183       switch (f) 
184         {
185         case RANK:
186         case RFRACTION:
187           strcpy(new_name,"R");
188           break;
189
190         case NORMAL:
191         case N:
192         case NTILES:
193           strcpy(new_name,"N");
194           break;
195       
196         case PERCENT:
197         case PROPORTION:
198           strcpy(new_name,"P");
199           break;
200
201         case SAVAGE:
202           strcpy(new_name,"S");
203           break;
204
205         default:
206           assert(false);
207           break;
208         }
209   
210       strncat(new_name, ranked_var_name, 7);
211     }
212   else
213     {
214       strncpy(temp, ranked_var_name, 3);
215       snprintf(new_name, SHORT_NAME_LEN, "%s%03d", temp, idx);
216     }
217
218   return new_name;
219 }
220
221 /* Parse the [/rank INTO var1 var2 ... varN ] clause */
222 static int
223 parse_rank_function(struct cmd_rank *cmd UNUSED, enum RANK_FUNC f)
224 {
225   static const struct fmt_spec f8_2 = {FMT_F, 8, 2};
226   int var_count = 0;
227   
228   n_rank_specs++;
229   rank_specs = xnrealloc(rank_specs, n_rank_specs, sizeof *rank_specs);
230   rank_specs[n_rank_specs - 1].rfunc = f;
231
232   rank_specs[n_rank_specs - 1].destvars = 
233             xcalloc (sc->crit_cnt, sizeof (struct variable *));
234           
235   if (lex_match_id("INTO"))
236     {
237       struct variable *destvar;
238
239       while( token == T_ID ) 
240         {
241           ++var_count;
242           if ( dict_lookup_var (default_dict, tokid) != NULL )
243             {
244               msg(ME, _("Variable %s already exists."), tokid);
245               return 0;
246             }
247           if ( var_count > sc->crit_cnt ) 
248             {
249               msg(ME, _("Too many variables in INTO clause."));
250               return 0;
251             }
252
253           destvar = dict_create_var (default_dict, tokid, 0);
254           if ( destvar ) 
255             {
256               destvar->print = destvar->write = f8_2;
257             }
258           
259           rank_specs[n_rank_specs - 1].destvars[var_count - 1] = destvar ;
260
261           lex_get();
262           
263         }
264     }
265
266   /* Allocate rank  variable names to all those which haven't had INTO 
267      variables assigned */
268   while (var_count < sc->crit_cnt)
269     {
270       static int idx=0;
271       struct variable *destvar ; 
272       const struct variable *v = dict_get_var(default_dict,
273                                               sc->crits[var_count].fv);
274
275       char *new_name;
276       
277       do {
278         new_name = new_variable_name(v->name, f, idx);
279
280         destvar = dict_create_var (default_dict, new_name, 0);
281         if (!destvar ) 
282           ++idx;
283
284       } while( !destvar ) ;
285
286       destvar->print = destvar->write = f8_2;
287
288       rank_specs[n_rank_specs - 1].destvars[var_count] = destvar ;
289       
290       ++var_count;
291     }
292
293   return 1;
294 }
295
296
297 static int
298 rank_custom_rank(struct cmd_rank *cmd )
299 {
300   return parse_rank_function(cmd, RANK);
301 }
302
303 static int
304 rank_custom_normal(struct cmd_rank *cmd )
305 {
306   return parse_rank_function(cmd, NORMAL);
307 }
308
309 static int
310 rank_custom_percent(struct cmd_rank *cmd )
311 {
312   return parse_rank_function(cmd, NORMAL);
313 }
314
315 static int
316 rank_custom_rfraction(struct cmd_rank *cmd )
317 {
318   return parse_rank_function(cmd, RFRACTION);
319 }
320
321 static int
322 rank_custom_proportion(struct cmd_rank *cmd )
323 {
324   return parse_rank_function(cmd, PROPORTION);
325 }
326
327 static int
328 rank_custom_n(struct cmd_rank *cmd )
329 {
330   return parse_rank_function(cmd, N);
331 }
332
333 static int
334 rank_custom_savage(struct cmd_rank *cmd )
335 {
336   return parse_rank_function(cmd, SAVAGE);
337 }
338
339
340 static int
341 rank_custom_ntiles(struct cmd_rank *cmd )
342 {
343   if ( lex_force_match('(') ) 
344     {
345       if ( lex_force_int() ) 
346         {
347           lex_get();
348           lex_force_match(')');
349         }
350       else
351         return 0;
352     }
353   else
354     return 0;
355
356   return parse_rank_function(cmd, NTILES);
357 }
358
359