1 /*
2  				fitskey.c
3 
4 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 *
6 *	Part of:	The LDAC Tools
7 *
8 *	Author:		E.BERTIN, DeNIS/LDAC
9 *
10 *	Contents:	Functions related to the management of keys.
11 *
12 *	Last modify:	15/08/2003
13 *
14 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15 */
16 
17 #ifdef HAVE_CONFIG_H
18 #include	"config.h"
19 #endif
20 
21 #include	<stdio.h>
22 #include	<stdlib.h>
23 #include	<string.h>
24 
25 #include	"fitscat_defs.h"
26 #include	"fitscat.h"
27 
28 /****** add_key ****************************************************************
29 PROTO	int add_key(keystruct *key, tabstruct *tab, int pos)
30 PURPOSE	Copy a key from one table to another.
31 INPUT	Pointer to the key,
32         Pointer to the table,
33 	Pointer to the destination table,
34 	Position (1= first, <=0 = at the end)
35 OUTPUT	RETURN_OK if everything went as expected, and RETURN_ERROR otherwise.
36 NOTES	A preexisting key in the destination table yields a RETURN_ERROR.
37 AUTHOR	E. Bertin (IAP & Leiden observatory)
38 VERSION	26/03/96
39  ***/
add_key(keystruct * key,tabstruct * tab,int pos)40 int	add_key(keystruct *key, tabstruct *tab, int pos)
41 
42   {
43 
44 /*Check if a similar key doesn't already exist in the dest. cat */
45   if (name_to_key(tab, key->name))
46     return RETURN_ERROR;
47 
48 /*Update links (portion of code similar to that of copy_key below) */
49   if ((key->nextkey = pos_to_key(tab, pos)))
50     {
51     (key->prevkey = key->nextkey->prevkey)->nextkey = key;
52     key->nextkey->prevkey = key;
53 /*--the first place has a special meaning*/
54     if (pos==1)
55       tab->key = key;
56     }
57   else
58 /*There was no no key before*/
59     tab->key = key->nextkey = key->prevkey = key;
60 
61   tab->nkey++;
62 
63   return RETURN_OK;
64   }
65 
66 
67 /****** blank_keys *************************************************************
68 PROTO	int blank_keys(tabstruct *tab)
69 PURPOSE	Put the array pointers from all keys in a table to NULL.
70 INPUT	Pointer to the table.
71 OUTPUT	RETURN_OK if keys were found, and RETURN_ERROR otherwise.
72 Notes:	-.
73 AUTHOR	E. Bertin (IAP & Leiden observatory)
74 VERSION	25/04/97
75  ***/
blank_keys(tabstruct * tab)76 int	blank_keys(tabstruct *tab)
77 
78   {
79    keystruct	*key;
80    int		k;
81 
82   if (!(key = tab->key))
83     return RETURN_ERROR;
84 
85   for (k=tab->nkey; k--;)
86     {
87     key->ptr = NULL;
88     key = key->nextkey;
89     }
90 
91   return RETURN_OK;
92   }
93 
94 
95 /****** copy_key ***************************************************************
96 PROTO	int copy_key(tabstruct *tabin, char *keyname, tabstruct *tabout, int pos)
97 PURPOSE	Copy a key from one table to another.
98 INPUT	Pointer to the original table,
99         Name of the key,
100 	Pointer to the destination table,
101 	Position (1= first, <=0 = at the end)
102 OUTPUT	RETURN_OK if everything went as expected, and RETURN_ERROR otherwise.
103 NOTES	A preexisting key in the destination table yields a RETURN_ERROR,
104 	the ptr member is NOT COPIED.
105 AUTHOR	E. Bertin (IAP & Leiden observatory)
106 VERSION	19/08/96
107  ***/
copy_key(tabstruct * tabin,char * keyname,tabstruct * tabout,int pos)108 int	copy_key(tabstruct *tabin, char *keyname, tabstruct *tabout, int pos)
109 
110   {
111    keystruct	*keyin, *keyout;
112 
113 /*Convert the key name to a pointer*/
114   if (!(keyin = name_to_key(tabin, keyname)))
115     return RETURN_ERROR;
116 
117 /*Check if a similar key doesn't already exist in the dest. cat */
118   if (name_to_key(tabout, keyname))
119     return RETURN_ERROR;
120 
121   tabout->nkey++;
122 
123 /*First, allocate memory and copy data */
124   QCALLOC(keyout, keystruct, 1);
125   *keyout = *keyin;
126   keyout->ptr = NULL;
127   if (keyin->naxis)
128     QMEMCPY(keyin->naxisn, keyout->naxisn, int, keyin->naxis);
129 
130 /*Then, update the links */
131   if ((keyout->nextkey = pos_to_key(tabout, pos)))
132     {
133     (keyout->prevkey = keyout->nextkey->prevkey)->nextkey = keyout;
134     keyout->nextkey->prevkey = keyout;
135 /*--the first place has a special meaning*/
136     if (pos==1)
137       tabout->key = keyout;
138     }
139   else
140 /*There was no no key before*/
141     tabout->key = keyout->nextkey = keyout->prevkey = keyout;
142 
143   return RETURN_OK;
144   }
145 
146 
147 /****** free_key ***************************************************************
148 PROTO	void free_key(keystruct *key)
149 PURPOSE	Free memory associated to a key ptr.
150 INPUT	Pointer to the key.
151 OUTPUT	-.
152 NOTES	-.
153 AUTHOR	E. Bertin (IAP & Leiden observatory)
154 VERSION	19/08/96
155  ***/
free_key(keystruct * key)156 void	free_key(keystruct *key)
157 
158   {
159   free(key->naxisn);
160   free(key->ptr);
161   free(key);
162 
163   return;
164   }
165 
166 
167 /****** new_key ****************************************************************
168 PROTO	keystruct *new_key(char *keyname)
169 PURPOSE	Create a new key.
170 INPUT	Name of the key.
171 OUTPUT	A pointer to the new keystruct.
172 NOTES	This function is only provided as a counterpart to new_tab() and
173 	new_cat(): in order to be usable, other key parameters MUST be
174 	handled by the user.
175 AUTHOR	E. Bertin (IAP & Leiden observatory)
176 VERSION	26/03/96
177  ***/
new_key(char * keyname)178 keystruct	*new_key(char *keyname)
179 
180   {
181    keystruct	*key;
182 
183   QCALLOC(key, keystruct, 1);
184   strcpy(key->name, keyname);
185 
186   return key;
187   }
188 
189 
190 /****** read_key ***************************************************************
191 PROTO	keystruct *read_key(tabstruct *tab, char *keyname)
192 PURPOSE	Read one simple column from a FITS binary table.
193 INPUT	pointer to the table,
194 	name of the key,
195 OUTPUT	A pointer to the relevant key, or NULL if the desired key is not
196 	found in the table.
197 NOTES	If key->ptr is not NULL, the function doesn't do anything.
198 AUTHOR	E. Bertin (IAP & Leiden observatory)
199         E.R. Deul (Sterrewacht Leiden) (Added open_cat error checking)
200 VERSION	18/02/2000
201  ***/
read_key(tabstruct * tab,char * keyname)202 keystruct *read_key(tabstruct *tab, char *keyname)
203 
204   {
205    catstruct	*cat;
206    keystruct	*key;
207    char		*buf, *ptr, *fptr,*fptr0;
208    int		i,j, larray,narray,size;
209    int		esize;
210 
211   if (!(key = name_to_key(tab, keyname)))
212     return NULL;
213 
214 /*If ptr is not NULL, there is already something loaded there: let's free mem */
215   QFREE(key->ptr);
216 
217 /*!! It is not necessarily the original table */
218   tab = key->tab;
219   cat = tab->cat;
220 
221 /*We are expecting a 2D binary-table, and nothing else*/
222   if ((tab->naxis != 2)
223 	|| (tab->bitpix!=8)
224 	|| (tab->tfields == 0)
225 	|| strncmp(tab->xtension, "BINTABLE", 8))
226     error(EXIT_FAILURE, "*Error*: No binary table in ", cat->filename);
227 
228 /*Size and number of lines in the binary table*/
229   larray = tab->naxisn[0];
230   narray = tab->naxisn[1];
231 
232 /*Positioning to the first element*/
233   if (open_cat(cat, READ_ONLY) == RETURN_ERROR)
234      error(EXIT_FAILURE, "*Error*: opening catalog ",cat->filename);
235   QFSEEK(cat->file, tab->bodypos , SEEK_SET, cat->filename);
236 
237 /*allocate memory for the buffer where we put one line of data*/
238   QMALLOC(buf, char, larray);
239 
240   fptr0 = buf+key->pos;
241   size = key->nbytes;
242 
243 /*allocate memory for the array*/
244   QMALLOC(ptr, char, size*narray);
245   key->ptr = ptr;
246 
247 /*read line by line*/
248   for (i=narray; i--;)
249     {
250     QFREAD(buf, larray, cat->file, cat->filename);
251     fptr = fptr0;
252     if (bswapflag)
253       {
254       esize = t_size[key->ttype];
255       swapbytes(fptr0, esize, size/esize);
256       }
257     for (j = size; j--;)
258       *(ptr++) = *(fptr++);
259     }
260 
261   free(buf);
262   return key;
263   }
264 
265 
266 /****** read_keys **************************************************************
267 PURPOSE	Read several columns from a FITS binary table.
268 INPUT	pointer to the table,
269 	pointer to an array of char *,
270 	pointer to an array of keystruct * (memory must have been allocated),
271 	number of keys to read,
272 	an optional mask pointer.
273 OUTPUT	-.
274 NOTES	The array of pointers pointed by keys is filled with pointers
275 	to the relevant keys (a NULL means NO key with such name was found).
276 	A NULL keys pointer can be given (no info returned of course).
277 	A NULL keynames pointer means read ALL keys belonging to the table.
278 	A NULL mask pointer means NO selection for reading.
279 AUTHOR	E. Bertin (IAP & Leiden observatory)
280 VERSION	18/02/2000
281  ***/
read_keys(tabstruct * tab,char ** keynames,keystruct ** keys,int nkeys,BYTE * mask)282 void	read_keys(tabstruct *tab, char **keynames, keystruct **keys, int nkeys,
283 		BYTE *mask)
284 
285   {
286    catstruct	*cat;
287    keystruct	*key, **ckeys;
288    BYTE		*mask2;
289    char		*buf, *ptr, *fptr;
290    int		i,j,k,n, larray,narray, nb, kflag = 0, size;
291    int		esize;
292 
293 /*!! It is not necessarily the original table */
294   tab = tab->key->tab;
295   cat = tab->cat;
296 
297 /*We are expecting a 2D binary-table, and nothing else*/
298   if ((tab->naxis != 2)
299 	|| (tab->bitpix!=8)
300 	|| (tab->tfields == 0)
301 	|| strncmp(tab->xtension, "BINTABLE", 8))
302     error(EXIT_FAILURE, "*Error*: No binary table in ", cat->filename);
303 
304 /*Size and number of lines in the binary table*/
305   larray = tab->naxisn[0];
306   narray = tab->naxisn[1];
307 
308   nb = 0;
309   if ((mask2 = mask))
310     {
311     for (i=narray; i--;)
312       if (*(mask2++))
313         nb++;
314     }
315 
316   if (!keynames)
317     nkeys = tab->nkey;
318 
319 /*Allocate memory to store the list of keys to be read */
320   if (!keys)
321     {
322     QMALLOC(keys, keystruct *, nkeys);
323     kflag = 1;
324     }
325 
326 /*allocate memory for the arrays*/
327   ckeys = keys;
328   if (keynames)
329     for (i=nkeys; i--;)
330       {
331       if ((key = name_to_key(tab, *(keynames++))))
332         {
333         QFREE(key->ptr);
334         if (nb)
335           key->nobj = nb;
336         else
337           nb=key->nobj;
338         QMALLOC(key->ptr, char, key->nbytes*nb);
339         *(ckeys++) = key;
340         }
341       else
342         *(ckeys++) = NULL;
343       }
344   else
345     {
346     key = tab->key;
347     for (i=nkeys; i--;)
348       {
349       QFREE(key->ptr);
350       if (nb)
351         key->nobj = nb;
352       else
353         nb=key->nobj;
354       QMALLOC(key->ptr, char, key->nbytes*nb);
355       *(ckeys++) = key;
356       key = key->nextkey;
357       }
358     }
359 
360 /*allocate memory for the buffer where we put one line of data*/
361   QMALLOC(buf, char, larray);
362 
363 /*Positioning to the first element*/
364   open_cat(cat, READ_ONLY);
365   QFSEEK(cat->file, tab->bodypos , SEEK_SET, cat->filename);
366 
367 /*read line by line*/
368   n = 0;
369   mask2 = mask;
370   for (i=narray; i--;)
371     {
372     QFREAD(buf, larray, cat->file, cat->filename);
373     if (!mask || *(mask2++))
374       {
375       ckeys = keys;
376       for (j=nkeys; j--;)
377         if ((key = *(ckeys++)))
378           {
379           fptr = buf+key->pos;
380           ptr = (char *)key->ptr+n*(size=key->nbytes);
381           if (bswapflag)
382             {
383             esize = t_size[key->ttype];
384             swapbytes(fptr, esize, size/esize);
385             }
386           for (k = size; k--;)
387             *(ptr++) = *(fptr++);
388           }
389       n++;
390       }
391     }
392 
393   free(buf);
394   if (kflag)
395     free(keys);
396 
397   return;
398   }
399 
400 /****** remove_key *************************************************************
401 PROTO	int remove_key(tabstruct *tab, char *keyname)
402 PURPOSE	Remove a key from a table.
403 INPUT	Pointer to the table,
404 	Name of the key.
405 OUTPUT	RETURN_OK if everything went as expected, and RETURN_ERROR otherwise.
406 NOTES	If keyname = "", the last key from the list is removed.
407 AUTHOR	E. Bertin (IAP & Leiden observatory)
408 VERSION	15/01/97
409  ***/
remove_key(tabstruct * tab,char * keyname)410 int	remove_key(tabstruct *tab, char *keyname)
411 
412   {
413    keystruct	*key, *prevkey, *nextkey;
414 
415   if (!keyname || !tab->nkey || !tab->key)
416     return RETURN_ERROR;
417 
418   if (keyname[0])
419     {
420 /*--Convert the key name to a pointer*/
421     if (!(key = name_to_key(tab, keyname)))
422       return RETURN_ERROR;
423     }
424   else
425     key = tab->key->prevkey;
426 
427   prevkey = key->prevkey;
428 /*Free memory*/
429   nextkey = key->nextkey;
430   if (tab->key==key)
431     tab->key = nextkey;
432   free_key(key);
433 
434   if (--tab->nkey)
435     {
436 /*--update the links of neighbours*/
437     nextkey->prevkey = prevkey;
438     prevkey->nextkey = nextkey;
439     }
440   else
441     tab->key = NULL;
442 
443   return RETURN_OK;
444   }
445 
446 
447 /****** remove_keys ************************************************************
448 PROTO	int remove_keys(tabstruct *tab)
449 PURPOSE	Remove all keys from a table.
450 INPUT	Pointer to the table.
451 OUTPUT	RETURN_OK if keys were found, and RETURN_ERROR otherwise.
452 NOTES	-.
453 AUTHOR	E. Bertin (IAP & Leiden observatory)
454 VERSION	13/03/99
455  ***/
remove_keys(tabstruct * tab)456 int	remove_keys(tabstruct *tab)
457 
458   {
459    int	k;
460 
461   if (!tab->key)
462     return RETURN_ERROR;
463 
464   for (k=tab->nkey; k--;)
465     remove_key(tab, "");
466 
467   return RETURN_OK;
468   }
469 
470 
471 /****** name_to_key ************************************************************
472 PROTO	keystruct *name_to_key(tabstruct *tab, char *keyname)
473 PURPOSE	Name search of a key in a table.
474 INPUT	Pointer to the table,
475 	Key name.
476 OUTPUT	The key pointer if the name was matched, and NULL otherwise.
477 NOTES	-.
478 AUTHOR	E. Bertin (IAP & Leiden observatory)
479 VERSION	25/04/97
480  ***/
name_to_key(tabstruct * tab,char * keyname)481 keystruct	*name_to_key(tabstruct *tab, char *keyname)
482 
483   {
484    keystruct	*key;
485    int		i;
486 
487   if (!(key=tab->key))
488    return NULL;
489 
490   for (i=tab->nkey; strcmp(keyname, key->name) && i--; key=key->nextkey);
491 
492   return i<0? NULL:key;
493   }
494 
495 /****** keys_list **************************************************************
496 PROTO	char **keys_list(catstruct *tab, int *n)
497 PURPOSE	List all keys in a table.
498 INPUT	Pointer to the table,
499 	Pointer to the number of names in that list.
500 OUTPUT	A list of all key names.
501 NOTES	-.
502 AUTHOR	E.R. Deul (Leiden observatory)
503 VERSION	??/??/96
504  ***/
keys_list(tabstruct * tab,int * n)505 char **keys_list(tabstruct *tab, int *n)
506 
507   {
508    keystruct	*key;
509    int		i;
510    char 	**names;
511 
512   QCALLOC(names, char *, tab->nkey);
513   key = tab->key;
514   for (i=0; i<tab->nkey; i++) {
515     QCALLOC(names[i], char, MAXCHARS);
516     strcpy(names[i],key->name);
517     key = key->nextkey;
518   }
519   *n = tab->nkey;
520   return names;
521   }
522 
523 
524 /****** pos_to_key *************************************************************
525 PROTO	keystruct *pos_to_key(tabstruct *tab, int pos)
526 PURPOSE	Position search of a key in a table.
527 INPUT	Pointer to the table,
528 	Position of the key.
529 OUTPUT	The key pointer if a key exists at the given position, and the
530 	pointer to the first key otherwise.
531 NOTES	pos = 0 or 1 means the first key.
532 AUTHOR	E. Bertin (IAP & Leiden observatory)
533 VERSION	20/03/96
534  ***/
pos_to_key(tabstruct * tab,int pos)535 keystruct	*pos_to_key(tabstruct *tab, int pos)
536 
537   {
538    keystruct	*key;
539    int		i;
540 
541   if (!(key=tab->key))
542    return NULL;
543 
544   if ((pos--)==1)
545     return tab->key;
546 
547   for (i=0; i!=pos && i<tab->nkey; i++, key=key->nextkey);
548 
549   return i<tab->nkey?key:tab->key;
550   }
551 
552 
553 /****** show_keys **************************************************************
554 PROTO	void show_keys(tabstruct *tab, char **keynames,
555 			keystruct **keys, int nkeys,
556 			BYTE *mask, FILE *stream,
557 			int strflag, int banflag, int leadflag,
558                         output_type o_type)
559 PURPOSE	Convert a binary table to an ASCII file.
560 INPUT	pointer to the table,
561 	pointer to an array of char *,
562 	pointer to an array of keystruct * (memory must have been allocated),
563 	number of keys to read,
564 	an optional mask pointer,
565 	a stream,
566 	a flag to indicate if arrays should be displayed (0=NO),
567 	a flag to indicate if a banner with keynames should be added (0=NO).
568 	a flag to indicate if a leading row number should be added (0=NO).
569         the output type
570 OUTPUT	-.
571 NOTES	This is approximately the same code as for read_keys.
572 	The array of pointers pointed by keys is filled with pointers
573 	to the relevant keys (a NULL means NO key with such name was found).
574 	A NULL keys pointer can be given (no info returned of course).
575 	A NULL keynames pointer means read ALL keys belonging to the table.
576 	A NULL mask pointer means NO selection for reading.
577 AUTHOR	E. Bertin (IAP & Leiden observatory)
578 VERSION	15/08/2003
579  ***/
show_keys(tabstruct * tab,char ** keynames,keystruct ** keys,int nkeys,BYTE * mask,FILE * stream,int strflag,int banflag,int leadflag,output_type o_type)580 void	show_keys(tabstruct *tab, char **keynames, keystruct **keys, int nkeys,
581 		BYTE *mask, FILE *stream,
582 		int strflag, int banflag, int leadflag, output_type o_type)
583 
584   {
585    catstruct	*cat;
586    keystruct	*key, **ckeys;
587    BYTE		*mask2;
588    char		*buf, *rfield, *ptr;
589    int		i,j,k,n,c, larray,narray, nb, kflag, maxnbytes, nelem,
590 		esize, *key_col;
591    typedef struct structreq_keyname
592       {
593       char    oldname[80];         /* Name of the original pipeline key */
594       char    newname[80];         /* Name of the skycat required key   */
595       } req_keynamestruct;
596 
597    req_keynamestruct objectmap[] =
598       {
599         {"SeqNr", "id"},
600         {"Ra", "ra"},
601         {"Dec", "dec"},
602         {"MAG_ISO", "Mag"},
603         {"", ""}
604       };
605    req_keynamestruct *map;
606 
607    char    skycathead[] = "QueryResult\n\n"
608         "# Config entry for original catalog server:\n"
609         "serv_type: catalog\n"
610         "long_name: ldactoskycat catalog\n"
611         "short_name: ldactoaskycat\n"
612         "symbol: id circle %4.1f\n"
613         "search_cols: mag {Brightest (min)} {Faintest (max)}\n"
614         "# End config entry\n\n";
615 
616    char    *t, skycattail[] = "";
617 
618 
619 /* !! It is not necessarily the original table */
620   if (tab->key)
621     tab = tab->key->tab;
622   cat = tab->cat;
623 
624 /* We are expecting a 2D binary-table, and nothing else */
625   if ((tab->naxis != 2)
626 	|| (tab->bitpix!=8)
627 	|| (tab->tfields == 0)
628 	|| strncmp(tab->xtension, "BINTABLE", 8))
629     error(EXIT_FAILURE, "*Error*: Not a binary table in ", cat->filename);
630 
631 /* Size and number of lines in the binary table */
632   larray = tab->naxisn[0];
633   narray = tab->naxisn[1];
634 
635   nb = 0;
636   if ((mask2 = mask))
637     {
638     for (i=narray; i--;)
639       if (*(mask2++))
640         nb++;
641     }
642 
643   if (!keynames)
644     nkeys = tab->nkey;
645   QCALLOC(key_col, int, nkeys);
646   if (keynames) {
647     for (i=0;i<nkeys;i++)
648        if ((t=strchr(keynames[i], ')'))!=NULL) {
649           *t='\0';
650           t=strchr(keynames[i], '(');
651           *t='\0';
652           key_col[i] = atoi(++t);
653        }
654   }
655 /* Allocate memory to store the list of keys to be read */
656   kflag = 0;
657   if (!keys)
658     {
659     QMALLOC(keys, keystruct *, nkeys);
660     kflag = 1;
661     }
662 
663   n=1;
664   switch (o_type) {
665   case SHOW_ASCII:
666               if (leadflag)
667                  fprintf(stream, "# %3d %-15.15s %.47s\n", n++,
668                                  "(row_pos)", "running row");
669               break;
670   case SHOW_SKYCAT:
671               fprintf(stream, skycathead, 6.0);
672               break;
673   }
674 
675 /* Allocate memory for the arrays */
676   maxnbytes = 0;
677   ckeys = keys;
678   if (keynames)
679     for (i=nkeys; i--;)
680       {
681       if ((key = name_to_key(tab, *(keynames++))))
682         {
683         for (map=objectmap; map->oldname[0]&&o_type == SHOW_SKYCAT; map++) {
684             if (strcmp(key->name, map->oldname) == 0) {
685 	      strcpy(key->name,  map->newname);
686            }
687         }
688         *(ckeys++) = key;
689         switch (o_type) {
690         case SHOW_ASCII:
691               if (banflag)
692                 {
693                 if (*key->unit)
694                   fprintf(stream, "# %3d %-19.19s %-47.47s [%s]\n",
695                       n, key->name,key->comment, key->unit);
696                 else
697                   fprintf(stream, "# %3d %-19.19s %.47s\n",
698                       n, key->name,key->comment);
699                 n += key->nbytes/t_size[key->ttype];
700               }
701               break;
702         case SHOW_SKYCAT:
703               if (key->nbytes/t_size[key->ttype] > 1)
704                  for (j=0;j<key->nbytes/t_size[key->ttype];j++)
705                     fprintf(stream, "%s(%d)\t", key->name,j+1);
706               else
707                     fprintf(stream, "%s\t", key->name);
708               break;
709         }
710         if (key->nbytes>maxnbytes)
711           maxnbytes = key->nbytes;
712         }
713       else
714         *(ckeys++) = NULL;
715       }
716   else
717     {
718     key = tab->key;
719     for (i=nkeys; i--; key = key->nextkey)
720       if (strflag || key->naxis==0)
721         {
722         for (map=objectmap; map->oldname[0]&&o_type == SHOW_SKYCAT; map++) {
723            if (strcmp(key->name, map->oldname) == 0) {
724               strcpy(key->name, map->newname);
725            }
726         }
727         *(ckeys++) = key;
728         switch (o_type) {
729         case SHOW_ASCII:
730               if (banflag)
731                 {
732                 if (*key->unit)
733                   fprintf(stream, "# %3d %-19.19s %-47.47s [%s]\n",
734                       n, key->name,key->comment, key->unit);
735                 else
736                   fprintf(stream, "# %3d %-19.19s %.47s\n",
737                       n, key->name,key->comment);
738                 n += key->nbytes/t_size[key->ttype];
739                 }
740               break;
741          case SHOW_SKYCAT:
742               if (key->nbytes/t_size[key->ttype] > 1)
743                  for (j=0;j<key->nbytes/t_size[key->ttype];j++)
744                     fprintf(stream, "%s(%d)\t", key->name,j+1);
745               else
746                     fprintf(stream, "%s\t", key->name);
747               break;
748          }
749            if (key->nbytes>maxnbytes)
750              maxnbytes = key->nbytes;
751            }
752       else
753         {
754         switch (o_type) {
755         case SHOW_ASCII:
756               if (*key->unit)
757                 fprintf(stream, "#     %-19.19s %-47.47s [%s]\n",
758 	            	key->name,key->comment, key->unit);
759               else
760                 fprintf(stream, "#     %-19.19s %.47s\n",
761             		key->name,key->comment);
762               break;
763         case SHOW_SKYCAT:
764               break;
765         }
766         *(ckeys++) = NULL;
767         }
768     }
769    if (o_type == SHOW_SKYCAT)
770       fprintf(stream, "\n------------------\n");
771 
772 /* Allocate memory for the buffer where we put one line of data */
773   QMALLOC(buf, char, larray);
774 
775 /* Allocate memory for the buffer where we put one element */
776   QMALLOC(rfield, char, maxnbytes);
777 
778 /* Positioning to the first element */
779   open_cat(cat, READ_ONLY);
780   QFSEEK(cat->file, tab->bodypos , SEEK_SET, cat->filename);
781 
782 /*read line by line*/
783   n = 0;
784   mask2 = mask;
785   for (i=narray; i--;)
786     {
787     QFREAD(buf, larray, cat->file, cat->filename);
788     if (!mask || *(mask2++))
789       {
790       ckeys = keys;
791       if (leadflag)
792         {
793         fprintf(stream, "%d", ++n);
794         if (nkeys)
795           putc(' ', stream);
796         }
797       for (k=0; k<nkeys; k++)
798         {
799         if ((key = *(ckeys++)) && (strflag || key->naxis==0))
800           {
801           ptr = memcpy(rfield, buf+key->pos, key->nbytes);
802           esize = t_size[key->ttype];
803           nelem = key->nbytes/esize;
804           if (bswapflag)
805             swapbytes(ptr, esize, nelem);
806           switch(key->ttype)
807             {
808             case T_SHORT:
809               for (j = 0; j<nelem; j++, ptr += esize)
810                 {
811                 if (key_col[k] == 0 || key_col[k] == j+1) {
812                    fprintf(stream, *key->printf?key->printf:"%d",
813 		   		*(short *)ptr);
814                    if (j < nelem-1) {
815                       switch (o_type) {
816                       case SHOW_ASCII:
817                          putc(' ', stream);
818                          break;
819                       case SHOW_SKYCAT:
820                          putc('\t', stream);
821                          break;
822                       }
823                       }
824                    }
825                 }
826               break;
827 
828             case T_LONG:
829               for (j = 0; j<nelem; j++,ptr += esize)
830                 {
831                 if (key_col[k] == 0 || key_col[k] == j+1) {
832                    fprintf(stream, *key->printf?key->printf:"%d",
833 		         		*(int *)ptr);
834                    if (j < nelem-1) {
835                       switch (o_type) {
836                       case SHOW_ASCII:
837                          putc(' ', stream);
838                          break;
839                       case SHOW_SKYCAT:
840                          putc('\t', stream);
841                          break;
842                       }
843                       }
844                    }
845                 }
846               break;
847 
848             case T_FLOAT:
849               for (j = 0; j<nelem; j++,ptr += esize)
850                 {
851                 if (key_col[k] == 0 || key_col[k] == j+1) {
852                     fprintf(stream, *key->printf?key->printf:"%g",
853 			*(float *)ptr);
854                    if (j < nelem-1) {
855                        switch (o_type) {
856                        case SHOW_ASCII:
857                           putc(' ', stream);
858                           break;
859                        case SHOW_SKYCAT:
860                           putc('\t', stream);
861                           break;
862                        }
863                        }
864                    }
865                 }
866               break;
867 
868             case T_DOUBLE:
869               for (j = 0; j<nelem; j++,ptr += esize)
870                 {
871                 if (key_col[k] == 0 || key_col[k] == j+1) {
872                    fprintf(stream, *key->printf?key->printf:"%f",
873 			*(double *)ptr);
874                    if (j < nelem-1) {
875                       switch (o_type) {
876                       case SHOW_ASCII:
877                          putc(' ', stream);
878                          break;
879                       case SHOW_SKYCAT:
880                          putc('\t', stream);
881                          break;
882                       }
883                       }
884                    }
885                 }
886               break;
887 
888             case T_BYTE:
889               if (key->htype==H_BOOL)
890                  for (j = 0; j<nelem; j++,ptr += esize)
891                    {
892                    if (key_col[k] == 0 || key_col[k] == j+1) {
893                       if (*(char *)ptr)
894                         fprintf(stream, "T");
895                       else
896                         fprintf(stream, "F");
897                       }
898                    }
899               else
900                 for (j = 0; j<nelem; j++,ptr += esize)
901                    {
902                    if (key_col[k] == 0 || key_col[k] == j+1) {
903                      fprintf(stream, *key->printf?key->printf:"%d",
904 			(int)*((unsigned char *)ptr));
905                    if (j) {
906                       switch (o_type) {
907                       case SHOW_ASCII:
908                          putc(' ', stream);
909                          break;
910                       case SHOW_SKYCAT:
911                          putc('\t', stream);
912                          break;
913                       }
914                       }
915                     }
916                  }
917               break;
918 
919             case T_STRING:
920               for (j = nelem; j-- && (c=(int)*ptr); ptr += esize)
921                 fprintf(stream, "%c", c);
922               break;
923 
924             default:
925               error(EXIT_FAILURE, "*FATAL ERROR*: Unknown FITS type in ",
926 			"show_keys()");
927             break;
928             }
929           if (k < nkeys - 1) {
930                    switch (o_type) {
931                    case SHOW_ASCII:
932                       putc(' ', stream);
933                       break;
934                    case SHOW_SKYCAT:
935                       putc('\t', stream);
936                       break;
937                    }
938                    }
939           }
940         }
941       putc('\n', stream);
942       }
943     }
944   free(key_col);
945   free(buf);
946   if (kflag)
947     free(keys);
948   if (o_type == SHOW_SKYCAT)
949      fprintf(stream, skycattail);
950   return;
951   }
952 
953