Release 0.2.1
[gpgme.git] / gpgme / debug.c
1 /* debug.c
2  *      Copyright (C) 2001 g10 Code GmbH
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <unistd.h>
27 #include <ctype.h>
28 #include <assert.h>
29
30 #include "util.h"
31 #include "sema.h"
32
33 DEFINE_STATIC_LOCK (debug_lock);
34
35 struct debug_control_s {
36     FILE *fp;
37     char fname[100];
38 };
39
40 static int debug_level = 0;
41 static FILE *errfp = NULL;
42
43 /****************
44  * remove leading and trailing white spaces
45  */
46 static char *
47 trim_spaces( char *str )
48 {
49     char *string, *p, *mark;
50
51     string = str;
52     /* find first non space character */
53     for( p=string; *p && isspace( *(byte*)p ) ; p++ )
54         ;
55     /* move characters */
56     for( (mark = NULL); (*string = *p); string++, p++ )
57         if( isspace( *(byte*)p ) ) {
58             if( !mark )
59                 mark = string ;
60         }
61         else
62             mark = NULL ;
63     if( mark )
64         *mark = '\0' ;  /* remove trailing spaces */
65
66     return str ;
67 }
68
69
70 static void
71 debug_init (void)
72 {
73     static volatile int initialized = 0;
74        
75     if (initialized) 
76         return;
77     LOCK (debug_lock);
78     if (!initialized) {
79         const char *e = getenv ("GPGME_DEBUG");
80         const char *s1, *s2;;
81
82         initialized = 1;
83         debug_level = 0;
84         errfp = stderr;
85         if (e) {
86             debug_level = atoi (e);
87             s1 = strchr (e, ':');
88             if (s1 
89 #ifndef HAVE_DOSISH_SYSTEM
90                 && getuid () == geteuid ()
91 #endif
92                 ) {
93                 char *p;
94                 FILE *fp;
95
96                 s1++;
97                 if ( !(s2 = strchr (s1, ':')) )
98                     s2 = s1 + strlen(s1);
99                 p = xtrymalloc (s2-s1+1);
100                 if (p) {
101                     memcpy (p, s1, s2-s1);
102                     p[s2-s1] = 0;
103                     trim_spaces (p);
104                     fp = fopen (p,"a");
105                     if (fp) {
106                         setvbuf (fp, NULL, _IOLBF, 0);
107                         errfp = fp;
108                     }
109                     xfree (p);
110                 }
111             }
112         }
113
114         if (debug_level > 0)
115             fprintf (errfp,"gpgme_debug: level=%d\n", debug_level);
116     }
117     UNLOCK (debug_lock);
118 }
119
120 int
121 _gpgme_debug_level ()
122 {
123     return debug_level;
124 }
125
126 void
127 _gpgme_debug (int level, const char *format, ...)
128 {
129     va_list arg_ptr ;
130
131     debug_init ();
132     if ( debug_level < level )
133         return;
134     
135     va_start ( arg_ptr, format ) ;
136     LOCK (debug_lock);
137     vfprintf (errfp, format, arg_ptr) ;
138     va_end ( arg_ptr ) ;
139     if( format && *format && format[strlen(format)-1] != '\n' )
140         putc ('\n', errfp);
141     UNLOCK (debug_lock);
142     fflush (errfp);
143 }
144
145
146
147 void
148 _gpgme_debug_begin ( void **helper, int level, const char *text)
149 {
150     struct debug_control_s *ctl;
151
152     debug_init ();
153
154     *helper = NULL;
155     if ( debug_level < level )
156         return;
157     ctl = xtrycalloc (1, sizeof *ctl );
158     if (!ctl) {
159         _gpgme_debug (255, __FILE__ ":" STR2(__LINE__)": out of core");
160         return;
161     }
162
163     /* Oh what a pitty that we don't have a asprintf or snprintf under
164      * Windoze.  We definitely should write our own clib for W32! */
165     sprintf ( ctl->fname, "/tmp/gpgme_debug.%d.%p", getpid (), ctl );
166     ctl->fp = fopen (ctl->fname, "w+");
167     if (!ctl->fp) {
168         _gpgme_debug (255,__FILE__ ":" STR2(__LINE__)": failed to create `%s'",
169                       ctl->fname );
170         xfree (ctl);
171         return;
172     }
173     *helper = ctl;
174     _gpgme_debug_add (helper, "%s", text );
175 }
176
177 int
178 _gpgme_debug_enabled (void **helper)
179 {
180     return helper && *helper;
181 }
182
183
184 void
185 _gpgme_debug_add (void **helper, const char *format, ...)
186 {
187     struct debug_control_s *ctl = *helper;
188     va_list arg_ptr ;
189
190     if ( !*helper )
191         return;
192     
193     va_start ( arg_ptr, format ) ;
194     vfprintf (ctl->fp, format, arg_ptr) ;
195     va_end ( arg_ptr ) ;
196 }
197
198 void
199 _gpgme_debug_end (void **helper, const char *text)
200 {
201     struct debug_control_s *ctl = *helper;
202     int c, last_c=EOF;
203
204     if ( !*helper )
205         return;
206     
207     _gpgme_debug_add (helper, "%s", text );
208     fflush (ctl->fp); /* we need this for the buggy Windoze libc */
209     rewind (ctl->fp);
210     LOCK (debug_lock);
211     while ( (c=getc (ctl->fp)) != EOF ) {
212         putc (c, errfp);
213         last_c = c;
214     }
215     if (last_c != '\n')
216         putc ('\n', errfp);
217     UNLOCK (debug_lock);
218     
219     fclose (ctl->fp);
220     remove (ctl->fname);
221     xfree (ctl);
222     *helper = NULL;
223 }
224