/[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.23 by jmd, Wed Apr 13 10:09:59 2005 UTC revision 1.24 by blp, Mon Apr 18 06:15:21 2005 UTC
# Line 54  enum operation Line 54  enum operation
54    {    {
55      OP_READ,    /* GET or IMPORT. */      OP_READ,    /* GET or IMPORT. */
56      OP_SAVE,    /* SAVE or XSAVE. */      OP_SAVE,    /* SAVE or XSAVE. */
57      OP_EXPORT,  /* EXPORT. */      OP_EXPORT   /* EXPORT. */
     OP_MATCH    /* MATCH FILES. */  
58    };    };
59    
60  static int trim_dictionary (struct dictionary *,  static bool trim_dictionary (struct dictionary *,
61                              enum operation, int *compress);                               enum operation, int *compress);
62    
63  /* GET input program. */  /* GET input program. */
64  struct get_pgm  struct get_pgm
# Line 368  static int rename_variables (struct dict Line 367  static int rename_variables (struct dict
367     write a system file, *COMPRESS is set to 1 if the system file     write a system file, *COMPRESS is set to 1 if the system file
368     should be compressed, 0 otherwise.     should be compressed, 0 otherwise.
369        
370     Returns nonzero on success, zero on failure. */     Returns true on success, false on failure. */
371  /* FIXME: IN, FIRST, LAST, MAP. */  static bool
 static int  
372  trim_dictionary (struct dictionary *dict, enum operation op, int *compress)  trim_dictionary (struct dictionary *dict, enum operation op, int *compress)
373  {  {
374    assert ((compress != NULL) == (op == OP_SAVE));    assert ((compress != NULL) == (op == OP_SAVE));
# Line 393  trim_dictionary (struct dictionary *dict Line 391  trim_dictionary (struct dictionary *dict
391        free (v);        free (v);
392      }      }
393        
394    while (op == OP_MATCH || lex_match ('/'))    while (lex_match ('/'))
395      {      {
396        if (op == OP_SAVE && lex_match_id ("COMPRESSED"))        if (op == OP_SAVE && lex_match_id ("COMPRESSED"))
397          *compress = 1;          *compress = 1;
# Line 406  trim_dictionary (struct dictionary *dict Line 404  trim_dictionary (struct dictionary *dict
404    
405            lex_match ('=');            lex_match ('=');
406            if (!parse_variables (dict, &v, &nv, PV_NONE))            if (!parse_variables (dict, &v, &nv, PV_NONE))
407              return 0;              return false;
408            dict_delete_vars (dict, v, nv);            dict_delete_vars (dict, v, nv);
409            free (v);            free (v);
410          }          }
# Line 418  trim_dictionary (struct dictionary *dict Line 416  trim_dictionary (struct dictionary *dict
416    
417            lex_match ('=');            lex_match ('=');
418            if (!parse_variables (dict, &v, &nv, PV_NONE))            if (!parse_variables (dict, &v, &nv, PV_NONE))
419              return 0;              return false;
420    
421            /* Move the specified variables to the beginning. */            /* Move the specified variables to the beginning. */
422            dict_reorder_vars (dict, v, nv);            dict_reorder_vars (dict, v, nv);
# Line 433  trim_dictionary (struct dictionary *dict Line 431  trim_dictionary (struct dictionary *dict
431        else if (lex_match_id ("RENAME"))        else if (lex_match_id ("RENAME"))
432          {          {
433            if (!rename_variables (dict))            if (!rename_variables (dict))
434              return 0;              return false;
435          }          }
436        else        else
437          {          {
438            lex_error (_("while expecting a valid subcommand"));            lex_error (_("while expecting a valid subcommand"));
439            return 0;            return false;
440          }          }
441    
442        if (dict_get_var_cnt (dict) == 0)        if (dict_get_var_cnt (dict) == 0)
443          {          {
444            msg (SE, _("All variables deleted from system file dictionary."));            msg (SE, _("All variables deleted from system file dictionary."));
445            return 0;            return false;
446          }          }
   
       if (op == OP_MATCH)  
         goto success;  
447      }      }
448    
449    if (token != '.')    if (!lex_end_of_command ())
450      {      return false;
       lex_error (_("expecting end of command"));  
       return 0;  
     }  
451    
452   success:    dict_compact_values (dict);
453    if (op != OP_MATCH)    return true;
     dict_compact_values (dict);  
   return 1;  
454  }  }
455    
456  /* Parses and performs the RENAME subcommand of GET and SAVE. */  /* Parses and performs the RENAME subcommand of GET and SAVE. */
# Line 660  struct mtf_file Line 650  struct mtf_file
650      struct file_handle *handle; /* File handle. */      struct file_handle *handle; /* File handle. */
651      struct sfm_reader *reader;  /* System file reader. */      struct sfm_reader *reader;  /* System file reader. */
652      struct dictionary *dict;    /* Dictionary from system file. */      struct dictionary *dict;    /* Dictionary from system file. */
653      char in[SHORT_NAME_LEN + 1];    /* Name of the variable from IN=. */      char in[SHORT_NAME_LEN + 1]; /* Name of the variable from IN=. */
654      char first[SHORT_NAME_LEN + 1];  
     char last[SHORT_NAME_LEN + 1];      /* Name of the variables from FIRST=, LAST=. */  
655      struct ccase input;         /* Input record. */      struct ccase input;         /* Input record. */
656    };    };
657    
# Line 672  struct mtf_proc Line 661  struct mtf_proc
661      struct mtf_file *head;      /* First file mentioned on FILE or TABLE. */      struct mtf_file *head;      /* First file mentioned on FILE or TABLE. */
662      struct mtf_file *tail;      /* Last file mentioned on FILE or TABLE. */      struct mtf_file *tail;      /* Last file mentioned on FILE or TABLE. */
663            
     struct variable **by;       /* Variables on the BY subcommand. */  
664      size_t by_cnt;              /* Number of variables on BY subcommand. */      size_t by_cnt;              /* Number of variables on BY subcommand. */
665    
666        /* Names of FIRST, LAST variables. */
667        char first[SHORT_NAME_LEN + 1], last[SHORT_NAME_LEN + 1];
668        
669      struct dictionary *dict;    /* Dictionary of output file. */      struct dictionary *dict;    /* Dictionary of output file. */
670      struct case_sink *sink;     /* Sink to receive output. */      struct case_sink *sink;     /* Sink to receive output. */
671      struct ccase *mtf_case;     /* Case used for output. */      struct ccase mtf_case;      /* Case used for output. */
672    
673      unsigned seq_num;           /* Have we initialized this variable? */      unsigned seq_num;           /* Have we initialized this variable? */
674      unsigned *seq_nums;         /* Sequence numbers for each var in dict. */      unsigned *seq_nums;         /* Sequence numbers for each var in dict. */
# Line 703  cmd_match_files (void) Line 694  cmd_match_files (void)
694  {  {
695    struct mtf_proc mtf;    struct mtf_proc mtf;
696    struct mtf_file *first_table = NULL;    struct mtf_file *first_table = NULL;
   struct mtf_file *iter;  
697        
698    int seen = 0;    bool used_active_file = false;
699      bool saw_table = false;
700        
701    mtf.head = mtf.tail = NULL;    mtf.head = mtf.tail = NULL;
   mtf.by = NULL;  
702    mtf.by_cnt = 0;    mtf.by_cnt = 0;
703      mtf.first[0] = '\0';
704      mtf.last[0] = '\0';
705    mtf.dict = dict_create ();    mtf.dict = dict_create ();
706    mtf.sink = NULL;    mtf.sink = NULL;
707    mtf.mtf_case = NULL;    case_nullify (&mtf.mtf_case);
708    mtf.seq_num = 0;    mtf.seq_num = 0;
709    mtf.seq_nums = NULL;    mtf.seq_nums = NULL;
710    dict_set_case_limit (mtf.dict, dict_get_case_limit (default_dict));    dict_set_case_limit (mtf.dict, dict_get_case_limit (default_dict));
     
   do  
     {  
       lex_match ('/');  
711    
712        if (lex_match (T_BY))    lex_match ('/');
713          {    while (lex_id_match ("FILE", tokid) || lex_id_match ("TABLE", tokid))
714            if (seen & 1)      {
715              {        struct mtf_file *file = xmalloc (sizeof *file);
               msg (SE, _("The BY subcommand may be given once at most."));  
               goto error;  
             }  
           seen |= 1;  
                 
           lex_match ('=');  
           if (!parse_variables (mtf.dict, &mtf.by, &mtf.by_cnt,  
                                 PV_NO_DUPLICATE | PV_NO_SCRATCH))  
             goto error;  
         }  
       else if (token != T_ID)  
         {  
           lex_error (NULL);  
           goto error;  
         }  
       else if (lex_id_match ("FILE", tokid) || lex_id_match ("TABLE", tokid))  
         {  
           struct mtf_file *file = xmalloc (sizeof *file);  
716    
717            if (lex_match_id ("FILE"))        if (lex_match_id ("FILE"))
718              file->type = MTF_FILE;          file->type = MTF_FILE;
719            else if (lex_match_id ("TABLE"))        else if (lex_match_id ("TABLE"))
720              {          {
721                file->type = MTF_TABLE;            file->type = MTF_TABLE;
722                seen |= 4;            saw_table = true;
723              }          }
724            else        else
725              assert (0);          assert (0);
726    
727            file->by = NULL;        file->by = NULL;
728            file->handle = NULL;        file->handle = NULL;
729            file->reader = NULL;        file->reader = NULL;
730            file->dict = NULL;        file->dict = NULL;
731            file->in[0] = '\0';        file->in[0] = '\0';
732            file->first[0] = '\0';        case_nullify (&file->input);
           file->last[0] = '\0';  
           case_nullify (&file->input);  
733    
734            /* FILEs go first, then TABLEs. */        /* FILEs go first, then TABLEs. */
735            if (file->type == MTF_TABLE || first_table == NULL)        if (file->type == MTF_TABLE || first_table == NULL)
736              {          {
737                file->next = NULL;            file->next = NULL;
738                file->prev = mtf.tail;            file->prev = mtf.tail;
739                if (mtf.tail)            if (mtf.tail)
740                  mtf.tail->next = file;              mtf.tail->next = file;
741                mtf.tail = file;            mtf.tail = file;
742                if (mtf.head == NULL)            if (mtf.head == NULL)
743                  mtf.head = file;              mtf.head = file;
744                if (file->type == MTF_TABLE && first_table == NULL)            if (file->type == MTF_TABLE && first_table == NULL)
745                  first_table = file;              first_table = file;
746              }          }
747            else        else
748              {          {
749                assert (file->type == MTF_FILE);            assert (file->type == MTF_FILE);
750                file->next = first_table;            file->next = first_table;
751                file->prev = first_table->prev;            file->prev = first_table->prev;
752                if (first_table->prev)            if (first_table->prev)
753                  first_table->prev->next = file;              first_table->prev->next = file;
754                else            else
755                  mtf.head = file;              mtf.head = file;
756                first_table->prev = file;            first_table->prev = file;
757              }          }
758                        
759            lex_match ('=');        lex_match ('=');
760                        
761            if (lex_match ('*'))        if (lex_match ('*'))
762              {          {
763                file->handle = NULL;            file->handle = NULL;
764                file->reader = NULL;            file->reader = NULL;
765                                
766                if (seen & 2)            if (used_active_file)
767                  {              {
768                    msg (SE, _("The active file may not be specified more "                msg (SE, _("The active file may not be specified more "
769                               "than once."));                           "than once."));
770                    goto error;                goto error;
771                  }              }
772                seen |= 2;            used_active_file = true;
773    
774                assert (pgm_state != STATE_INPUT);            assert (pgm_state != STATE_INPUT);
775                if (pgm_state == STATE_INIT)            if (pgm_state == STATE_INIT)
776                  {              {
777                    msg (SE, _("Cannot specify the active file since no active "                msg (SE, _("Cannot specify the active file since no active "
778                               "file has been defined."));                           "file has been defined."));
779                    goto error;                goto error;
780                  }              }
781    
782                if (temporary != 0)            if (temporary != 0)
783                  {              {
784                    msg (SE,                msg (SE,
785                         _("MATCH FILES may not be used after TEMPORARY when "                     _("MATCH FILES may not be used after TEMPORARY when "
786                           "the active file is an input source.  "                       "the active file is an input source.  "
787                           "Temporary transformations will be made permanent."));                       "Temporary transformations will be made permanent."));
788                    cancel_temporary ();                cancel_temporary ();
789                  }              }
790    
791                file->dict = default_dict;            file->dict = default_dict;
792              }          }
793            else        else
794              {          {
795                file->handle = fh_parse ();            file->handle = fh_parse ();
796                if (file->handle == NULL)            if (file->handle == NULL)
797                  goto error;              goto error;
798    
799              file->reader = sfm_open_reader (file->handle, &file->dict, NULL);
800              if (file->reader == NULL)
801                goto error;
802    
803                file->reader = sfm_open_reader (file->handle, &file->dict, NULL);            case_create (&file->input, dict_get_next_value_idx (file->dict));
804                if (file->reader == NULL)          }
805    
806          while (lex_match ('/'))
807            if (lex_match_id ("RENAME"))
808              {
809                if (!rename_variables (file->dict))
810                  goto error;
811              }
812            else if (lex_match_id ("IN"))
813              {
814                lex_match ('=');
815                if (token != T_ID)
816                  {
817                    lex_error (NULL);
818                  goto error;                  goto error;
819                  }
820    
821                case_create (&file->input, dict_get_next_value_idx (file->dict));              if (file->in[0])
822              }                {
823          }                  msg (SE, _("Multiple IN subcommands for a single FILE or "
824        else if (lex_id_match ("IN", tokid)                             "TABLE."));
825                 || lex_id_match ("FIRST", tokid)                  goto error;
826                 || lex_id_match ("LAST", tokid))                }
827                strcpy (file->in, tokid);
828                lex_get ();
829              }
830    
831          mtf_merge_dictionary (mtf.dict, file);
832        }
833          
834      while (token != '.')
835        {
836          if (lex_match (T_BY))
837          {          {
838            const char *sbc;            struct variable **by;
839            char *name;            struct mtf_file *iter;
840                        
841            if (mtf.tail == NULL)            if (mtf.by_cnt)
842              {              {
843                msg (SE, _("IN, FIRST, and LAST subcommands may not occur "                msg (SE, _("BY may appear at most once."));
                          "before the first FILE or TABLE."));  
844                goto error;                goto error;
845              }              }
846                  
           if (lex_match_id ("IN"))  
             {  
               name = mtf.tail->in;  
               sbc = "IN";  
             }  
           else if (lex_match_id ("FIRST"))  
             {  
               name = mtf.tail->first;  
               sbc = "FIRST";  
             }  
           else if (lex_match_id ("LAST"))  
             {  
               name = mtf.tail->last;  
               sbc = "LAST";  
             }  
           else  
             {  
               assert (0);  
               abort ();  
             }  
   
847            lex_match ('=');            lex_match ('=');
848            if (token != T_ID)            if (!parse_variables (mtf.dict, &by, &mtf.by_cnt,
849              {                                  PV_NO_DUPLICATE | PV_NO_SCRATCH))
850                lex_error (NULL);              goto error;
               goto error;  
             }  
   
           if (*name)  
             {  
               msg (SE, _("Multiple %s subcommands for a single FILE or "  
                          "TABLE."),  
                    sbc);  
               goto error;  
             }  
           strcpy (name, tokid);  
           lex_get ();  
851    
852            if (!dict_create_var (mtf.dict, name, 0))            for (iter = mtf.head; iter != NULL; iter = iter->next)
853              {              {
854                msg (SE, _("Duplicate variable name %s while creating %s "                int i;
855                           "variable."),            
856                     name, sbc);                iter->by = xmalloc (sizeof *iter->by * mtf.by_cnt);
               goto error;  
             }  
         }  
       else if (lex_id_match ("RENAME", tokid)  
                || lex_id_match ("KEEP", tokid)  
                || lex_id_match ("DROP", tokid))  
         {  
           if (mtf.tail == NULL)  
             {  
               msg (SE, _("RENAME, KEEP, and DROP subcommands may not occur "  
                          "before the first FILE or TABLE."));  
               goto error;  
             }  
857    
858            if (!trim_dictionary (mtf.tail->dict, OP_MATCH, NULL))                for (i = 0; i < mtf.by_cnt; i++)
859              goto error;                  {
860                      iter->by[i] = dict_lookup_var (iter->dict, by[i]->name);
861                      if (iter->by[i] == NULL)
862                        {
863                          msg (SE, _("File %s lacks BY variable %s."),
864                               iter->handle ? handle_get_name (iter->handle) : "*",
865                               by[i]->name);
866                          free (by);
867                          goto error;
868                        }
869                    }
870                }
871          }          }
872          else if (lex_match_id ("FIRST"))
873            {
874              if (mtf.first[0] != '\0')
875                {
876                  msg (SE, _("FIRST may appear at most once."));
877                  goto error;
878                }
879                  
880              lex_match ('=');
881              if (!lex_force_id ())
882                goto error;
883              strcpy (mtf.first, tokid);
884              lex_get ();
885            }
886          else if (lex_match_id ("LAST"))
887            {
888              if (mtf.last[0] != '\0')
889                {
890                  msg (SE, _("LAST may appear at most once."));
891                  goto error;
892                }
893                  
894              lex_match ('=');
895              if (!lex_force_id ())
896                goto error;
897              strcpy (mtf.last, tokid);
898              lex_get ();
899            }
900        else if (lex_match_id ("MAP"))        else if (lex_match_id ("MAP"))
901          {          {
902            /* FIXME. */            /* FIXME. */
# Line 918  cmd_match_files (void) Line 906  cmd_match_files (void)
906            lex_error (NULL);            lex_error (NULL);
907            goto error;            goto error;
908          }          }
     }  
   while (token != '.');  
   
   for (iter = mtf.head; iter != NULL; iter = iter->next)  
     mtf_merge_dictionary (mtf.dict, iter);  
909    
910    if (seen & 4)        if (!lex_match ('/') && token != '.')
911      {          {
912        if (!(seen & 1))            lex_end_of_command ();
913          {            goto error;
914            msg (SE, _("The BY subcommand is required when a TABLE subcommand "          }
                      "is given."));  
           goto error;  
         }  
915      }      }
916    
917    if (seen & 1)    if (mtf.by_cnt == 0 && saw_table)
918      {      {
919        for (iter = mtf.head; iter != NULL; iter = iter->next)        msg (SE, _("BY is required when TABLE is specified."));
920          {        goto error;
           int i;  
             
           iter->by = xmalloc (sizeof *iter->by * mtf.by_cnt);  
   
           for (i = 0; i < mtf.by_cnt; i++)  
             {  
               iter->by[i] = dict_lookup_var (iter->dict, mtf.by[i]->name);  
               if (iter->by[i] == NULL)  
                 {  
                   msg (SE, _("File %s lacks BY variable %s."),  
                        iter->handle ? handle_get_name (iter->handle) : "*",  
                        mtf.by[i]->name);  
                   goto error;  
                 }  
             }  
         }  
921      }      }
922    
923    /* MATCH FILES performs an n-way merge on all its input files.    /* MATCH FILES performs an n-way merge on all its input files.
# Line 991  cmd_match_files (void) Line 955  cmd_match_files (void)
955       better algorithm would use a heap for finding minimum       better algorithm would use a heap for finding minimum
956       values. */       values. */
957    
958    if (!(seen & 2))    if (!used_active_file)
959      discard_variables ();      discard_variables ();
960    
961    mtf.sink = create_case_sink (&storage_sink_class, mtf.dict, NULL);    mtf.sink = create_case_sink (&storage_sink_class, mtf.dict, NULL);
962      if (mtf.sink->class->open != NULL)
963        mtf.sink->class->open (mtf.sink);
964    
965    mtf.seq_nums = xmalloc (dict_get_var_cnt (mtf.dict)    mtf.seq_nums = xmalloc (dict_get_var_cnt (mtf.dict) * sizeof *mtf.seq_nums);
                           * sizeof *mtf.seq_nums);  
966    memset (mtf.seq_nums, 0,    memset (mtf.seq_nums, 0,
967            dict_get_var_cnt (mtf.dict) * sizeof *mtf.seq_nums);            dict_get_var_cnt (mtf.dict) * sizeof *mtf.seq_nums);
968    mtf.mtf_case = xmalloc (dict_get_case_size (mtf.dict));    case_create (&mtf.mtf_case, dict_get_next_value_idx (mtf.dict));
969    
970    mtf_read_nonactive_records (NULL);    mtf_read_nonactive_records (&mtf);
971    if (seen & 2)    if (used_active_file)
972      procedure (mtf_processing, NULL);      procedure (mtf_processing, &mtf);
973    mtf_processing_finish (NULL);    mtf_processing_finish (&mtf);
974    
975    dict_destroy (default_dict);    dict_destroy (default_dict);
976    default_dict = mtf.dict;    default_dict = mtf.dict;
# Line 1088  mtf_free (struct mtf_proc *mtf) Line 1053  mtf_free (struct mtf_proc *mtf)
1053        mtf_free_file (iter);        mtf_free_file (iter);
1054      }      }
1055        
   free (mtf->by);  
1056    if (mtf->dict)    if (mtf->dict)
1057      dict_destroy (mtf->dict);      dict_destroy (mtf->dict);
1058      case_destroy (&mtf->mtf_case);
1059    free (mtf->seq_nums);    free (mtf->seq_nums);
1060  }  }
1061    
# Line 1117  mtf_delete_file_in_place (struct mtf_pro Line 1082  mtf_delete_file_in_place (struct mtf_pro
1082      for (i = 0; i < dict_get_var_cnt (f->dict); i++)      for (i = 0; i < dict_get_var_cnt (f->dict); i++)
1083        {        {
1084          struct variable *v = dict_get_var (f->dict, i);          struct variable *v = dict_get_var (f->dict, i);
1085          union value *out = case_data_rw (mtf->mtf_case, get_master (v)->fv);          union value *out = case_data_rw (&mtf->mtf_case, get_master (v)->fv);
1086                        
1087          if (v->type == NUMERIC)          if (v->type == NUMERIC)
1088            out->f = SYSMIS;            out->f = SYSMIS;
# Line 1131  mtf_delete_file_in_place (struct mtf_pro Line 1096  mtf_delete_file_in_place (struct mtf_pro
1096    
1097  /* Read a record from every input file except the active file. */  /* Read a record from every input file except the active file. */
1098  static void  static void
1099  mtf_read_nonactive_records (void *mtf_ UNUSED)  mtf_read_nonactive_records (void *mtf_)
1100  {  {
1101    struct mtf_proc *mtf = mtf_;    struct mtf_proc *mtf = mtf_;
1102    struct mtf_file *iter;    struct mtf_file *iter;
# Line 1197  mtf_compare_BY_values (struct mtf_proc * Line 1162  mtf_compare_BY_values (struct mtf_proc *
1162    
1163  /* Perform one iteration of steps 3...7 above. */  /* Perform one iteration of steps 3...7 above. */
1164  static int  static int
1165  mtf_processing (struct ccase *c, void *mtf_ UNUSED)  mtf_processing (struct ccase *c, void *mtf_)
1166  {  {
1167    struct mtf_proc *mtf = mtf_;    struct mtf_proc *mtf = mtf_;
1168    struct mtf_file *min_head, *min_tail; /* Files with minimum BY values. */    struct mtf_file *min_head, *min_tail; /* Files with minimum BY values. */
# Line 1208  mtf_processing (struct ccase *c, void *m Line 1173  mtf_processing (struct ccase *c, void *m
1173      {      {
1174        /* If the active file doesn't have the minimum BY values, don't        /* If the active file doesn't have the minimum BY values, don't
1175           return because that would cause a record to be skipped. */           return because that would cause a record to be skipped. */
1176        int advance = 1;        bool advance = true;
1177    
1178        if (mtf->head->type == MTF_TABLE)        if (mtf->head->type == MTF_TABLE)
1179          return 0;          return 0;
# Line 1265  mtf_processing (struct ccase *c, void *m Line 1230  mtf_processing (struct ccase *c, void *m
1230            assert (iter->type == MTF_TABLE);            assert (iter->type == MTF_TABLE);
1231                
1232            if (iter->handle == NULL)            if (iter->handle == NULL)
1233              advance = 0;              advance = false;
1234    
1235          again:          again:
1236            switch (mtf_compare_BY_values (mtf, min_head, iter, c))            switch (mtf_compare_BY_values (mtf, min_head, iter, c))
# Line 1309  mtf_processing (struct ccase *c, void *m Line 1274  mtf_processing (struct ccase *c, void *m
1274            for (i = 0; i < dict_get_var_cnt (iter->dict); i++)            for (i = 0; i < dict_get_var_cnt (iter->dict); i++)
1275              {              {
1276                struct variable *v = dict_get_var (iter->dict, i);                struct variable *v = dict_get_var (iter->dict, i);
1277                struct ccase *record;                struct variable *mv = get_master (v);
               union value *out;  
1278                        
1279                if (mtf->seq_nums[get_master (v)->index] == mtf->seq_num)                if (mtf->seq_nums[mv->index] != mtf->seq_num)
1280                  continue;                  {
1281                mtf->seq_nums[get_master (v)->index] = mtf->seq_num;                    struct ccase *record
1282                        = case_is_null (&iter->input) ? c : &iter->input;
1283                record = case_is_null (&iter->input) ? c : &iter->input;                    union value *out = case_data_rw (&mtf->mtf_case, mv->fv);
1284    
1285                assert (v->type == NUMERIC || v->type == ALPHA);                    mtf->seq_nums[mv->index] = mtf->seq_num;
1286                out = case_data_rw (mtf->mtf_case, get_master (v)->fv);                    if (v->type == NUMERIC)
1287                if (v->type == NUMERIC)                      out->f = case_num (record, v->fv);
1288                  out->f = case_num (record, v->fv);                    else
1289                else                      memcpy (out->s, case_str (record, v->fv), v->width);
1290                  memcpy (out->s, case_str (record, v->fv), v->width);                  }
1291              }              }
1292          }          }
1293    
1294        /* Store missing values to all the records we're not using. */        /* Store missing values to all the records we're not using. */
# Line 1337  mtf_processing (struct ccase *c, void *m Line 1301  mtf_processing (struct ccase *c, void *m
1301            for (i = 0; i < dict_get_var_cnt (iter->dict); i++)            for (i = 0; i < dict_get_var_cnt (iter->dict); i++)
1302              {              {
1303                struct variable *v = dict_get_var (iter->dict, i);                struct variable *v = dict_get_var (iter->dict, i);
1304                union value *out;                struct variable *mv = get_master (v);
1305                        
1306                if (mtf->seq_nums[get_master (v)->index] == mtf->seq_num)                if (mtf->seq_nums[mv->index] != mtf->seq_num)
1307                  continue;                  {
1308                mtf->seq_nums[get_master (v)->index] = mtf->seq_num;                    union value *out = case_data_rw (&mtf->mtf_case, mv->fv);
1309                      mtf->seq_nums[mv->index] = mtf->seq_num;
1310                out = case_data_rw (mtf->mtf_case, get_master (v)->fv);  
1311                if (v->type == NUMERIC)                    if (v->type == NUMERIC)
1312                  out->f = SYSMIS;                      out->f = SYSMIS;
1313                else                    else
1314                  memset (out->s, ' ', v->width);                      memset (out->s, ' ', v->width);
1315              }                  }
1316                }
1317    
1318            if (iter->handle == NULL)            if (iter->handle == NULL)
1319              advance = 0;              advance = false;
1320          }          }
1321    
1322        /* 6. Write the output record. */        /* 6. Write the output record. */
1323        mtf->sink->class->write (mtf->sink, mtf->mtf_case);        mtf->sink->class->write (mtf->sink, &mtf->mtf_case);
1324    
1325        /* 7. Read another record from each input file FILE and TABLE        /* 7. Read another record from each input file FILE and TABLE
1326           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
# Line 1387  mtf_merge_dictionary (struct dictionary Line 1352  mtf_merge_dictionary (struct dictionary
1352  {  {
1353    struct dictionary *d = f->dict;    struct dictionary *d = f->dict;
1354    const char *d_docs, *m_docs;    const char *d_docs, *m_docs;
1355      int i;
1356    
1357    if (dict_get_label (m) == NULL)    if (dict_get_label (m) == NULL)
1358      dict_set_label (m, dict_get_label (d));      dict_set_label (m, dict_get_label (d));
# Line 1413  mtf_merge_dictionary (struct dictionary Line 1379  mtf_merge_dictionary (struct dictionary
1379        
1380    dict_compact_values (d);    dict_compact_values (d);
1381    
1382    {    for (i = 0; i < dict_get_var_cnt (d); i++)
1383      int i;      {
1384          struct variable *dv = dict_get_var (d, i);
1385          struct variable *mv = dict_lookup_var (m, dv->name);
1386    
1387      for (i = 0; i < dict_get_var_cnt (d); i++)        if (mv != NULL)
1388        {          {
1389          struct variable *dv = dict_get_var (d, i);            if (mv->width != dv->width)
1390          struct variable *mv = dict_lookup_var (m, dv->name);              {
1391                  msg (SE, _("Variable %s in file %s (%s) has different "
1392                             "type or width from the same variable in "
1393                             "earlier file (%s)."),
1394                       dv->name, handle_get_name (f->handle),
1395                       var_type_description (dv), var_type_description (mv));
1396                  return 0;
1397                }
1398            
1399              if (dv->width == mv->width)
1400                {
1401                  if (val_labs_count (dv->val_labs)
1402                      && !val_labs_count (mv->val_labs))
1403                    mv->val_labs = val_labs_copy (dv->val_labs);
1404                  if (dv->miss_type != MISSING_NONE
1405                      && mv->miss_type == MISSING_NONE)
1406                    copy_missing_values (mv, dv);
1407                }
1408    
1409          assert (dv->type == ALPHA || dv->width == 0);            if (dv->label && !mv->label)
1410          assert (!mv || mv->type == ALPHA || mv->width == 0);              mv->label = xstrdup (dv->label);
1411          if (mv && dv->width == mv->width)          }
1412            {        else
1413              if (val_labs_count (dv->val_labs)          {
1414                  && !val_labs_count (mv->val_labs))            mv = dict_clone_var (m, dv, dv->name, dv->longname);
1415                mv->val_labs = val_labs_copy (dv->val_labs);            assert (mv != NULL);
1416              if (dv->miss_type != MISSING_NONE          }
1417                  && mv->miss_type == MISSING_NONE)          
1418                copy_missing_values (mv, dv);        set_master (dv, mv);
1419            }      }
         if (mv && dv->label && !mv->label)  
           mv->label = xstrdup (dv->label);  
         if (!mv)  
           {  
             mv = dict_clone_var (m, dv, dv->name, dv->longname);  
             assert (mv != NULL);  
           }  
         else if (mv->width != dv->width)  
           {  
             msg (SE, _("Variable %s in file %s (%s) has different "  
                        "type or width from the same variable in "  
                        "earlier file (%s)."),  
                  dv->name, handle_get_name (f->handle),  
                  var_type_description (dv), var_type_description (mv));  
             return 0;  
           }  
         set_master (dv, mv);  
       }  
   }  
1420    
1421    return 1;    return 1;
1422  }  }

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

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