/[pspp]/pspp/src/get.c
ViewVC logotype

Diff of /pspp/src/get.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.24 by blp, Mon Apr 18 06:15:21 2005 UTC revision 1.25 by blp, Tue Apr 26 06:32:02 2005 UTC
# Line 356  save_trns_free (struct trns_header *t_) Line 356  save_trns_free (struct trns_header *t_)
356      }      }
357  }  }
358    
359  static int rename_variables (struct dictionary *dict);  static bool rename_variables (struct dictionary *dict);
360    static bool drop_variables (struct dictionary *dict);
361    static bool keep_variables (struct dictionary *dict);
362    
363  /* Commands that read and write system files share a great deal  /* Commands that read and write system files share a great deal
364     of common syntactic structure for rearranging and dropping     of common syntactic structure for rearranging and dropping
# Line 393  trim_dictionary (struct dictionary *dict Line 395  trim_dictionary (struct dictionary *dict
395        
396    while (lex_match ('/'))    while (lex_match ('/'))
397      {      {
398          bool ok = true;
399          
400        if (op == OP_SAVE && lex_match_id ("COMPRESSED"))        if (op == OP_SAVE && lex_match_id ("COMPRESSED"))
401          *compress = 1;          *compress = 1;
402        else if (op == OP_SAVE && lex_match_id ("UNCOMPRESSED"))        else if (op == OP_SAVE && lex_match_id ("UNCOMPRESSED"))
403          *compress = 0;          *compress = 0;
404        else if (lex_match_id ("DROP"))        else if (lex_match_id ("DROP"))
405          {          ok = drop_variables (dict);
           struct variable **v;  
           int nv;  
   
           lex_match ('=');  
           if (!parse_variables (dict, &v, &nv, PV_NONE))  
             return false;  
           dict_delete_vars (dict, v, nv);  
           free (v);  
         }  
406        else if (lex_match_id ("KEEP"))        else if (lex_match_id ("KEEP"))
407          {          ok = keep_variables (dict);
           struct variable **v;  
           int nv;  
           int i;  
   
           lex_match ('=');  
           if (!parse_variables (dict, &v, &nv, PV_NONE))  
             return false;  
   
           /* Move the specified variables to the beginning. */  
           dict_reorder_vars (dict, v, nv);  
             
           /* Delete the remaining variables. */  
           v = xrealloc (v, (dict_get_var_cnt (dict) - nv) * sizeof *v);  
           for (i = nv; i < dict_get_var_cnt (dict); i++)  
             v[i - nv] = dict_get_var (dict, i);  
           dict_delete_vars (dict, v, dict_get_var_cnt (dict) - nv);  
           free (v);  
         }  
408        else if (lex_match_id ("RENAME"))        else if (lex_match_id ("RENAME"))
409          {          ok = rename_variables (dict);
           if (!rename_variables (dict))  
             return false;  
         }  
410        else        else
411          {          {
412            lex_error (_("while expecting a valid subcommand"));            lex_error (_("expecting a valid subcommand"));
413            return false;            ok = false;
414          }          }
415    
416        if (dict_get_var_cnt (dict) == 0)        if (!ok)
417          {          return false;
           msg (SE, _("All variables deleted from system file dictionary."));  
           return false;  
         }  
418      }      }
419    
420    if (!lex_end_of_command ())    if (!lex_end_of_command ())
# Line 454  trim_dictionary (struct dictionary *dict Line 425  trim_dictionary (struct dictionary *dict
425  }  }
426    
427  /* Parses and performs the RENAME subcommand of GET and SAVE. */  /* Parses and performs the RENAME subcommand of GET and SAVE. */
428  static int  static bool
429  rename_variables (struct dictionary *dict)  rename_variables (struct dictionary *dict)
430  {  {
431    int i;    int i;
# Line 541  done: Line 512  done:
512    
513    return success;    return success;
514  }  }
515    
516    /* Parses and performs the DROP subcommand of GET and SAVE.
517       Returns true if successful, false on failure.*/
518    static bool
519    drop_variables (struct dictionary *dict)
520    {
521      struct variable **v;
522      int nv;
523    
524      lex_match ('=');
525      if (!parse_variables (dict, &v, &nv, PV_NONE))
526        return false;
527      dict_delete_vars (dict, v, nv);
528      free (v);
529    
530      if (dict_get_var_cnt (dict) == 0)
531        {
532          msg (SE, _("Cannot DROP all variables from dictionary."));
533          return false;
534        }
535      return true;
536    }
537    
538    /* Parses and performs the KEEP subcommand of GET and SAVE.
539       Returns true if successful, false on failure.*/
540    static bool
541    keep_variables (struct dictionary *dict)
542    {
543      struct variable **v;
544      int nv;
545      int i;
546    
547      lex_match ('=');
548      if (!parse_variables (dict, &v, &nv, PV_NONE))
549        return false;
550    
551      /* Move the specified variables to the beginning. */
552      dict_reorder_vars (dict, v, nv);
553              
554      /* Delete the remaining variables. */
555      v = xrealloc (v, (dict_get_var_cnt (dict) - nv) * sizeof *v);
556      for (i = nv; i < dict_get_var_cnt (dict); i++)
557        v[i - nv] = dict_get_var (dict, i);
558      dict_delete_vars (dict, v, dict_get_var_cnt (dict) - nv);
559      free (v);
560    
561      return true;
562    }
563    
564  /* EXPORT procedure. */  /* EXPORT procedure. */
565  struct export_proc  struct export_proc
# Line 650  struct mtf_file Line 669  struct mtf_file
669      struct file_handle *handle; /* File handle. */      struct file_handle *handle; /* File handle. */
670      struct sfm_reader *reader;  /* System file reader. */      struct sfm_reader *reader;  /* System file reader. */
671      struct dictionary *dict;    /* Dictionary from system file. */      struct dictionary *dict;    /* Dictionary from system file. */
672      char in[SHORT_NAME_LEN + 1]; /* Name of the variable from IN=. */  
673        /* IN subcommand. */
674        char *in_name;              /* Variable name. */
675        struct variable *in_var;    /* Variable (in master dictionary). */
676    
677      struct ccase input;         /* Input record. */      struct ccase input;         /* Input record. */
678    };    };
# Line 694  cmd_match_files (void) Line 716  cmd_match_files (void)
716  {  {
717    struct mtf_proc mtf;    struct mtf_proc mtf;
718    struct mtf_file *first_table = NULL;    struct mtf_file *first_table = NULL;
719      struct mtf_file *iter;
720        
721    bool used_active_file = false;    bool used_active_file = false;
722    bool saw_table = false;    bool saw_table = false;
723      bool saw_in = false;
724        
725    mtf.head = mtf.tail = NULL;    mtf.head = mtf.tail = NULL;
726    mtf.by_cnt = 0;    mtf.by_cnt = 0;
# Line 728  cmd_match_files (void) Line 752  cmd_match_files (void)
752        file->handle = NULL;        file->handle = NULL;
753        file->reader = NULL;        file->reader = NULL;
754        file->dict = NULL;        file->dict = NULL;
755        file->in[0] = '\0';        file->in_name = NULL;
756          file->in_var = NULL;
757        case_nullify (&file->input);        case_nullify (&file->input);
758    
759        /* FILEs go first, then TABLEs. */        /* FILEs go first, then TABLEs. */
# Line 818  cmd_match_files (void) Line 843  cmd_match_files (void)
843                  goto error;                  goto error;
844                }                }
845    
846              if (file->in[0])              if (file->in_name != NULL)
847                {                {
848                  msg (SE, _("Multiple IN subcommands for a single FILE or "                  msg (SE, _("Multiple IN subcommands for a single FILE or "
849                             "TABLE."));                             "TABLE."));
850                  goto error;                  goto error;
851                }                }
852              strcpy (file->in, tokid);              file->in_name = xstrdup (tokid);
853              lex_get ();              lex_get ();
854                saw_in = true;
855            }            }
856    
857        mtf_merge_dictionary (mtf.dict, file);        mtf_merge_dictionary (mtf.dict, file);
858      }      }
859            
860    while (token != '.')    while (token != '.')
861      {      {
862        if (lex_match (T_BY))        if (lex_match (T_BY))
863          {          {
864            struct variable **by;            struct variable **by;
           struct mtf_file *iter;  
865                        
866            if (mtf.by_cnt)            if (mtf.by_cnt)
867              {              {
# Line 901  cmd_match_files (void) Line 926  cmd_match_files (void)
926          {          {
927            /* FIXME. */            /* FIXME. */
928          }          }
929          else if (lex_match_id ("DROP"))
930            {
931              if (!drop_variables (mtf.dict))
932                goto error;
933            }
934          else if (lex_match_id ("KEEP"))
935            {
936              if (!keep_variables (mtf.dict))
937                goto error;
938            }
939        else        else
940          {          {
941            lex_error (NULL);            lex_error (NULL);
# Line 914  cmd_match_files (void) Line 949  cmd_match_files (void)
949          }          }
950      }      }
951    
952    if (mtf.by_cnt == 0 && saw_table)    if (mtf.by_cnt == 0)
953        {
954          if (saw_table)
955            {
956              msg (SE, _("BY is required when TABLE is specified."));
957              goto error;
958            }
959          if (saw_in)
960            {
961              msg (SE, _("BY is required when IN is specified."));
962              goto error;
963            }
964        }
965    
966      for (iter = mtf.head; iter != NULL; iter = iter->next)
967      {      {
968        msg (SE, _("BY is required when TABLE is specified."));        struct dictionary *d = iter->dict;
969        goto error;        int i;
970    
971          for (i = 0; i < dict_get_var_cnt (d); i++)
972            {
973              struct variable *v = dict_get_var (d, i);
974              struct variable *mv = dict_lookup_var (mtf.dict, v->name);
975              if (mv != NULL)
976                set_master (v, mv);
977            }
978      }      }
979    
980      for (iter = mtf.head; iter != NULL; iter = iter->next)
981        if (iter->in_name != NULL)
982          {
983            static const struct fmt_spec f1_0 = {FMT_F, 1, 0};
984            
985            iter->in_var = dict_create_var (mtf.dict, iter->in_name, 0);
986            if (iter->in_var == NULL)
987              {
988                msg (SE, _("IN variable name %s duplicates an "
989                           "existing variable name."),
990                     iter->in_var);
991                goto error;
992              }
993            iter->in_var->print = iter->in_var->write = f1_0;
994          }
995        
996    /* MATCH FILES performs an n-way merge on all its input files.    /* MATCH FILES performs an n-way merge on all its input files.
997       Abstract algorithm:       Abstract algorithm:
998    
# Line 927  cmd_match_files (void) Line 1000  cmd_match_files (void)
1000    
1001       2. If no FILEs are left, stop.  Otherwise, proceed to step 3.       2. If no FILEs are left, stop.  Otherwise, proceed to step 3.
1002    
1003       3. Find the FILE input record with minimum BY values.  Store all       3. Find the FILE input record(s) that have minimum BY
1004       the values from this input record into the output record.       values.  Store all the values from these input records into
   
      4. Find all the FILE input records with BY values identical to  
      the minimums.  Store all the values from these input records into  
1005       the output record.       the output record.
1006    
1007       5. For every TABLE, read another record as long as the BY values       4. For every TABLE, read another record as long as the BY values
1008       on the TABLE's input record are less than the FILEs' BY values.       on the TABLE's input record are less than the FILEs' BY values.
1009       If an exact match is found, store all the values from the TABLE       If an exact match is found, store all the values from the TABLE
1010       input record into the output record.       input record into the output record.
1011    
1012       6. Write the output record.       5. Write the output record.
1013    
1014       7. Read another record from each input file FILE and TABLE that       6. Read another record from each input file FILE and TABLE that
1015       we stored values from above.  If we come to the end of one of the       we stored values from above.  If we come to the end of one of the
1016       input files, remove it from the list of input files.       input files, remove it from the list of input files.
1017    
1018       8. Repeat from step 2.       7. Repeat from step 2.
1019    
1020       Unfortunately, this algorithm can't be directly implemented       Unfortunately, this algorithm can't be implemented in a
1021       because there's no function to read a record from the active       straightforward way because there's no function to read a
1022       file; instead, it has to be done using callbacks.       record from the active file.  Instead, it has to be written
1023         as a state machine.
1024    
1025       FIXME: For merging large numbers of files (more than 10?) a       FIXME: For merging large numbers of files (more than 10?) a
1026       better algorithm would use a heap for finding minimum       better algorithm would use a heap for finding minimum
# Line 958  cmd_match_files (void) Line 1029  cmd_match_files (void)
1029    if (!used_active_file)    if (!used_active_file)
1030      discard_variables ();      discard_variables ();
1031    
1032      dict_compact_values (mtf.dict);
1033    mtf.sink = create_case_sink (&storage_sink_class, mtf.dict, NULL);    mtf.sink = create_case_sink (&storage_sink_class, mtf.dict, NULL);
1034    if (mtf.sink->class->open != NULL)    if (mtf.sink->class->open != NULL)
1035      mtf.sink->class->open (mtf.sink);      mtf.sink->class->open (mtf.sink);
1036    
1037    mtf.seq_nums = xmalloc (dict_get_var_cnt (mtf.dict) * sizeof *mtf.seq_nums);    mtf.seq_nums = xcalloc (dict_get_var_cnt (mtf.dict) * sizeof *mtf.seq_nums);
   memset (mtf.seq_nums, 0,  
           dict_get_var_cnt (mtf.dict) * sizeof *mtf.seq_nums);  
1038    case_create (&mtf.mtf_case, dict_get_next_value_idx (mtf.dict));    case_create (&mtf.mtf_case, dict_get_next_value_idx (mtf.dict));
1039    
1040    mtf_read_nonactive_records (&mtf);    mtf_read_nonactive_records (&mtf);
# Line 986  error: Line 1056  error:
1056    return CMD_FAILURE;    return CMD_FAILURE;
1057  }  }
1058    
1059  /* Repeats 2...8 an arbitrary number of times. */  /* Repeats 2...7 an arbitrary number of times. */
1060  static void  static void
1061  mtf_processing_finish (void *mtf_)  mtf_processing_finish (void *mtf_)
1062  {  {
# Line 1037  mtf_free_file (struct mtf_file *file) Line 1107  mtf_free_file (struct mtf_file *file)
1107    if (file->dict != default_dict)    if (file->dict != default_dict)
1108      dict_destroy (file->dict);      dict_destroy (file->dict);
1109    case_destroy (&file->input);    case_destroy (&file->input);
1110      free (file->in_name);
1111    free (file);    free (file);
1112  }  }
1113    
# Line 1049  mtf_free (struct mtf_proc *mtf) Line 1120  mtf_free (struct mtf_proc *mtf)
1120    for (iter = mtf->head; iter; iter = next)    for (iter = mtf->head; iter; iter = next)
1121      {      {
1122        next = iter->next;        next = iter->next;
   
1123        mtf_free_file (iter);        mtf_free_file (iter);
1124      }      }
1125        
# Line 1065  static void Line 1135  static void
1135  mtf_delete_file_in_place (struct mtf_proc *mtf, struct mtf_file **file)  mtf_delete_file_in_place (struct mtf_proc *mtf, struct mtf_file **file)
1136  {  {
1137    struct mtf_file *f = *file;    struct mtf_file *f = *file;
1138      int i;
1139    
1140    if (f->prev)    if (f->prev)
1141      f->prev->next = f->next;      f->prev->next = f->next;
# Line 1076  mtf_delete_file_in_place (struct mtf_pro Line 1147  mtf_delete_file_in_place (struct mtf_pro
1147      mtf->tail = f->prev;      mtf->tail = f->prev;
1148    *file = f->next;    *file = f->next;
1149    
1150    {    if (f->in_var != NULL)
1151      int i;      case_data_rw (&mtf->mtf_case, f->in_var->fv)->f = 0.;
1152      for (i = 0; i < dict_get_var_cnt (f->dict); i++)
1153      for (i = 0; i < dict_get_var_cnt (f->dict); i++)      {
1154        {        struct variable *v = dict_get_var (f->dict, i);
1155          struct variable *v = dict_get_var (f->dict, i);        struct variable *mv = get_master (v);
1156          union value *out = case_data_rw (&mtf->mtf_case, get_master (v)->fv);        if (mv != NULL)
1157            {
1158              union value *out = case_data_rw (&mtf->mtf_case, mv->fv);
1159                        
1160          if (v->type == NUMERIC)            if (v->type == NUMERIC)
1161            out->f = SYSMIS;              out->f = SYSMIS;
1162          else            else
1163            memset (out->s, ' ', v->width);              memset (out->s, ' ', v->width);
1164        }          }
1165    }      }
1166    
1167    mtf_free_file (f);    mtf_free_file (f);
1168  }  }
# Line 1099  static void Line 1172  static void
1172  mtf_read_nonactive_records (void *mtf_)  mtf_read_nonactive_records (void *mtf_)
1173  {  {
1174    struct mtf_proc *mtf = mtf_;    struct mtf_proc *mtf = mtf_;
1175    struct mtf_file *iter;    struct mtf_file *iter, *next;
1176    
1177    for (iter = mtf->head; iter; )    for (iter = mtf->head; iter != NULL; iter = next)
1178      {      {
1179        if (iter->handle)        next = iter->next;
1180          {        if (iter->handle && !sfm_read_case (iter->reader, &iter->input))
1181            if (!sfm_read_case (iter->reader, &iter->input))          mtf_delete_file_in_place (mtf, &iter);
             mtf_delete_file_in_place (mtf, &iter);  
           else  
             iter = iter->next;  
         }  
       else  
         iter = iter->next;  
1182      }      }
1183  }  }
1184    
# Line 1122  mtf_compare_BY_values (struct mtf_proc * Line 1189  mtf_compare_BY_values (struct mtf_proc *
1189                         struct mtf_file *a, struct mtf_file *b,                         struct mtf_file *a, struct mtf_file *b,
1190                         struct ccase *c)                         struct ccase *c)
1191  {  {
1192    struct ccase *a_input, *b_input;    struct ccase *ca = case_is_null (&a->input) ? c : &a->input;
1193    int i;    struct ccase *cb = case_is_null (&b->input) ? c : &b->input;
   
1194    assert ((a == NULL) + (b == NULL) + (c == NULL) <= 1);    assert ((a == NULL) + (b == NULL) + (c == NULL) <= 1);
1195    a_input = case_is_null (&a->input) ? c : &a->input;    return case_compare_2dict (ca, cb, a->by, b->by, mtf->by_cnt);
   b_input = case_is_null (&b->input) ? c : &b->input;  
   for (i = 0; i < mtf->by_cnt; i++)  
     {  
       assert (a->by[i]->type == b->by[i]->type);  
       assert (a->by[i]->width == b->by[i]->width);  
         
       if (a->by[i]->type == NUMERIC)  
         {  
           double af = case_num (a_input, a->by[i]->fv);  
           double bf = case_num (b_input, b->by[i]->fv);  
   
           if (af < bf)  
             return -1;  
           else if (af > bf)  
             return 1;  
         }  
       else  
         {  
           int result;  
             
           assert (a->by[i]->type == ALPHA);  
           result = memcmp (case_str (a_input, a->by[i]->fv),  
                            case_str (b_input, b->by[i]->fv),  
                            a->by[i]->width);  
           if (result < 0)  
             return -1;  
           else if (result > 0)  
             return 1;  
         }  
     }  
   return 0;  
1196  }  }
1197    
1198  /* Perform one iteration of steps 3...7 above. */  /* Perform one iteration of steps 3...7 above. */
# Line 1165  static int Line 1200  static int
1200  mtf_processing (struct ccase *c, void *mtf_)  mtf_processing (struct ccase *c, void *mtf_)
1201  {  {
1202    struct mtf_proc *mtf = mtf_;    struct mtf_proc *mtf = mtf_;
   struct mtf_file *min_head, *min_tail; /* Files with minimum BY values. */  
   struct mtf_file *max_head, *max_tail; /* Files with non-minimum BY values. */  
   struct mtf_file *iter;                /* Iterator. */  
1203    
1204    for (;;)    /* Do we need another record from the active file? */
1205      bool read_active_file;
1206    
1207      assert (mtf->head != NULL);
1208      assert (mtf->head->type == MTF_FILE);
1209      do
1210      {      {
1211        /* If the active file doesn't have the minimum BY values, don't        struct mtf_file *min_head, *min_tail; /* Files with minimum BY values. */
1212           return because that would cause a record to be skipped. */        struct mtf_file *max_head, *max_tail; /* Files with non-minimum BYs. */
1213        bool advance = true;        struct mtf_file *iter, *next;
1214    
1215        if (mtf->head->type == MTF_TABLE)        read_active_file = false;
         return 0;  
1216                
1217        /* 3. Find the FILE input record with minimum BY values.  Store        /* 3. Find the FILE input record(s) that have minimum BY
1218           all the values from this input record into the output record.           values.  Store all the values from these input records into
1219             the output record. */
          4. Find all the FILE input records with BY values identical  
          to the minimums.  Store all the values from these input  
          records into the output record. */  
1220        min_head = min_tail = mtf->head;        min_head = min_tail = mtf->head;
1221        max_head = max_tail = NULL;        max_head = max_tail = NULL;
1222        for (iter = mtf->head->next; iter && iter->type == MTF_FILE;        for (iter = mtf->head->next; iter && iter->type == MTF_FILE;
# Line 1219  mtf_processing (struct ccase *c, void *m Line 1252  mtf_processing (struct ccase *c, void *m
1252              assert (0);              assert (0);
1253            }            }
1254    
1255        /* 5. For every TABLE, read another record as long as the BY        /* 4. For every TABLE, read another record as long as the BY
1256           values on the TABLE's input record are less than the FILEs'           values on the TABLE's input record are less than the FILEs'
1257           BY values.  If an exact match is found, store all the values           BY values.  If an exact match is found, store all the values
1258           from the TABLE input record into the output record. */           from the TABLE input record into the output record. */
1259        while (iter)        for (; iter != NULL; iter = next)
1260          {          {
           struct mtf_file *next = iter->next;  
             
1261            assert (iter->type == MTF_TABLE);            assert (iter->type == MTF_TABLE);
1262                
1263            if (iter->handle == NULL)            next = iter->next;
             advance = false;  
1264    
1265          again:          again:
1266            switch (mtf_compare_BY_values (mtf, min_head, iter, c))            switch (mtf_compare_BY_values (mtf, min_head, iter, c))
# Line 1257  mtf_processing (struct ccase *c, void *m Line 1287  mtf_processing (struct ccase *c, void *m
1287              default:              default:
1288                assert (0);                assert (0);
1289              }              }
   
           iter = next;  
1290          }          }
1291    
1292        /* Next sequence number. */        /* Next sequence number. */
1293        mtf->seq_num++;        mtf->seq_num++;
1294      
1295        /* Store data to all the records we are using. */        /* Store data to all the records we are using. */
1296        if (min_tail)        if (min_tail)
1297          min_tail->next_min = NULL;          min_tail->next_min = NULL;
# Line 1276  mtf_processing (struct ccase *c, void *m Line 1304  mtf_processing (struct ccase *c, void *m
1304                struct variable *v = dict_get_var (iter->dict, i);                struct variable *v = dict_get_var (iter->dict, i);
1305                struct variable *mv = get_master (v);                struct variable *mv = get_master (v);
1306                        
1307                if (mtf->seq_nums[mv->index] != mtf->seq_num)                if (mv != NULL && mtf->seq_nums[mv->index] != mtf->seq_num)
1308                  {                  {
1309                    struct ccase *record                    struct ccase *record
1310                      = case_is_null (&iter->input) ? c : &iter->input;                      = case_is_null (&iter->input) ? c : &iter->input;
# Line 1289  mtf_processing (struct ccase *c, void *m Line 1317  mtf_processing (struct ccase *c, void *m
1317                      memcpy (out->s, case_str (record, v->fv), v->width);                      memcpy (out->s, case_str (record, v->fv), v->width);
1318                  }                  }
1319              }              }
1320              if (iter->in_var != NULL)
1321                case_data_rw (&mtf->mtf_case, iter->in_var->fv)->f = 1.;
1322    
1323              if (iter->type == MTF_FILE && iter->handle == NULL)
1324                read_active_file = true;
1325          }          }
1326    
1327        /* Store missing values to all the records we're not using. */        /* Store missing values to all the records we're not
1328             using. */
1329        if (max_tail)        if (max_tail)
1330          max_tail->next_min = NULL;          max_tail->next_min = NULL;
1331        for (iter = max_head; iter; iter = iter->next_min)        for (iter = max_head; iter; iter = iter->next_min)
# Line 1302  mtf_processing (struct ccase *c, void *m Line 1336  mtf_processing (struct ccase *c, void *m
1336              {              {
1337                struct variable *v = dict_get_var (iter->dict, i);                struct variable *v = dict_get_var (iter->dict, i);
1338                struct variable *mv = get_master (v);                struct variable *mv = get_master (v);
1339              
1340                if (mtf->seq_nums[mv->index] != mtf->seq_num)                if (mv != NULL && mtf->seq_nums[mv->index] != mtf->seq_num)
1341                  {                  {
1342                    union value *out = case_data_rw (&mtf->mtf_case, mv->fv);                    union value *out = case_data_rw (&mtf->mtf_case, mv->fv);
1343                    mtf->seq_nums[mv->index] = mtf->seq_num;                    mtf->seq_nums[mv->index] = mtf->seq_num;
# Line 1314  mtf_processing (struct ccase *c, void *m Line 1348  mtf_processing (struct ccase *c, void *m
1348                      memset (out->s, ' ', v->width);                      memset (out->s, ' ', v->width);
1349                  }                  }
1350              }              }
1351              if (iter->in_var != NULL)
1352            if (iter->handle == NULL)              case_data_rw (&mtf->mtf_case, iter->in_var->fv)->f = 0.;
             advance = false;  
1353          }          }
1354    
1355        /* 6. Write the output record. */        /* 5. Write the output record. */
1356        mtf->sink->class->write (mtf->sink, &mtf->mtf_case);        mtf->sink->class->write (mtf->sink, &mtf->mtf_case);
1357    
1358        /* 7. Read another record from each input file FILE and TABLE        /* 6. Read another record from each input file FILE and TABLE
1359           that we stored values from above.  If we come to the end of           that we stored values from above.  If we come to the end of
1360           one of the input files, remove it from the list of input           one of the input files, remove it from the list of input
1361           files. */           files. */
1362        for (iter = min_head; iter && iter->type == MTF_FILE; )        for (iter = min_head; iter && iter->type == MTF_FILE; iter = next)
1363          {          {
1364            struct mtf_file *next = iter->next_min;            next = iter->next_min;
1365                        if (iter->reader != NULL
1366            if (iter->reader != NULL)                && !sfm_read_case (iter->reader, &iter->input))
1367              {              mtf_delete_file_in_place (mtf, &iter);
               if (!sfm_read_case (iter->reader, &iter->input))  
                 mtf_delete_file_in_place (mtf, &iter);  
             }  
   
           iter = next;  
1368          }          }
         
       if (advance)  
         break;  
1369      }      }
1370      while (!read_active_file
1371             && mtf->head != NULL && mtf->head->type == MTF_FILE);
1372    
1373    return (mtf->head && mtf->head->type != MTF_TABLE);    return mtf->head != NULL && mtf->head->type == MTF_FILE;
1374  }  }
1375    
1376  /* Merge the dictionary for file F into master dictionary M. */  /* Merge the dictionary for file F into master dictionary M. */
# Line 1414  mtf_merge_dictionary (struct dictionary Line 1441  mtf_merge_dictionary (struct dictionary
1441            mv = dict_clone_var (m, dv, dv->name, dv->longname);            mv = dict_clone_var (m, dv, dv->name, dv->longname);
1442            assert (mv != NULL);            assert (mv != NULL);
1443          }          }
           
       set_master (dv, mv);  
1444      }      }
1445    
1446    return 1;    return 1;
# Line 1433  set_master (struct variable *v, struct v Line 1458  set_master (struct variable *v, struct v
1458  static struct variable *  static struct variable *
1459  get_master (struct variable *v)  get_master (struct variable *v)
1460  {  {
   assert (v->aux != NULL);  
1461    return v->aux;    return v->aux;
1462  }  }
1463    

Legend:
Removed from v.1.24  
changed lines
  Added in v.1.25

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26