[comp.sources.x] v06i047: Xcol -- Color-Selector, Part01/02

hoenig@informatik.uni-kl.de (Helmut Hoenig) (03/23/90)

Submitted-by: Helmut Hoenig <hoenig@informatik.uni-kl.de>
Posting-number: Volume 6, Issue 47
Archive-name: xcol/part01

XCol is a program to edit occurrences of color-names in text-files
(i.e. the '.twmrc'-file). It shows the available colors and you can
change the textfile by selecting new colors with the mouse.

Even without editing a textfile, it gives you a good impression
of the available colors (the colors defined in the 'rgb.txt'-file
of the server).

The program runs on X11R4. It should run on X11R3 too, but I
already had some small problems with the created colormap.
A manual page is included.

by Helmut Hoenig
hoenig@informatik.uni-kl.de

-------------------------------------------------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  xcol.txt makefile Imakefile patchlevel.h xcol.part1
# Wrapped by hoenig@popper on Wed Mar 21 16:47:26 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f xcol.txt -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"xcol.txt\"
else
echo shar: Extracting \"xcol.txt\" \(3824 characters\)
sed "s/^X//" >xcol.txt <<'END_OF_xcol.txt'
XNAME
X     xcol - change color-entries in textfiles
X
XSYNOPSIS
X     xcol [-options ...] [filename]
X
XDESCRIPTION
X     XCol displays the colors defined in the rgb.txt-file of  the
X     XServer.   The  colors  are  sorted by their names and their
X     RGB-values and shown in a cube in the ColorView-Window  (The
X     positions  represent  the  RGB-values).  Since there usually
X     are more colors defined in the file than cells in the color-
X     map, entries with the same name but different RGB-values for
X     different intensities, are grouped together.
X
X     If a filename is given as a parameter,  all  occurrences  of
X     color-names   in  that  file  are  shown  in  an  additional
X     TextView-Window. To change the colors, a text-line has to be
X     made  active.  Afterwards a new color can be selected in the
X     ColorView-Window. To get a better impression of the color, a
X     help-color  (background) can be selected for each text-line.
X     If 2 lines define a foreground and a  background  color,  an
X     association  can be made and the colors of both lines can be
X     selected together.
X
XBUTTONS
X     in ColorView-Window
X
X          left:   select color for the active line.
X          middle: select help-color for the active line.
X          right:  warp pointer to color of active line.
X
X     in TextView-Window
X
X          left:   select line as active line.
X          middle: toggle reverse-mode or
X                  connect/disconnect 2 lines.
X          right:  show line in the textfile.
X
XOPTIONS
X     -rv     Color-positions are reversed in the cube.  Some  new
X             colors  can  become  visible in the area of the very
X             bright colors.
X
X     -b<n>   The size of color blocks is set to the constant <n>.
X             By   default,   it   depends  on  the  size  of  the
X             ColorView-Window.
X
X     -gran<n>
X             The maximum number of associated colors  is  set  to
X             <n>.  By default, this value is 11. (You can see the
X             effect  when  reaching  the  grey-field,  where  101
X             associated entries are possibly available.)
X
X     -dark<n>
X             The percentage of the intensity of other colors  can
X             be  set  (default:  50).  It  is  easier to select a
X             color, if the screen is darkened a little bit.
X
X     +<char_list>
X             add characters to list of 'space'-chars. The  color-
X             string  in  the  textfile  has  to  occur  between 2
X             'space'-chars to be recognized.  By  default,  these
X             letters are ' ', '\t', '\n', ':', '"'.
X
X     -strings
X             Names of colors in the file are only recognized when
X             used  in a string (useful for C-Sources). This means
X             that the list of 'space'-chars is set to '"' only.
X
X     -case   All occurrences of color-names  in  wrong  case  are
X             replaced by the color-name of the 'rgb.txt'-file.
X
X     -help   print some instructions (usage of buttons).
X
X     -file <name>
X             name of a different 'rgb.txt'-file.
X
XFILES
X     /usr/lib/X11/rgb.txt
X
XSEE ALSO
X     X(1)
X
XBUGS
X     Actually I wanted the program to  work  with  the  selection
X     mechanism  used in xterm (when no textfile is given), but it
X     seems to be too complicated to use it here.  So, the current
X     version   always   stores   the   string  of  the  color  in
X     CUT_BUFFER0.  If anyone has an easy way to use  the  correct
X     selection mechanism, please inform me.
X
XCOPYRIGHT
X     Copyright 1990, University of Kaiserslautern.
X
X     Author: Helmut Hoenig (hoenig@informatik.uni-kl.de)
X
X     Permission  to  use,  copy,  modify,  and  distribute   this
X     software  for any purpose and without fee is hereby granted,
X     provided that the  above  copyright  notice  appear  in  all
X     copies.
END_OF_xcol.txt
if test 3824 -ne `wc -c <xcol.txt`; then
    echo shar: \"xcol.txt\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"makefile\"
else
echo shar: Extracting \"makefile\" \(99 characters\)
sed "s/^X//" >makefile <<'END_OF_makefile'
XCFLAGS = 
XLIBS   = -lX11
XG_OBJ  = xcol.o
X
Xxcol:	$(G_OBJ)
X	$(CC) $(CFLAGS) $(G_OBJ) $(LIBS) -o xcol
END_OF_makefile
if test 99 -ne `wc -c <makefile`; then
    echo shar: \"makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Imakefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Imakefile\"
else
echo shar: Extracting \"Imakefile\" \(78 characters\)
sed "s/^X//" >Imakefile <<'END_OF_Imakefile'
X           SRCS = xcol.c
X           OBJS = xcol.o
X
XComplexProgramTarget(xcol)
END_OF_Imakefile
if test 78 -ne `wc -c <Imakefile`; then
    echo shar: \"Imakefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f patchlevel.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"patchlevel.h\"
else
echo shar: Extracting \"patchlevel.h\" \(53 characters\)
sed "s/^X//" >patchlevel.h <<'END_OF_patchlevel.h'
X#define	PATCHLEVEL	0
X#define	PATCHDATE	"Mar-21-1990"
END_OF_patchlevel.h
if test 53 -ne `wc -c <patchlevel.h`; then
    echo shar: \"patchlevel.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f xcol.part1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"xcol.part1\"
else
echo shar: Extracting \"xcol.part1\" \(24317 characters\)
sed "s/^X//" >xcol.part1 <<'END_OF_xcol.part1'
X/****************************************************************
X *								*
X *  xcol - program to edit color-name-occurrences in textfiles	*
X *								*
X *	     Written by Helmut Hoenig, Feb. 1990.		*
X *	    University of Kaiserslautern, Germany		*
X *								*
X *	     email: hoenig@informatik.uni-kl.de			*
X *								*
X ****************************************************************/
X
X#include <X11/Xlib.h>
X#include <X11/Xutil.h>
X#include <X11/cursorfont.h>
X
X#include <sys/param.h>
X#include <stdio.h>
X#include <strings.h>
X#include <ctype.h>
X
X#include "patchlevel.h"
X
X/*----------------------------------------------------------------------------*/
X
X#define	COLOR_FONT	"-adobe-times-bold-r-normal--17-120-100-100-p-88-iso8859-1"
X#define	TEXT_FONT	"-adobe-times-bold-r-normal--12-120-75-75-p-67-iso8859-1"
X
X#define	RGB_FILE	"/usr/lib/X11/rgb.txt"
X
X/* MAX_??? - definitions are used in the definition of some local arrays, 
X   where I didn't want to make complicated memory allocation.		*/
X
X#define	MAX_CELLS	256	/* number of cells, used by the programm*/
X
X#define	MAX_COLS	1000	/* colors in rgb.txt-file		*/
X#define	MAX_COLOR_LINES	400	/* color occurrences in a textfile	*/
X#define	MAX_LINE_LENGTH	1000	/* linelength of textfile		*/
X
X/*----------------------------------------------------------------------------*/
X
X/* switch on/off some bugs ?? */
X#define	CHG_TEXT_WINDOW_COLORMAP
X#define _RECOLOR_CURSOR
X
X/* variables for parameters (default is set) */
Xint		reverse	= 0;
Xint		BO_def	= 0;
Xint		darkness=50;
Xint		gran	=11;
Xint		original= 0;
X
X/* X-Data */
XDisplay		*display;
XScreen		*screen;
XXFontStruct	*finfo;
XGC		gc;
Xint		cells;
X
X/* the grey-pixmap is used to get an impression of mixing the foreground
X * and background color of a color-line.
X */
X#define grey_width 16
X#define grey_height 16
Xstatic char grey_bits[] = {
X   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 
X   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 
X   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 
X   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa};
XPixmap	grey_pixmap;
X
XCursor	mw_cursor;	/* Cursor in main-window			*/
XCursor	tw_cursor;	/* Cursor in text-window			*/
XCursor	subsel_cursor;	/* Cursor during selection of associated colors */
XCursor	text_cursor;	/* Cursor while looking in the source-file	*/
XCursor	quest_cursor;	/* Cursor while asking for write-confirmation	*/
XCursor	updown_cursor;	/* Cursor while making association		*/
X
X/* Mainwindow-Data */
XWindow		mw;	/* Window-Id */
Xint		dx, dy;	/* current size of the window */
Xint		BO=14;	/* current size of the color-boxes in the window */
X
X/* Textwindow-Data */
XWindow		tw = NULL;
XXFontStruct	*tinfo;			/* Structure of the textfont */
Xint		char_width, char_height;/* char-size depending on the font */
Xchar		*tw_message[2];		/* messages in header and footer-line */
Xint		twidth;			/* width in pixel */
Xint		tw_lines;		/* height in lines (header&footer not included) */
Xint		act_line=0;		/* active-line */
Xint		act_offset=0;		/* first color-line (when not all lines fit in the window) */
X
X/* Subwindow-Data (little window for selected color) */
XWindow		subw;		/* Window-Id */
Xint		sdx, sdy;	/* current size of subwindow */
Xint		subcols;	/* number of associated colors in the subwindow */
X
X/* Color-Management */
XColormap	my_map=NULL;
Xint		my_pixel[MAX_CELLS];	/* flag: 0 = pixel not used in my program */
Xint		only_mine;	/* flag: 1 = allocations only in own map */
X
X#define	NotAllocated	(-1L)
X#define	Undefined	(-2L)
X
Xtypedef	struct _color_def {
X	int			r, g, b;	/* rgb-value from the 'rbg.txt'-file */
X	char			*name;	/* name from the 'rgb.txt'-file */
X	int			x, y;	/* position in main window	*/
X	unsigned long		pixel;	/* allocated pixel for the color */
X	struct	_color_def	*associated;	/* colors with different intensity (e.g. 'blue' -> 'blue4' ... ) */
X	struct	_color_def	*brother;	/* colors with different name (e.g. 'OldLace' -> 'old lace') */
X} ColorDef;
X
Xtypedef	struct _color_strings {
X	char		*name;
X	int		length;
X	ColorDef	*def;
X} ColorString;
X
XColorDef	*color[MAX_COLS];	/* field with the definitions of the colors */
XColorString	cname[MAX_COLS];	/* sorted field with the names of all colors */
XColorString	*first[256];		/* 'Hash-Table', points to the first name
X					   that starts with the given letter. */
X
Xint	color_names;	/* number of color-names
X			   = entries in the 'rgb.txt'-file */
Xint	color_number;	/* number of 'different' colors
X			   = number of colors shown in the cube */
X
X#define	BLACK_STRING	"black"
X#define	WHITE_STRING	"white"
X#define	GREY_STRING	"gray"
X
XColorDef std_black = {   0,   0,   0, BLACK_STRING };
XColorDef std_white = { 255, 255, 255, WHITE_STRING };
XColorDef std_grey  = { 192, 192, 192, GREY_STRING  };
X
Xunsigned long	white, black, grey;	/* pixel-values (in my_map !!) */
XColorDef *back_def;			/* default background in textwindow */
X
X/*----------------------------------------------------------------------------*/
X
Xtypedef	struct	_text_line {	/* structure to store the text-file */
X	char			*contents;
X	struct	_text_line	*next;
X	struct	_text_line	*previous;
X} TextLine;
X
Xtypedef	struct	_color_line {	/* structure for a line with color-entry */
X	TextLine	*line;		/* pointer to the textline */	
X	ColorDef	*color;		/* the color defined in the line */
X	ColorDef	*help;		/* a help-color for the background */
X	int		reverse;	/* flag to display line in reverse */
X	int		pos_in_line;	/* position of the color-name in the line */
X	int		assoc;		/* corresponding color-line, when a
X					   'foreground-background'-association
X					   was found (or entered) */
X} ColorLine;
X
Xchar		*file_name;		/* name of the text-file */
XTextLine	*loaded_text;		/* Pointer to the first line */
XColorLine	line[MAX_COLOR_LINES];	/* array of the color-lines */
Xint		color_lines;		/* number of the color-lines */
Xint		longest_colored;	/* length of the longest color-line */
X
Xchar	space_char[256];		/* flag, which chars should be recognized
X					   as spaces */
X
X
X/********************************************************************************
X *	    parsing the text-file (not very efficient, but who cares)		*
X ********************************************************************************/
X
X
Xvoid set_default_spaces()
X{
X	memset( space_char, 0, (int)sizeof(space_char) );
X	space_char[ ' ' ] = space_char[ '\t' ] = space_char[ '\n' ] = 
X	space_char[ ':' ] = space_char[ '"' ] = 1;
X}
X
Xint strncase_equal( s1, s2, n )
X	register char	*s1;
X	register char	*s2;
X	register int	n;
X/* the function is NOT correct, since just proves, if strings are equal
X   when the 5th bit of their characters is ignored.
X */
X{
X	while(n--)
X	{	if ( ((*s1++)^(*s2++))&((unsigned char)~32) )	return(1);
X	}
X	return(0);
X}
X
Xint strcase_equal( s1, s2 )
X	char	*s1,*s2;
X{
Xint	n1,n2;
X
X	n1 = strlen(s1);
X	n2 = strlen(s2);
X	if (n1!=n2)	return(-1);
X	else		return(strncase_equal( s1, s2, n1 ));
X}
X
Xstring_exchange( cline, new_color )
X	ColorLine	*cline;
X	ColorDef	*new_color;
X/* replaces the color-string in a color-line */
X{
Xchar	new_line[MAX_LINE_LENGTH];
Xint	pos;
X
X	pos = cline->pos_in_line;
X	strncpy( &new_line[0], cline->line->contents, pos );
X	strcpy( &new_line[pos], new_color->name );
X	strcat( new_line, &cline->line->contents[pos+strlen(cline->color->name)] );
X	free( cline->line->contents );
X	cline->line->contents = (char *)malloc((unsigned) strlen( new_line )+1 );
X	strcpy( cline->line->contents, new_line );
X}
X
Xvoid check_colors( in_line )
X	TextLine	*in_line;
X/* checks, if a color exists in the given line and possibly adds
X * the line to the list of color-lines.
X */
X{
Xint		i, c;
Xchar		lett;
Xchar		check;
XColorString	*col;
Xchar		*act_line = in_line->contents;
X
X	c=strlen(act_line);
X	while(c>0)
X	{   do
X	    {	c--;
X		if (space_char[act_line[c-1]])	break;
X	    }
X	    while(c>1);
X
X	    lett = act_line[c];
X	    if (isalpha(lett))
X	    {
X	    	if (isupper(lett))	lett = tolower( lett );
X	/* compares both cases */
X		for (i=0;i<2;i++)
X		{    for (col=first[lett];col<first[lett+1];col++)
X		    {
X		    	check = act_line[c+col->length];
X			if (space_char[check])
X			{	if ((strncase_equal( &act_line[c], col->name, col->length )==0 ))
X				{	line[color_lines].line = in_line;
X					line[color_lines].color= col->def;
X					line[color_lines].help = back_def;
X					line[color_lines].pos_in_line = c;
X					line[color_lines].reverse = 0;
X					line[color_lines].assoc = -1;
X
X					if (original)
X					{	string_exchange( &line[color_lines], col->def );
X					}
X					if (XTextWidth( tinfo, act_line, strlen(act_line) )>longest_colored)
X						longest_colored = XTextWidth( tinfo, act_line, strlen(act_line) );
X					color_lines++;
X					return;
X				}
X			}
X		    }
X		    lett = toupper( lett );
X		}
X	    }
X	}
X}
X
Xint spc_line( search_string, line, name, length )
X	char		*search_string;
X	TextLine	*line;
X	char		*name;
X	int		*length;
X/* searches for the search-string in the given line. If it exists, the name
X * in front of the search-string is copied to name and its length is returned.
X */
X{
Xint	c, sl, cs;
X
X	c = strlen( line->contents );
X	sl = strlen(search_string);
X	while( c>0 )
X	{	if (strncase_equal( search_string, &line->contents[c], sl )==0)
X		{	cs=c;
X			do
X			{	cs--;
X				if (isspace(line->contents[cs]))	break;
X			}
X			while(cs>0);
X			*length = c-cs;
X			if (cs)
X			{	(*length)--;	cs++;
X			}
X
X			strncpy( name, &line->contents[cs], *length );
X			name[*length]='\0';
X			return(1);
X		}
X		c--;
X	}
X	return(0);
X}
X
Xvoid find_assocs()
X/* tries to find 'Foreground-Background'-Associations in the Color-Lines */
X{
Xint	i, j;
Xchar	name1[100], name2[100];
Xint	length1, length2;
X
X	for (i=0;i<color_lines;i++)
X	{	if (spc_line("foreground", line[i].line, name1, &length1))
X		{	for (j=i+1;j>=i-1;j-=2)
X			{   if ((j>=0)&&(j<color_lines))
X			    {	if (spc_line("background", line[j].line, name2, &length2))
X				{
X					if (strcmp(name1, name2)==0)
X					{	line[i].reverse=0;
X						line[i].help = line[j].color;
X						line[i].assoc= j;
X
X						line[j].reverse=1;
X						line[j].help = line[i].color;
X						line[j].assoc= i;
X					}
X				}
X			    }
X			}
X		}
X		else if ((spc_line("background", line[i].line, name1, &length1))&&(line[i].assoc<0))
X		{	for (j=i+1;j>=i-1;j-=2)
X			{   if ((j>=0)&&(j<color_lines))
X			    {	if (spc_line("border", line[j].line, name2, &length2))
X				{
X					if (strcmp(name1, name2)==0)
X					{	line[i].reverse=1;
X						line[i].help = line[j].color;
X						line[i].assoc= j;
X
X						line[j].reverse=0;
X						line[j].help = line[i].color;
X						line[j].assoc= i;
X					}
X				}
X			    }
X			}
X		}
X	}
X}
X
Xint load_file( fname )
X	char	*fname;
X/* loads the text-file and tries to find color-entries in each line */
X{
XFILE		*fp;
XTextLine	*act, *next;
Xchar		linebuffer[MAX_LINE_LENGTH];
X
X/* load the file with colors */
X	longest_colored = 0;
X	color_lines = 0;
X
X	fp = fopen( fname, "r" );
X	if (fp==NULL)
X	{	fprintf( stderr, "can't load file '%s'.\n", fname );
X		return(0);
X	}
X
X	loaded_text = act = NULL;
X	while (fgets( linebuffer, sizeof linebuffer, fp )!=NULL)
X	{	next = (TextLine *)malloc((unsigned)sizeof(TextLine));
X		next->contents = (char *)malloc((unsigned)strlen(linebuffer)+1);
X		strcpy( next->contents, linebuffer );
X
X		check_colors( next );
X		if (act==NULL)
X		{	loaded_text=act	= next;
X			next->previous	= NULL;
X		}
X		else
X		{	act->next	= next;
X			next->previous	= act;
X			act = next;
X		}
X	}
X	fclose( fp );
X	act->next=NULL;
X	return(1);
X}
X
Xint write_file( fname )
X	char	*fname;
X{
XFILE		*fp;
XTextLine	*act;
X
X	fp = fopen( fname, "w" );
X	if (fp==NULL)	return(-1);
X	act = loaded_text;
X	while( act )
X	{	if (fputs( act->contents, fp )==EOF)
X		{	fprintf(stderr, "write error on file '%s'\n", fname);
X			fclose(fp);
X			return(-2);
X		}
X		act = act->next;
X	}
X	fclose( fp );
X	return(0);
X}
X
X
X/********************************************************************************
X *		allocating, freeing, sorting, searching COLORS.			*
X ********************************************************************************/
X
X
XColorDef *find_color( name )
X	char	*name;
X/* searches in the tree of colordefinitions for the named color */
X{
XColorDef	*erg, *assoc;
Xint		i;
X
X	for (i=0;i<color_number;i++)
X	{	erg = color[i];
X		do
X		{
X			if (strcase_equal(erg->name, name)==0)	return( erg );
X			assoc = erg->associated;
X			while( assoc )
X			{	if (strcase_equal(assoc->name, name)==0)	return( assoc );
X				assoc = assoc->associated;
X			}
X			erg = erg->brother;
X		}
X		while (erg);
X	}
X	return(NULL);
X}
X
Xvoid load_color( act )
X	ColorDef *act;
X/* allocates a pixel for the color, if it is not already allocated. When it's
X * still possible to allocate pixels in the DefaultColormap, this is done and
X * the same color is stored in both maps. If no more cells are available in
X * the DefaultColormap, the program continues working only in its own map.
X */
X{
XXColor	scr;
Xlong	pixel;
X
X	if (act->pixel==NotAllocated)
X	{	if (!only_mine)
X		{	if ( (!XAllocColorCells( display, DefaultColormapOfScreen(screen), True, 
X				NULL, 0, (unsigned long*)&pixel, 1 )) || (pixel>=cells) )
X			{
X				for (pixel=0;pixel<cells;pixel++)
X				{
X				    if (my_pixel[pixel])
X				    {	XFreeColors( display, DefaultColormapOfScreen(screen), 
X				    		(unsigned long*)&pixel, 1, 0 );
X				    }
X				}
X
X				only_mine=1;
X#ifdef CHG_TEXT_WINDOW_COLORMAP
X/* when switched on, all windows (not only the textwindow), are displayed
X * in my Colormap, when the DefaultColormap hasn't got any more cells available.
X * Try the option -gran100 and search for the 'gray'-color in the main-window
X * to reach the extremes of the program.
X */
X				if (tw)
X				{	XSetWindowColormap( display, tw, my_map );
X				}
X#endif
X			}
X		}
X		if (only_mine)
X		{	for (pixel=cells-1;pixel>=0;pixel--)
X			{	if (my_pixel[pixel]==0)	break;
X			}
X	/* the reaction to an overflow in the color-map is hard, but
X	 * I can't think of an easy solution for that problem.
X	 */		if (pixel<0)
X			{	fprintf( stderr, "You did it. The Colormap if full.\n");
X				if (CellsOfScreen(screen)>MAX_CELLS)
X				{	fprintf( stderr, "Compile the program again with the\n");
X					fprintf( stderr, "MAX_CELLS-macro set to an higher value.\n");
X				}
X				exit(0);
X			}
X		}
X		act -> pixel = pixel;
X		scr.pixel = pixel;
X		scr.flags = DoRed | DoGreen | DoBlue;
X		scr.red   = act->r << 8;
X		scr.green = act->g << 8;
X		scr.blue  = act->b << 8;
X		XStoreColor( display, my_map, &scr );
X		if (!only_mine)
X			XStoreColor( display, DefaultColormapOfScreen(screen), &scr );
X	}
X	my_pixel[act->pixel]++;
X}
X
Xvoid unload_color( act )
X	ColorDef *act;
X/* The color is not used anymore. It is possible that the color was loaded
X * more than once and therefor, the cell can't be freed.
X */
X{
X	if (act->pixel==NotAllocated)	return;
X
X	if ((--my_pixel[act->pixel])==0)
X	{	if (!only_mine)
X		{	XFreeColors( display, DefaultColormapOfScreen(screen), 
X					&act->pixel, 1, 0 );
X		}
X		act->pixel=NotAllocated;
X	}
X}
X
Xvoid load_text_colors()
X/* to load all colors used in the color-lines of the text-file */
X{
Xint i;
X
X	for (i=0;i<color_lines;i++)
X	{	load_color( line[i].color );
X		load_color( line[i].help  );
X	}
X}
X
Xvoid exchange( old, new )
X	ColorDef	**old;
X	ColorDef	*new;
X/* correct exchanging of a loaded color */
X{
X	if (*old)
X	{	unload_color( *old );
X	}
X	load_color( new );
X	*old = new;
X}
X
X/*----------------------------------------------------------------------------*/
X
X/*
X * functions to sort the colors
X */
X
Xint color_name_sort( p1, p2 )
X	ColorString	*p1, *p2;
X{
X	return(strcmp(p1->name, p2->name));
X}
X
Xint color_sort( p1, p2 )
X	ColorDef	**p1, **p2;
X{
Xchar	*s1, *s2;
X
X	if ((*p1)->b!=(*p2)->b)	return(((*p1)->b>(*p2)->b)?1:-1);
X	if ((*p1)->g!=(*p2)->g)	return(((*p1)->g>(*p2)->g)?1:-1);
X	if ((*p1)->r!=(*p2)->r)	return(((*p1)->r>(*p2)->r)?1:-1);
X	s1 = index((*p1)->name, ' ');
X	s2 = index((*p2)->name, ' ');
X	s1 = s2 = NULL;
X
X	if (s1)
X	{	if (s2)	return(strcmp((*p1)->name, (*p2)->name));
X		else	return(1);
X	}
X	else
X	{	if (s2)	return(-1);
X		else	return(strcmp((*p1)->name, (*p2)->name));
X	}
X}
X
Xint color_sort_r( p1, p2 )
X	ColorDef	**p1, **p2;
X{
X	if ((*p1)->b!=(*p2)->b)	return(((*p1)->b>(*p2)->b)?-1:1);
X	if ((*p1)->g!=(*p2)->g)	return(((*p1)->g>(*p2)->g)?-1:1);
X	if ((*p1)->r!=(*p2)->r)	return(((*p1)->r>(*p2)->r)?-1:1);
X	return(0);
X}
X
Xvoid brother_sort( first )
X	ColorDef	**first;
X{
XColorDef *list[1000];
Xint	 length;
X
X	length = 0;
X
X	list[length] = *first;
X	while(list[length]->brother)
X	{	list[length+1] = list[length]->brother;
X		length++;
X	}
X
X	qsort( (char *)list, length+1, sizeof(ColorDef *), color_sort );
X
X	list[length]->brother = NULL;
X
X	while(length>0)
X	{	list[length-1]->brother = list[length];
X		length--;
X	}
X	*first = list[0];
X}
X
Xvoid associated_sort( first )
X	ColorDef	*first;
X{
XColorDef *list[1000];
Xint	 length;
X
X	length = 0;
X
X	list[length] = first;
X	while(list[length]->associated)
X	{	list[length+1] = list[length]->associated;
X		length++;
X	}
X
X	qsort( (char *)&list[1], length, sizeof(ColorDef *), color_sort );
X
X	list[length]->associated = NULL;
X
X	while(length>0)
X	{	list[length-1]->associated = list[length];
X		length--;
X	}
X}
X
X/*----------------------------------------------------------------------------*/
X
X/*
X * functions to load the color-file and build the tree with colordefinitions
X */
X
Xchar *cut_digits( name )
X	char	*name;
X/* cuts digits from a color-string. returns a pointer to a static string
X * which of course must not be freed. if there where no digits, the original
X * pointer is returned.
X */
X{
Xstatic char short_name[40];
Xint i;
X
X	i = strlen(name);
X	if ((i>39)||(!isdigit(name[i-1])))	return(name);
X
X	strcpy( short_name, name );
X	i--;
X	while ((i>0)&&(isdigit(short_name[i])))
X	{	short_name[i] = '\0';
X		i--;
X	}
X	return(short_name);
X}
X
Xvoid next_name( act )
X	ColorDef	*act;
X/* collects color-names for the hash-table */
X{
X	if (act->pixel==Undefined)
X	{	fprintf(stderr, "%s not defined.\n", act->name);
X		return;
X	}
X	cname[color_names].name   = act->name;
X	cname[color_names].length = strlen(act->name);
X	cname[color_names].def    = act;
X	color_names++;
X}
X
XColorDef *make_entry( new )
X	ColorDef *new;
X/* allocates space for the data of a new color */
X{
XColorDef	*erg;
X
X	erg = (ColorDef *)malloc((unsigned) sizeof(ColorDef) );
X	memcpy( (char *)erg, (char *)new, sizeof(ColorDef) );
X	erg -> associated = NULL;
X	erg -> brother    = NULL;
X	erg -> pixel      = NotAllocated;
X
X	return( erg );
X}
X
Xvoid new_color( new )
X	ColorDef	*new;
X/* searches for overlaps in the color-field and stores the new color */
X{
Xchar		*search_name;
XColorDef	*act;
XColorDef	*help;
Xint		i;
Xint		subname = 0;
X
X	search_name = cut_digits( new->name );
X	subname = (search_name!=new->name);
X
X	act = find_color( search_name );
X
X	if (act)
X	{	if (subname)		/* found and associated entry */
X		{	help = act->associated;
X			act->associated = make_entry( new );
X			act->associated->associated = help;
X		}
X		else			/* strange: color declared twice ? */
X		{	if (act->pixel==Undefined)
X			{	memcpy( (char *)act, (char *)new, sizeof(ColorDef)-2*sizeof(ColorDef *) );
X				act->pixel = NotAllocated;
X			}
X			else
X			{
X				help = act->brother;
X				act->brother = make_entry( new );
X				act->brother->brother = help;
X			}
X		}
X	}
X	else
X	{	for (i=0;i<color_number;i++)
X		{	if ( (new->r==color[i]->r) && (new->g==color[i]->g) && (new->b==color[i]->b) )	break;
X		}
X		if (i<color_number)
X		{	help = color[i]->brother;
X			color[i]->brother = make_entry( new );
X			color[i]->brother->brother = help;
X		}
X		else
X		{	if (subname)	/* indexed name found before original */
X			{	act = (ColorDef *)malloc((unsigned) sizeof(ColorDef) );
X				memset( (char *)act, (char)-1, sizeof(ColorDef) );
X				act->pixel = Undefined;
X				act->name  = (char *)malloc((unsigned) strlen(search_name)+1 );
X				strcpy( act->name, search_name );
X				act->associated = make_entry( new );
X				act->brother = NULL;
X				color[color_number++] = act;
X			}
X			else		/* found new color */
X			{	color[color_number++] = make_entry( new );
X			}
X		}
X	}
X}
X
Xload_standard( act )
X	ColorDef	*act;
X{
XXColor		exact_def,screen_def;
X
X	if (XLookupColor( display, DefaultColormapOfScreen(screen), act->name,
X		&exact_def, &screen_def ))
X	{	act->r = exact_def.red   >> 8;
X		act->g = exact_def.green >> 8;
X		act->b = exact_def.blue  >> 8;
X	}
X	new_color( act );
X}
X		
X/*----------------------------------------------------------------------------*/
X
Xupdate_map()
X/* sets unused pixels in my_map to the colors (with different intensity)
X * of the DefaultColormap.
X */
X{
XXColor	qcols[MAX_CELLS];
Xint	i, j;
X
X	j=0;
X	for (i=0;i<cells;i++)
X	{	if (my_pixel[i]==0)	qcols[j++].pixel=i;
X	}
X	XQueryColors( display, DefaultColormapOfScreen(screen), qcols, j );
X	for (i=0;i<j;i++)
X	{	qcols[i].red   = ((long)qcols[i].red  *darkness)/100;
X		qcols[i].green = ((long)qcols[i].green*darkness)/100;
X		qcols[i].blue  = ((long)qcols[i].blue *darkness)/100;
X		qcols[i].flags = DoRed | DoGreen | DoBlue;
X	}
X	XStoreColors( display, my_map, qcols, j );
X}
X
Xcreate_new_map()
X/* get an own colormap */
X{
Xint		i;
XXColor		qcols[MAX_CELLS];
Xunsigned long	pixel[MAX_CELLS];
X
X/* allocate new colormap and copy the darkened colors of the default-map */
X	my_map = XCreateColormap( display, mw, 
X			XDefaultVisualOfScreen(screen), AllocAll);
X	if (my_map==(Colormap)0)
X	{	fprintf(stderr, "can't create colormap.\n" );
X		exit(0);
X	}
X	memset( (char *)my_pixel, (char)0, sizeof(my_pixel) );
X
X/* copy the default-map */
X	for (i=0;i<cells;i++)	qcols[i].pixel = i;
X	XQueryColors( display, DefaultColormapOfScreen(screen), qcols, cells );
X	for (i=0;i<cells;i++)
X	{	qcols[i].red   = ((long)qcols[i].red  *darkness)/100;
X		qcols[i].green = ((long)qcols[i].green*darkness)/100;
X		qcols[i].blue  = ((long)qcols[i].blue *darkness)/100;
X		qcols[i].flags = DoRed | DoGreen | DoBlue;
X	}
X	XStoreColors( display, my_map, qcols, cells );
X
X/* try to allocate the color_cells in the default-map */
X	if (XAllocColorCells( display, DefaultColormapOfScreen(screen), True, 
X		NULL, 0, pixel, color_number ))
X	{	int	high_value=0;
X
X    /* store the colors into my map and into and into the default-colormap
X     * as there are enough cells for both.
X     */
X		for (i=0;i<color_number;i++)
X		{	qcols[i].pixel = pixel[i];
X			qcols[i].flags = DoRed | DoGreen | DoBlue;
X			qcols[i].red   = color[i]->r << 8;
X			qcols[i].green = color[i]->g << 8;
X			qcols[i].blue  = color[i]->b << 8;
X			color[i]->pixel = pixel[i];
X			if (pixel[i]>=cells)
X			{	high_value=1;
X				break;
X			}
X			my_pixel[pixel[i]]=1;
X		}
X
X		if (high_value)
X		{	XFreeColors( display, DefaultColormapOfScreen(screen), 
X				pixel, color_number, 0 );
X			only_mine = 1;
X		}
X		else
X		{
X			XStoreColors( display, DefaultColormapOfScreen(screen), qcols, color_number );
X			XStoreColors( display, my_map, qcols, color_number );
X			only_mine = 0;
X		}
X	}
X	else	only_mine = 1;
X
X	if (only_mine)
X	{
X    /* pixels are just used from high to low numbers */
X		for (i=0;i<color_number;i++)
X		{
X			qcols[i].pixel = cells-i-1;
X			qcols[i].flags = DoRed | DoGreen | DoBlue;
X			qcols[i].red   = color[i]->r << 8;
X			qcols[i].green = color[i]->g << 8;
X			qcols[i].blue  = color[i]->b << 8;
X			color[i]->pixel = cells-i-1;
X			my_pixel[cells-i-1]=1;
X		}
X		XStoreColors( display, my_map, qcols, color_number );
X
X    /* afterwards, all free pixels of the default-map are allocated
X     * and set to the values of the new colormap.
X     */
X		i=0;
X		while( XAllocColorCells( display, DefaultColormapOfScreen(screen), True, 
X			NULL, 0, &pixel[i], 1 ) )
X		{	qcols[i].pixel = pixel[i];
X			i++;
X		}
X		XQueryColors( display, my_map, qcols, i );
X		XStoreColors( display, DefaultColormapOfScreen(screen), qcols, i );
X		XFreeColors( display, DefaultColormapOfScreen(screen), pixel, i, 0 );
X		only_mine = 1;
X	}
X
X/* the pixels for black, white have to be used from my_map, since
X * the entries of the DefaultColormap are possibly darkened.
X */
X	black = find_color( BLACK_STRING )->pixel;
X	my_pixel[black]++;
X	white = find_color( WHITE_STRING )->pixel;
X	my_pixel[white]++;
X	grey  = find_color( GREY_STRING )->pixel;
X	my_pixel[grey]++;
X}
X
Xdestroy_colormap()
X/* not used */
X{
Xunsigned long	pixel[MAX_CELLS];
Xint	i, j;
XColorDef *assoc, *erg;
X
X	XFreeColormap( display, my_map );
X	j=0;
X	if (!only_mine)
X	{	for (i=0;i<cells;i++)
X		{	if (my_pixel[i])	pixel[j++] = i;
X		}
X		XFreeColors( display, DefaultColormapOfScreen(screen), pixel, j, 0 );
X	}
X	my_map = NULL;
X	memset( (char *)my_pixel, (char)0, sizeof(my_pixel) );
X
X	for (i=0;i<color_number;i++)
X	{	erg = color[i];
X		do
X		{	erg->pixel = NotAllocated;
X			assoc = erg->associated;
X			while( assoc )
X			{	assoc->pixel = NotAllocated;
X				assoc = assoc->associated;
X			}
X			erg = erg->brother;
X		}
X		while (erg);
X	}
X}
X
X
END_OF_xcol.part1
if test 24317 -ne `wc -c <xcol.part1`; then
    echo shar: \"xcol.part1\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
# additional concatenation of splitted file
if test -f xcol.part2 ; then 
  echo '      concatenation of "xcol.part1" and "xcol.part2" to "xcol.c".'
  cat xcol.part1 xcol.part2 > xcol.c
  echo '      removing "xcol.part1" and "xcol.part2".'
  rm xcol.part1 xcol.part2
else
  echo '      unpack the second part now.'
fi
exit 0

dan
-----------------------------------------------------------
		    O'Reilly && Associates
		argv@sun.com / argv@ora.com
	   632 Petaluma Ave, Sebastopol, CA 95472 
     800-338-NUTS, in CA: 800-533-NUTS, FAX 707-829-0104
    Opinions expressed reflect those of the author only.