1 /*
2  				fitstab.c
3 
4 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 *
6 *	Part of:	The LDAC Tools
7 *
8 *	Author:		E.BERTIN, DeNIS/LDAC
9 *
10 *	Contents:	general functions for handling LDAC FITS catalogs.
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 /****** about_tab **************************************************************
29 PROTO	int about_tab(catstruct *cat, char *tabname, FILE *stream)
30 PURPOSE	Print information concerning a tab structure.
31 INPUT	Pointer to the input catalog,
32 	table name,
33 	an output stream.
34 OUTPUT	RETURN_OK if the table was found, RETURN_ERROR otherwise.
35 NOTES	-.
36 AUTHOR	E.R. Deul(Leiden observatory),
37 	E. Bertin (IAP & Leiden observatory): return value modified.
38 	E.R. Deul(Leiden observatory): output units
39 VERSION	15/08/2003
40  ***/
about_tab(catstruct * cat,char * tabname,FILE * stream)41 int about_tab(catstruct *cat, char *tabname, FILE *stream)
42 {
43    tabstruct *tab;
44    keystruct *key;
45    int		i, j;
46 
47    if ((tab = name_to_tab(cat, tabname, 0))) {
48        fprintf(stream, "Table %s\n", tabname);
49       for (i=0, key=tab->key; i<tab->nkey; i++,key=key->nextkey)
50     {
51     fprintf(stream,
52 	"******	Key #%d\n", i+1);
53     fprintf(stream,
54 	"	Key name:...............%s\n", key->name);
55     fprintf(stream,
56 	"	Key comment:............%s\n", key->comment);
57     fprintf(stream,
58 	"	Key type:...............");
59     switch (key->ttype) {
60     case T_BYTE: fprintf(stream,"Byte"); break;
61     case T_SHORT: fprintf(stream,"Short Int"); break;
62     case T_LONG: fprintf(stream,"Long Int"); break;
63     case T_FLOAT: fprintf(stream,"Float"); break;
64     case T_DOUBLE: fprintf(stream,"Double"); break;
65     case T_STRING: fprintf(stream,"String"); break;
66     }
67     fprintf(stream,"\n");
68     fprintf(stream,
69 	"	Key dimension:..........%d ", key->naxis);
70     if (key->naxis) fprintf(stream, "(");
71     for (j=0;j<key->naxis;j++) {
72        if (j>0) fprintf(stream, " ");
73        fprintf(stream, "%d", key->naxisn[j]);
74     }
75     if (key->naxis) fprintf(stream, ")");
76     fprintf(stream, "\n");
77     if (key->unit[0] != '\0')
78        fprintf(stream,
79 	"	Key unit:...............%s\n", key->unit);
80     }
81    } else return RETURN_ERROR;
82 
83    return RETURN_OK;
84 }
85 
86 /****** add_tab ****************************************************************
87 PROTO	int add_tab(tabstruct *tab, catstruct *cat, int pos)
88 PURPOSE	Add a table to a catalog.
89 INPUT	Pointer to the table,
90 	Pointer to the destination catalog,
91 	Position (1= first after the primary HDU, <=0 = at the end).
92 OUTPUT	RETURN_OK if everything went as expected, and RETURN_ERROR otherwise.
93 NOTES	Only 1-segment tables are accepted. To copy multi-segment tables,
94 	use copy_tab() instead.
95 	If a table with the same name and basic attributes already exists in
96 	the destination catalog, then the new table is appended to it.
97 AUTHOR	E. Bertin (IAP & Leiden observatory)
98 VERSION	15/08/2003
99  ***/
add_tab(tabstruct * tab,catstruct * cat,int pos)100 int	add_tab(tabstruct *tab, catstruct *cat, int pos)
101 
102   {
103    tabstruct	*outtab, *prevtab;
104    int		i;
105 
106 /*Check if a similar table doesn't already exist in the dest. cat */
107   if ((outtab = name_to_tab(cat, tab->extname, 0)))
108     {
109     if ((outtab->naxis != 2)
110 	|| (outtab->bitpix!=8)
111 	|| strcmp(outtab->xtension,tab->xtension)
112 	|| (outtab->tfields != tab->tfields)
113         || (outtab->naxisn[0] != tab->naxisn[0]))
114       return RETURN_ERROR;
115 
116     prevtab = outtab;
117     for (i=outtab->nseg-1; i--;)
118       prevtab = prevtab->nexttab;
119     tab->seg = prevtab->seg+1;
120     tab->nseg = 0;
121     outtab->nseg++;
122     }
123   else
124     {
125     if ((prevtab = pos_to_tab(cat, pos, 0)))
126       prevtab = prevtab->prevtab;
127     else
128       tab->nexttab = tab->prevtab = prevtab = tab;
129     cat->ntab++;
130     }
131 
132   (tab->nexttab = (tab->prevtab = prevtab)->nexttab)->prevtab = tab;
133   prevtab->nexttab = tab;
134 
135   return RETURN_OK;
136   }
137 
138 
139 /****** copy_tab **************************************************************
140 PROTO	int copy_tab(catstruct *catin, char *tabname, int seg,
141 		catstruct *catout, int pos)
142 PURPOSE	Copy a table from one catalog to another.
143 INPUT	Pointer to the original catalog,
144 	Name of the table,
145 	Table segment (0 = all),
146 	Pointer to the destination catalog,
147 	Position (1= first after the primary HDU, <=0 = at the end)
148 OUTPUT	RETURN_OK if everything went as expected, and RETURN_ERROR otherwise.
149 NOTES	If a table with the same name and basic attributes already exists in
150 	the destination catalog, then the original table is appended to it.
151 AUTHOR	E. Bertin (IAP & Leiden observatory)
152 VERSION	15/08/2003
153  ***/
copy_tab(catstruct * catin,char * tabname,int seg,catstruct * catout,int pos)154 int	copy_tab(catstruct *catin, char *tabname, int seg,
155 		catstruct *catout, int pos)
156 
157   {
158    keystruct	*key;
159    tabstruct	*outtab, *prevtab, *nexttab, *tabin,*tabout;
160    int		i,j, nseg;
161 
162 /*Convert the table name to a pointer*/
163   if (!(tabin = name_to_tab(catin, tabname, seg)))
164     return RETURN_ERROR;
165 
166   nseg = seg?1:tabin->nseg;
167 /*Check if a similar table doesn't already exist in the dest. cat */
168   if (*tabname && (outtab = name_to_tab(catout, tabname, 0)))
169     {
170     if ((outtab->naxis != 2)
171 	|| (outtab->bitpix!=8)
172 	|| strcmp(outtab->xtension,tabin->xtension)
173 	|| (outtab->tfields != tabin->tfields)
174         || (outtab->naxisn[0] != tabin->naxisn[0]))
175       return RETURN_ERROR;
176     prevtab = outtab;
177     for (i=0; i<outtab->nseg-1; i++)
178       prevtab = prevtab->nexttab;
179     nexttab = prevtab->nexttab;
180     outtab->nseg += nseg;
181     }
182   else
183     {
184     prevtab = nexttab = outtab = NULL;
185     catout->ntab++;
186     }
187 
188 /*Now copy each segment of the original table*/
189   tabout = NULL;	/* to satisfy gcc -Wall */
190   for (i=nseg; i--;)
191      {
192 /*---First, allocate memory and copy data */
193      QCALLOC(tabout, tabstruct, 1);
194      *tabout = *tabin;
195      if (tabin->naxis)
196        QMEMCPY(tabin->naxisn, tabout->naxisn, int, tabin->naxis);
197      if (tabin->headbuf)
198        QMEMCPY(tabin->headbuf, tabout->headbuf, char, tabin->headnblock*FBSIZE);
199      if (tabin->bodybuf)
200        QMEMCPY(tabin->bodybuf, tabout->bodybuf, char, tabin->tabsize);
201 
202      key = tabin->key;
203      tabout->key = NULL;
204      tabout->nkey = 0;
205      for (j=tabin->nkey; j--;)
206        {
207        copy_key(tabin, key->name, tabout, 0);
208        key = key->nextkey;
209        }
210 
211 /*---Then, update the links */
212      if (prevtab)
213        {
214        prevtab->nexttab = tabout;
215        tabout->prevtab = prevtab;
216        tabout->seg = prevtab->seg+1;
217        tabout->nseg = 0;
218        }
219      else
220        {
221        outtab = tabout;
222        outtab->prevtab = NULL;
223        tabout->seg = 1;
224        }
225      tabin = tabin->nexttab;
226      prevtab = tabout;
227      }
228 
229 /*place the new chain of table-segments within the catalog (tricky, isn't it?)*/
230   if (!nexttab)
231 /*--if the table is new */
232     {
233     nexttab = pos_to_tab(catout, pos, 0);
234     if (!nexttab)
235       nexttab = catout->tab = tabout;
236     else
237       {
238       outtab->prevtab = nexttab->prevtab;
239       nexttab->prevtab->nexttab = outtab;
240       }
241     }
242 
243   prevtab->nexttab = nexttab;
244   nexttab->prevtab = prevtab;
245 
246   return RETURN_OK;
247   }
248 
249 
250 /****** copy_tab_fromptr ******************************************************
251 PROTO	void copy_tab_fromptr(tabstruct *tabin, catstruct *catout, int pos)
252 PURPOSE	Copy a table from one catalog to another.
253 INPUT	Pointer to the original catalog,
254 	Pointer to the table,
255 	Pointer to the destination catalog,
256 	Position (1= first after the primary HDU, <=0 = at the end)
257 OUTPUT	-.
258 NOTES	-.
259 AUTHOR	E. Bertin (IAP & Leiden observatory)
260 VERSION	22/06/2001
261  ***/
copy_tab_fromptr(tabstruct * tabin,catstruct * catout,int pos)262 void	copy_tab_fromptr(tabstruct *tabin, catstruct *catout, int pos)
263 
264   {
265    keystruct	*key;
266    tabstruct	*prevtab, *nexttab,*tabout;
267    int		j;
268 
269   catout->ntab++;
270 
271 /* First, allocate memory and copy data */
272    QCALLOC(tabout, tabstruct, 1);
273    *tabout = *tabin;
274    if (tabin->naxis)
275      QMEMCPY(tabin->naxisn, tabout->naxisn, int, tabin->naxis);
276    if (tabin->headbuf)
277      QMEMCPY(tabin->headbuf, tabout->headbuf, char, tabin->headnblock*FBSIZE);
278    if (tabin->bodybuf)
279      QMEMCPY(tabin->bodybuf, tabout->bodybuf, char, tabin->tabsize);
280 
281    key = tabin->key;
282    tabout->key = NULL;
283    tabout->nkey = 0;
284    for (j=tabin->nkey; j--;)
285      {
286      copy_key(tabin, key->name, tabout, 0);
287      key = key->nextkey;
288      }
289 
290 /* Then, update the links */
291    tabout->prevtab = NULL;
292    tabout->seg = 1;
293    tabin = tabin->nexttab;
294    prevtab = tabout;
295 
296   if (!(nexttab = pos_to_tab(catout, pos, 0)))
297     nexttab = catout->tab = tabout;
298   else
299     {
300     tabout->prevtab = nexttab->prevtab;
301     nexttab->prevtab->nexttab = tabout;
302     }
303 
304   prevtab->nexttab = nexttab;
305   nexttab->prevtab = prevtab;
306 
307   return;
308   }
309 
310 
311 /****** copy_tabs **************************************************************
312 PROTO	int copy_tabs(catstruct *catin, catstruct *catout)
313 PURPOSE	Copy all tables from one catalog to another.
314 INPUT	Pointer to the original catalog,
315 	Pointer to the destination catalog,
316 OUTPUT	RETURN_OK if everything went as expected, and RETURN_ERROR otherwise
317 	(for instance if there were tabs that were not binary-tables, and
318 	therefore that were not copied).
319 NOTES	If a table with the same name and basic attributes already exists in
320 	the destination catalog, then the original table is appended to it.
321 AUTHOR	E. Bertin (IAP & Leiden observatory)
322 VERSION	12/06/2001
323  ***/
copy_tabs(catstruct * catin,catstruct * catout)324 int	copy_tabs(catstruct *catin, catstruct *catout)
325 
326   {
327    tabstruct	*tab;
328    int		i, flag, ntab;
329 
330   if (!catin->tab)
331     return RETURN_ERROR;
332 
333   tab = catin->tab->nexttab;	/* skip the primary header */
334   flag = RETURN_OK;
335   ntab = catin->ntab-1;
336   if (!ntab)
337     ntab = 1;
338   for (i=ntab; i--;)
339     {
340     flag |= copy_tab(catin, tab->extname, 0, catout, 0);
341     while (!(tab=tab->nexttab)->nseg);
342     }
343 
344   return flag;
345   }
346 
347 
348 /****** copy_tabs_blind *******************************************************
349 PROTO	int copy_tabs(catstruct *catin, catstruct *catout)
350 PURPOSE	Copy all tables from one catalog to another, without trying to append.
351 INPUT	Pointer to the original catalog,
352 	Pointer to the destination catalog,
353 OUTPUT	RETURN_OK if everything went as expected, and RETURN_ERROR otherwise.
354 NOTES	-.
355 AUTHOR	E. Bertin (IAP & Leiden observatory)
356 VERSION	07/05/2002
357  ***/
copy_tabs_blind(catstruct * catin,catstruct * catout)358 int	copy_tabs_blind(catstruct *catin, catstruct *catout)
359 
360   {
361    tabstruct	*tab;
362    int		i, ntab;
363 
364   if (!catin->tab)
365     return RETURN_ERROR;
366 
367   tab = catin->tab;	/* don't skip the primary header */
368   ntab = catin->ntab;
369   for (i=ntab; i--;)
370     {
371     copy_tab_fromptr(tab, catout, 0);
372     tab=tab->nexttab;
373     }
374 
375   return RETURN_OK;
376   }
377 
378 
379 /****** free_tab ***************************************************************
380 PROTO	void free_tab(tabstruct *tab)
381 PURPOSE	Free memory associated to a table pointer.
382 INPUT	Pointer to the table.
383 OUTPUT	-.
384 NOTES	-.
385 AUTHOR	E. Bertin (IAP & Leiden observatory)
386 VERSION	28/02/2000
387  ***/
free_tab(tabstruct * tab)388 void	free_tab(tabstruct *tab)
389 
390   {
391   free_body(tab);
392   free(tab->naxisn);
393   free(tab->headbuf);
394   free(tab->compress_buf);
395   remove_keys(tab);
396   free(tab);
397 
398   return;
399   }
400 
401 
402 /****** new_tab ****************************************************************
403 PROTO	tabstruct *new_tab(char *tabname)
404 PURPOSE	Create a new binary table.
405 INPUT	Name.
406 OUTPUT	A pointer to the new table.
407 NOTES	A defaut header is also created.
408 	No links are initialized.
409 AUTHOR	E. Bertin (IAP & Leiden observatory)
410 VERSION	25/04/97
411  ***/
new_tab(char * tabname)412 tabstruct	*new_tab(char *tabname)
413 
414   {
415    static char	bintabtemplate[][80] = {
416 "XTENSION= 'BINTABLE'           / THIS IS A BINARY TABLE (FROM THE LDACTOOLS)",
417 "BITPIX  =                    8 / ",
418 "NAXIS   =                    2 / ",
419 "NAXIS1  =                    0 / BYTES PER ROW",
420 "NAXIS2  =                    0 / NUMBER OF ROWS",
421 "PCOUNT  =                    0 / RANDOM PARAMETER COUNT",
422 "GCOUNT  =                    1 / GROUP COUNT",
423 "TFIELDS =                    0 / FIELDS PER ROWS",
424 "EXTNAME = 'WHOCARES'           / TABLE NAME",
425 "END                            "};
426    tabstruct	*tab;
427    char		*buf;
428    int		i;
429 
430   QCALLOC(tab, tabstruct, 1);
431   strcpy(tab->xtension, "BINTABLE");
432   strcpy(tab->extname, tabname);
433   tab->naxis = 2;
434   QCALLOC(tab->naxisn, int, tab->naxis);
435   tab->bitpix = 8;
436   tab->bytepix = 1;
437   tab->pcount = 0;
438   tab->gcount = 1;
439   tab->seg = 1;
440   tab->nseg = 1;
441 /*Provide a new header*/
442   QCALLOC(tab->headbuf, char, FBSIZE);
443   memcpy(tab->headbuf, bintabtemplate, sizeof(bintabtemplate));
444   for (buf = tab->headbuf, i=FBSIZE; i--; buf++)
445     if (!*buf)
446       *buf = ' ';
447   tab->headnblock = 1;
448 
449   return tab;
450   }
451 
452 
453 /****** remove_tab *************************************************************
454 PROTO	int remove_tab(catstruct *cat, char *tabname, int seg)
455 PURPOSE	Remove a table from a catalog.
456 INPUT	Pointer to the catalog,
457 	Name of the table,
458 	Table segment (0 = all).
459 OUTPUT	RETURN_OK if everything went as expected, and RETURN_ERROR otherwise.
460 NOTES	If tabname = "", the last table from the list is removed.
461 AUTHOR	E. Bertin (IAP & Leiden observatory)
462 VERSION	15/08/2003
463  ***/
remove_tab(catstruct * cat,char * tabname,int seg)464 int	remove_tab(catstruct *cat, char *tabname, int seg)
465 
466   {
467    tabstruct	*tab, *prevtab, *nexttab;
468    int		i,nseg;
469 
470   if (!tabname || !cat->ntab || !cat->tab)
471     return RETURN_ERROR;
472 
473   if (tabname[0])
474     {
475 /*--Convert the table name to a pointer*/
476     if (!(tab = name_to_tab(cat, tabname, seg)))
477       return RETURN_ERROR;
478 /*--a small trick to simplify decisions afterwards*/
479     if (seg && tab->nseg==1)
480       seg = 0;
481     }
482   else
483     {
484     tab = cat->tab->prevtab;
485     if (!seg)
486       for (;!tab->nseg; tab = tab->prevtab);
487     }
488 
489   prevtab = tab->prevtab;
490   nseg = seg?1:tab->nseg;
491 
492 /*Free memory for each table segment*/
493   nexttab = NULL;	/* to satisfy gcc -Wall */
494   for (i=nseg; i--;)
495     {
496     nexttab = tab->nexttab;
497     if (cat->tab == tab)
498       cat->tab = nexttab;
499     free_tab(tab);
500     tab = nexttab;
501     }
502 
503   if (!seg)
504     if (!--cat->ntab)
505       {
506       cat->tab = NULL;
507       return RETURN_OK;
508       }
509 
510 /*update the links of neighbours*/
511   nexttab->prevtab = prevtab;
512   prevtab->nexttab = nexttab;
513 
514   if (seg)
515 /*--update status for each table segment*/
516     {
517     for (tab=prevtab;!tab->nseg; tab = tab->prevtab);
518     for (nexttab=tab->nexttab,i=2;!nexttab->nseg;nexttab=nexttab->nexttab,i++);
519       nexttab->seg = i;
520     tab->nseg = i;
521     tab->seg = 1;
522     }
523 
524   return RETURN_OK;
525   }
526 
527 
528 /****** remove_tabs ************************************************************
529 PROTO	int remove_tabs(catstruct *cat)
530 PURPOSE	Remove all tables from a catalog.
531 INPUT	Pointer to the catalog.
532 OUTPUT	RETURN_OK if tabs were found, and RETURN_ERROR otherwise.
533 NOTES	-.
534 AUTHOR	E. Bertin (IAP & Leiden observatory)
535 VERSION	25/05/97
536  ***/
remove_tabs(catstruct * cat)537 int	remove_tabs(catstruct *cat)
538 
539   {
540    int	t;
541 
542   if (!cat->tab)
543     return RETURN_ERROR;
544 
545   for (t=cat->ntab; t--;)
546     remove_tab(cat, "",0);
547 
548   return RETURN_OK;
549   }
550 
551 
552 /****** update_tab ************************************************************
553 PROTO	int update_tab(tabstruct *tab)
554 PURPOSE	Update a table according to what's in the keys.
555 INPUT	Table structure.
556 OUTPUT	RETURN_OK if tab is a binary table, or RETURN_ERROR otherwise.
557 NOTES	The headbuf pointer in the catstruct might be reallocated.
558 AUTHOR	E. Bertin (IAP & Leiden observatory)
559 VERSION	08/02/97
560  ***/
update_tab(tabstruct * tab)561 int	update_tab(tabstruct *tab)
562 
563   {
564    tabstruct	*keytab;
565    keystruct	*key;
566    int		i,j, nobj, nbytes;
567 
568 /*Just pass if not a binary table*/
569   if ((tab->naxis != 2)
570 	|| (tab->bitpix!=8)
571 	|| strncmp(tab->xtension, "BINTABLE", 8))
572     return RETURN_ERROR;
573 
574 /*Well, not much to do if there are no keys!*/
575   if (!(key = tab->key))
576     return RETURN_OK;
577 
578   nobj = -1;
579   keytab = NULL;
580   nbytes = 0;
581   for (i=tab->nkey; i--;)
582     {
583     if (keytab && !key->ptr && key->tab != keytab)
584       error(EXIT_FAILURE, "*Error*: wrong reference table in ",
585 	key->name);
586     if (nobj!=-1 && (nobj != key->nobj))
587       error(EXIT_FAILURE, "*Error*: wrong number of elements in key ",
588 	key->name);
589     keytab = key->tab;
590     nobj = key->nobj;
591 /*-- If the number of bytes per element is not set, recover it */
592     if (!key->nbytes)
593       {
594       key->nbytes = t_size[key->ttype];
595       for (j=key->naxis; j--;)
596         key->nbytes *= key->naxisn[j];
597       }
598     nbytes += key->nbytes;
599     key = key->nextkey;
600     }
601 
602   tab->tabsize = nobj*nbytes;
603   tab->naxisn[0] = nbytes;
604   tab->naxisn[1] = nobj;
605   tab->tfields = tab->nkey;
606 
607   return RETURN_OK;
608   }
609 
610 
611 /****** name_to_tab ***********************************************************
612 PROTO	tabstruct *name_to_tab(catstruct *cat, char *tabname, int seg)
613 PURPOSE	Name search of a table in a catalog.
614 INPUT	Pointer to the catalog,
615 	Table name,
616 	Table segment (0 = first).
617 OUTPUT	The table pointer if the name was matched, and NULL otherwise.
618 NOTES	-
619 VERSION	12/06/2001
620  ***/
name_to_tab(catstruct * cat,char * tabname,int seg)621 tabstruct	*name_to_tab(catstruct *cat, char *tabname, int seg)
622 
623   {
624    tabstruct	*tab;
625    int		i;
626 
627   if (!(tab = cat->tab))
628     return NULL;
629 
630   for (i=cat->ntab; strcmp(tabname,tab->extname) && i--;)
631     while (!(tab=tab->nexttab)->nseg);
632 
633   if (i<0)
634     return NULL;
635 
636   if (seg)
637     {
638     for (;tab->seg!=seg && !tab->nexttab->nseg; tab=tab->nexttab);
639     return tab->seg==seg?tab:NULL;
640     }
641 
642   return tab;
643   }
644 
645 
646 /****** pos_to_tab *************************************************************
647 PROTO	tabstruct *pos_to_tab(catstruct *cat, int pos, int seg)
648 PURPOSE	Position search of a table in a catalog.
649 INPUT	Pointer to the catalog,
650 	Position of the table,
651 	Table segment (0 = first).
652 OUTPUT	The table pointer if the table exists at the given position, and the
653 	pointer to the primary ``table'' otherwise.
654 NOTES	pos = 1 means the first table after the primary one.
655 AUTHOR	E. Bertin (IAP & Leiden observatory)
656 VERSION	15/02/96
657  ***/
pos_to_tab(catstruct * cat,int pos,int seg)658 tabstruct	*pos_to_tab(catstruct *cat, int pos, int seg)
659 
660   {
661    tabstruct	*tab;
662    int		i;
663 
664   tab = cat->tab;
665   for (i=0; i!=pos && i<cat->ntab; i++)
666     while (!(tab=tab->nexttab)->nseg);
667 
668   if (seg)
669     for (;tab->seg!=seg && !tab->nexttab->nseg; tab=tab->nexttab);
670 
671   return i<cat->ntab?tab:cat->tab;
672   }
673 
674 /****** tabs_list **************************************************************
675 PROTO	char **tabs_list(catstruct *cat, int *n)
676 PURPOSE	List all tables in a catalog.
677 INPUT	Pointer to the catalog,
678 	Pointer to the number of names in that list.
679 OUTPUT	A list of all table names.
680 NOTES	-.
681 AUTHOR	E.R. Deul (Leiden observatory)
682 VERSION	??/??/96
683  ***/
tabs_list(catstruct * cat,int * n)684 char **tabs_list(catstruct *cat, int *n)
685 
686   {
687    tabstruct	*tab;
688    int		i;
689    char 	**names;
690 
691   tab = cat->tab;
692   QCALLOC(names, char *, cat->ntab);
693   for (i=0; i<cat->ntab; i++) {
694     QCALLOC(names[i], char, MAXCHARS);
695     strcpy(names[i],tab->extname);
696     while (!(tab=tab->nexttab)->nseg);
697   }
698   *n = cat->ntab;
699   return names;
700   }
701 
702 /****** tabs_row_len ***********************************************************
703 PROTO	int tab_row_len(char *file, char *tabname)
704 PURPOSE	Return the row length in bytes of a given table in a given catalog.
705 INPUT	File pointer.
706 OUTPUT	Table size (bytes)
707 NOTES	-.
708 AUTHOR	E.R. Deul (Leiden observatory)
709 VERSION	05/06/200`
710  ***/
tab_row_len(char * file,char * tabname)711 int tab_row_len(char *file, char *tabname)
712 
713 {
714     catstruct   *tcat;
715     tabstruct   *tab;
716     int		retcode = -1;
717 
718     if ((tcat = read_cat(file)) != NULL) {
719        if ((tab = name_to_tab(tcat, tabname, 0)) != NULL) {
720           retcode = tab->naxisn[0];
721 	  free_tab(tab);
722        }
723        close_cat(tcat);
724        free_cat(&tcat,1);
725     }
726     return retcode;
727 }
728 
729