* gpgsm/t-encrypt.c (main): Add a simple option parser and allow
[gpgme.git] / gpgme / debug.c
1 /* debug.c - helpful output in desperate situations
2  *      Copyright (C) 2001, 2002 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 #ifndef HAVE_DOSISH_SYSTEM
29   #include <sys/types.h>
30   #include <sys/stat.h>
31   #include <fcntl.h>
32 #endif
33 #include <assert.h>
34
35 #include "util.h"
36 #include "sema.h"
37
38 \f
39 /* Lock to serialize initialization of the debug output subsystem and
40    output of actual debug messages.  */
41 DEFINE_STATIC_LOCK (debug_lock);
42
43 /* The amount of detail requested by the user, per environment
44    variable GPGME_DEBUG.  */
45 static int debug_level;
46
47 /* The output stream for the debug messages.  */
48 static FILE *errfp;
49
50 \f
51 /* Remove leading and trailing white spaces.  */
52 static char *
53 trim_spaces (char *str)
54 {
55   char *string, *p, *mark;
56
57   string = str;
58   /* Find first non space character.  */
59   for (p = string; *p && isspace (*(byte *) p); p++)
60     ;
61   /* Move characters.  */
62   for (mark = NULL; (*string = *p); string++, p++)
63     if (isspace (*(byte *) p))
64       {
65         if (!mark)
66           mark = string;
67       }
68     else
69       mark = NULL;
70   if (mark)
71     *mark = '\0';       /* Remove trailing spaces.  */
72
73   return str;
74 }
75
76
77 static void
78 debug_init (void)
79 {
80   static int initialized;
81
82   LOCK (debug_lock);
83   if (!initialized)
84     {
85       const char *e = getenv ("GPGME_DEBUG");
86       const char *s1, *s2;;
87
88       initialized = 1;
89       errfp = stderr;
90       if (e)
91         {
92           debug_level = atoi (e);
93           s1 = strchr (e, ':');
94           if (s1)
95             {
96 #ifndef HAVE_DOSISH_SYSTEM
97               if (getuid () == geteuid ())
98                 {
99 #endif
100                   char *p;
101                   FILE *fp;
102
103                   s1++;
104                   if (!(s2 = strchr (s1, ':')))
105                     s2 = s1 + strlen (s1);
106                   p = xtrymalloc (s2 - s1 + 1);
107                   if (p)
108                     {
109                       memcpy (p, s1, s2 - s1);
110                       p[s2-s1] = 0;
111                       trim_spaces (p);
112                       fp = fopen (p,"a");
113                       if (fp)
114                         {
115                           setvbuf (fp, NULL, _IOLBF, 0);
116                           errfp = fp;
117                         }
118                       xfree (p);
119                     }
120 #ifndef HAVE_DOSISH_SYSTEM
121                 }
122 #endif
123             }
124         }
125
126       if (debug_level > 0)
127         fprintf (errfp, "gpgme_debug: level=%d\n", debug_level);
128     }
129   UNLOCK (debug_lock);
130 }
131
132 \f
133 /* Log the formatted string FORMAT at debug level LEVEL or higher.  */
134 void
135 _gpgme_debug (int level, const char *format, ...)
136 {
137   va_list arg_ptr;
138
139   debug_init ();
140   if (debug_level < level)
141     return;
142     
143   va_start (arg_ptr, format);
144   LOCK (debug_lock);
145   vfprintf (errfp, format, arg_ptr);
146   va_end (arg_ptr);
147   if(format && *format && format[strlen (format) - 1] != '\n')
148     putc ('\n', errfp);
149   UNLOCK (debug_lock);
150   fflush (errfp);
151 }
152
153
154 /* Start a new debug line in *LINE, logged at level LEVEL or higher,
155    and starting with the formatted string FORMAT.  */
156 void
157 _gpgme_debug_begin (void **line, int level, const char *format, ...)
158 {
159   va_list arg_ptr;
160
161   debug_init ();
162   if (debug_level < level)
163     {
164       /* Disable logging of this line.  */
165       *line = NULL;
166       return;
167     }
168
169   va_start (arg_ptr, format);
170   vasprintf ((char **) line, format, arg_ptr);
171   va_end (arg_ptr);
172 }
173
174
175 /* Add the formatted string FORMAT to the debug line *LINE.  */
176 void
177 _gpgme_debug_add (void **line, const char *format, ...)
178 {
179   va_list arg_ptr;
180   char *toadd;
181   char *result;
182
183   if (!line)
184     return;
185
186   va_start (arg_ptr, format);
187   vasprintf (&toadd, format, arg_ptr);
188   va_end (arg_ptr);
189   asprintf (&result, "%s%s", *(char **) line, toadd);
190   free (*line);
191   free (toadd);
192   *line = result;
193 }
194
195
196 /* Finish construction of *LINE and send it to the debug output
197    stream.  */
198 void
199 _gpgme_debug_end (void **line)
200 {
201   if (!line)
202     return;
203
204   /* The smallest possible level is 1, so force logging here by
205      using that.  */
206   _gpgme_debug (1, "%s", *line);
207   free (*line);
208   *line = NULL;
209 }