Signed vs. unsigned fixes from Joerg Mayer.
[obnox/wireshark/wip.git] / gtk / colors.c
1 /* colors.c
2  * Definitions for color structures and routines
3  *
4  * $Id: colors.c,v 1.9 2001/04/24 00:28:21 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <gtk/gtk.h>
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35
36 #include <errno.h>
37
38 #ifdef HAVE_SYS_TYPES_H
39 #include <sys/types.h>
40 #endif
41
42 #include <epan.h>
43 #include <epan/filesystem.h>
44 #include "gtk/main.h"
45 #include "packet.h"
46 #include "colors.h"
47 #include "file.h"
48 #include "dfilter/dfilter.h"
49 #include "simple_dialog.h"
50
51 extern capture_file cf;
52
53 static gboolean read_filters(colfilter *filter);
54
55 GSList *filter_list;
56
57 static GdkColormap*     sys_cmap;
58 static GdkColormap*     our_cmap = NULL;
59
60 GdkColor        WHITE = { 0, 65535, 65535, 65535 };
61 GdkColor        BLACK = { 0, 0, 0, 0 };
62
63 /* This structure is used to allow you to compile in default colors if
64  * you wish.  They can be later changed by a user.
65  */
66 #ifdef READ_DEFAULT_COLOR_LIST
67 struct _default_colors {
68         gchar* proto;
69         gchar* color; /* background only */
70 } default_colors[]  = {
71         {"arp", "green2"},
72         {"ip",  "light red"},
73         {"tcp",  "light blue"}
74 };
75 #endif
76
77 colfilter *
78 colfilter_new(void)
79 {
80   colfilter *filter;
81   gboolean got_white, got_black;
82 #ifdef READ_DEFAULT_COLOR_LIST
83   color_filter_t *colorf;
84   gint i;
85   GdkColor color;
86 #endif
87
88   filter = (colfilter *)g_malloc(sizeof(colfilter));
89   filter->num_of_filters = 0;
90
91   sys_cmap = gdk_colormap_get_system();
92
93   /* Allocate "constant" colors. */
94   got_white = get_color(&WHITE);
95   got_black = get_color(&BLACK);
96
97   /* Got milk? */
98   if (!got_white) {
99     if (!got_black)
100       simple_dialog(ESD_TYPE_WARN, NULL, "Could not allocate colors black or white.");
101     else
102       simple_dialog(ESD_TYPE_WARN, NULL, "Could not allocate color white.");
103   } else {
104     if (!got_black)
105       simple_dialog(ESD_TYPE_WARN, NULL, "Could not allocate color black.");
106   }
107
108 #ifdef READ_DEFAULT_COLOR_LIST
109   /* Now process defaults */
110   for (i = 0 ; i < sizeof default_colors/sizeof (struct _default_colors); i++){
111         gdk_color_parse(default_colors[i].color, &color);
112         
113         if( !get_color(&color)){
114                 /* oops */
115                 simple_dialog(ESD_TYPE_WARN, NULL, "Could not allocate color %s.",
116                     default_colors[i].color);
117         }
118
119         colorf = new_color_filter(filter, default_colors[i].proto,
120             default_colors[i].proto);
121         colorf->bg_color = color;
122
123         if (!dfilter_compile(default_colors[i].proto,
124             &colorf->c_colorfilter)) {
125                 simple_dialog(ESD_TYPE_WARN, NULL,
126                   "Cannot compile default color filter %s.\n%s",
127                   default_colors[i].proto, dfilter_error_msg);
128                 /* should reject this filter */
129         }
130         filter->num_of_filters++;
131   }
132 #endif
133   read_filters(filter);
134   return filter;
135 }
136
137 color_filter_t *
138 new_color_filter(colfilter *filters, gchar *name, gchar *filter_string)
139 {
140         color_filter_t *colorf;
141
142         colorf = (color_filter_t *)g_malloc(sizeof (color_filter_t));
143         colorf->filter_name = g_strdup(name);
144         colorf->filter_text = g_strdup(filter_string);
145         colorf->bg_color = WHITE;
146         colorf->fg_color = BLACK;
147         colorf->c_colorfilter = NULL;
148         colorf->edit_dialog = NULL;
149         filter_list = g_slist_append(filter_list, colorf);
150         return colorf;
151 }
152
153 void
154 delete_color_filter(color_filter_t *colorf)
155 {
156         if (colorf->filter_name != NULL)
157           g_free(colorf->filter_name);
158         if (colorf->filter_text != NULL)
159           g_free(colorf->filter_text);
160         if (colorf->c_colorfilter != NULL)
161           dfilter_free(colorf->c_colorfilter);
162         filter_list = g_slist_remove(filter_list, colorf);
163         g_free(colorf);
164 }
165
166 static gboolean
167 read_filters(colfilter *filter)
168 {
169         /* TODO: Lots more syntax checking on the file */
170         /* I hate these fixed length names! TODO: make more dynamic */
171         /* XXX - buffer overflow possibility here */
172         gchar name[256],filter_exp[256], buf[1024];
173         guint16 fg_r, fg_g, fg_b, bg_r, bg_g, bg_b;
174         GdkColor fg_color, bg_color;
175         color_filter_t *colorf;
176         int i;
177         FILE *f;
178         gchar *path;
179         gchar *fname = PF_DIR "/colorfilters";
180         dfilter_t *temp_dfilter;
181
182         /* decide what file to open (from dfilter code) */
183
184         /* should only be called by colors_init.
185          */
186         if(filter == NULL)
187                 return FALSE;
188         /* we have a clist */
189
190         path = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(fname) +  4);
191         sprintf(path, "%s/%s", get_home_dir(), fname);
192
193         if ((f = fopen(path, "r")) == NULL) {
194           if (errno != ENOENT) {
195             simple_dialog(ESD_TYPE_CRIT, NULL,
196               "Could not open filter file\n\"%s\": %s.", path,
197               strerror(errno));
198           }
199           g_free(path);
200           return FALSE;
201         }
202         g_free(path);
203
204         i = 0;
205
206         do{
207           if(!fgets(buf,sizeof buf, f))
208                 break;
209                 
210           if(strspn( buf," \t") == (size_t)((strchr(buf,'*') - buf))){
211                 /* leading # comment */
212                 continue;
213           }
214
215           /* we get the @ delimiter.  It is not in any strings */
216           if(sscanf(buf," @%[^@]@%[^@]@[%hu,%hu,%hu][%hu,%hu,%hu]",
217                 name, filter_exp, &bg_r, &bg_g, &bg_b, &fg_r, &fg_g, &fg_b) == 8){
218                 /* we got a filter */
219
220             if(!dfilter_compile(filter_exp, &temp_dfilter)) {
221                 simple_dialog(ESD_TYPE_CRIT, NULL,
222                  "Could not compile color filter %s from saved filters.\n%s",
223                  name, dfilter_error_msg);
224                 continue;
225             }
226             colorf = new_color_filter(filter, name, filter_exp);
227             colorf->c_colorfilter = temp_dfilter;
228             filter->num_of_filters++;
229             fg_color.red = fg_r;
230             fg_color.green = fg_g;
231             fg_color.blue = fg_b;
232             bg_color.red = bg_r;
233             bg_color.green = bg_g;
234             bg_color.blue = bg_b;
235             if( !get_color(&fg_color)){
236                 /* oops */
237                 simple_dialog(ESD_TYPE_WARN, NULL, "Could not allocate fg color specified"
238                   "in input file for %s.", name);
239
240                 i++;
241                 continue;
242             }
243             if( !get_color(&bg_color)){
244                 /* oops */
245                 simple_dialog(ESD_TYPE_WARN, NULL, "Could not allocate bg color specified"
246                   "in input file for %s.", name);
247                 i++;
248                 continue;
249             }
250
251             colorf->bg_color = bg_color;
252             colorf->fg_color = fg_color;
253             i++;
254           }    /* if sscanf */
255         } while( !feof(f));
256         return TRUE;
257 }
258
259 static void
260 write_filter(gpointer filter_arg, gpointer file_arg)
261 {
262         color_filter_t *colorf = filter_arg;
263         FILE *f = file_arg;
264
265         fprintf(f,"@%s@%s@[%d,%d,%d][%d,%d,%d]\n",
266             colorf->filter_name,
267             colorf->filter_text,
268             colorf->bg_color.red,
269             colorf->bg_color.green,
270             colorf->bg_color.blue,
271             colorf->fg_color.red,
272             colorf->fg_color.green,
273             colorf->fg_color.blue);
274 }
275         
276 gboolean
277 write_filters(colfilter *filter)
278 {
279         FILE *f;
280         gchar *path;
281         gchar *name = PF_DIR "/colorfilters";
282         /* decide what file to open (from dfilter code) */
283         path = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(name) +  4);
284         sprintf(path, "%s/%s", get_home_dir(), name);
285
286         if ((f = fopen(path, "w+")) == NULL) {
287           simple_dialog(ESD_TYPE_CRIT, NULL,
288                 "Could not open\n%s\nfor writing: %s.",
289                 path, strerror(errno));
290           g_free(path);
291           return FALSE;
292         }
293         fprintf(f,"# DO NOT EDIT THIS FILE!  It was created by Ethereal\n");
294         g_slist_foreach(filter_list, write_filter, f);
295         fclose(f);
296         g_free(path);
297         return TRUE;
298 }
299
300 gboolean
301 get_color (GdkColor *new_color)
302 {
303     GdkVisual *pv;
304
305     if (!our_cmap) {
306         if ( !gdk_colormap_alloc_color (sys_cmap, new_color, FALSE, TRUE)) {
307             pv = gdk_visual_get_best();
308             if ( !(our_cmap = gdk_colormap_new(pv, TRUE)))
309                 simple_dialog(ESD_TYPE_WARN, NULL, "Could not create new colormap");
310         } else
311             return (TRUE);
312     }
313     return ( gdk_colormap_alloc_color ( our_cmap, new_color, FALSE, TRUE) );
314 }