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