~noskcaj/ubuntu/trusty/gpgme1.0/1.4.3

« back to all changes in this revision

Viewing changes to gpgme/version.c

  • Committer: Bazaar Package Importer
  • Author(s): Jose Carlos Garcia Sogo
  • Date: 2004-11-16 21:36:40 UTC
  • Revision ID: james.westby@ubuntu.com-20041116213640-6ffmegu7bqe05u7l
Tags: upstream-1.0.1
ImportĀ upstreamĀ versionĀ 1.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* version.c - Version check routines.
 
2
   Copyright (C) 2000 Werner Koch (dd9jn)
 
3
   Copyright (C) 2001, 2002, 2003 g10 Code GmbH
 
4
 
 
5
   This file is part of GPGME.
 
6
 
 
7
   GPGME is free software; you can redistribute it and/or modify it
 
8
   under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 2 of the License, or
 
10
   (at your option) any later version.
 
11
 
 
12
   GPGME is distributed in the hope that it will be useful, but
 
13
   WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
   General Public License for more details.
 
16
 
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with GPGME; if not, write to the Free Software Foundation,
 
19
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
20
 
 
21
#if HAVE_CONFIG_H
 
22
#include <config.h>
 
23
#endif
 
24
#include <string.h>
 
25
#include <limits.h>
 
26
#include <ctype.h>
 
27
 
 
28
#include "gpgme.h"
 
29
#include "io.h"
 
30
 
 
31
/* For _gpgme_sema_subsystem_init ().  */
 
32
#include "sema.h"
 
33
 
 
34
 
 
35
/* Bootstrap the subsystems needed for concurrent operation.  This
 
36
   must be done once at startup.  We can not guarantee this using a
 
37
   lock, though, because the semaphore subsystem needs to be
 
38
   initialized itself before it can be used.  So we expect that the
 
39
   user performs the necessary syncrhonization.  */
 
40
static void
 
41
do_subsystem_inits (void)
 
42
{
 
43
  static int done = 0;
 
44
 
 
45
  if (done)
 
46
    return;
 
47
 
 
48
  _gpgme_sema_subsystem_init ();
 
49
  _gpgme_io_subsystem_init ();
 
50
 
 
51
  done = 1;
 
52
}
 
53
 
 
54
 
 
55
/* Read the next number in the version string STR and return it in
 
56
   *NUMBER.  Return a pointer to the tail of STR after parsing, or
 
57
   *NULL if the version string was invalid.  */
 
58
static const char *
 
59
parse_version_number (const char *str, int *number)
 
60
{
 
61
#define MAXVAL ((INT_MAX - 10) / 10)
 
62
  int val = 0;
 
63
 
 
64
  /* Leading zeros are not allowed.  */
 
65
  if (*str == '0' && isdigit(str[1]))
 
66
    return NULL;
 
67
 
 
68
  while (isdigit (*str) && val <= MAXVAL)
 
69
    {
 
70
      val *= 10;
 
71
      val += *(str++) - '0';
 
72
    }
 
73
  *number = val;
 
74
  return val > MAXVAL ? NULL : str;
 
75
}
 
76
 
 
77
 
 
78
/* Parse the version string STR in the format MAJOR.MINOR.MICRO (for
 
79
   example, 9.3.2) and return the components in MAJOR, MINOR and MICRO
 
80
   as integers.  The function returns the tail of the string that
 
81
   follows the version number.  This might be te empty string if there
 
82
   is nothing following the version number, or a patchlevel.  The
 
83
   function returns NULL if the version string is not valid.  */
 
84
static const char *
 
85
parse_version_string (const char *str, int *major, int *minor, int *micro)
 
86
{
 
87
  str = parse_version_number (str, major);
 
88
  if (!str || *str != '.')
 
89
    return NULL;
 
90
  str++;
 
91
 
 
92
  str = parse_version_number (str, minor);
 
93
  if (!str || *str != '.')
 
94
    return NULL;
 
95
  str++;
 
96
 
 
97
  str = parse_version_number (str, micro);
 
98
  if (!str)
 
99
    return NULL;
 
100
 
 
101
  /* A patchlevel might follow.  */
 
102
  return str;
 
103
}
 
104
 
 
105
 
 
106
const char *
 
107
_gpgme_compare_versions (const char *my_version,
 
108
                         const char *rq_version)
 
109
{
 
110
  int my_major, my_minor, my_micro;
 
111
  int rq_major, rq_minor, rq_micro;
 
112
  const char *my_plvl, *rq_plvl;
 
113
 
 
114
  if (!rq_version)
 
115
    return my_version;
 
116
  if (!my_version)
 
117
    return NULL;
 
118
 
 
119
  my_plvl = parse_version_string (my_version, &my_major, &my_minor, &my_micro);
 
120
  if (!my_plvl)
 
121
    return NULL;
 
122
 
 
123
  rq_plvl = parse_version_string (rq_version, &rq_major, &rq_minor, &rq_micro);
 
124
  if (!rq_plvl)
 
125
    return NULL;
 
126
 
 
127
  if (my_major > rq_major
 
128
      || (my_major == rq_major && my_minor > rq_minor)
 
129
      || (my_major == rq_major && my_minor == rq_minor 
 
130
          && my_micro > rq_micro)
 
131
      || (my_major == rq_major && my_minor == rq_minor
 
132
          && my_micro == rq_micro && strcmp (my_plvl, rq_plvl) >= 0))
 
133
    return my_version;
 
134
 
 
135
  return NULL;
 
136
}
 
137
 
 
138
 
 
139
/* Check that the the version of the library is at minimum the
 
140
   requested one and return the version string; return NULL if the
 
141
   condition is not met.  If a NULL is passed to this function, no
 
142
   check is done and the version string is simply returned.
 
143
 
 
144
   This function must be run once at startup, as it also initializes
 
145
   some subsystems.  Its invocation must be synchronized against
 
146
   calling any of the other functions in a multi-threaded
 
147
   environments.  */
 
148
const char *
 
149
gpgme_check_version (const char *req_version)
 
150
{
 
151
  do_subsystem_inits ();
 
152
  return _gpgme_compare_versions (VERSION, req_version);
 
153
}
 
154
 
 
155
 
 
156
#define LINELENGTH 80
 
157
 
 
158
/* Retrieve the version number from the --version output of the
 
159
   program FILE_NAME.  */
 
160
char *
 
161
_gpgme_get_program_version (const char *const file_name)
 
162
{
 
163
  char line[LINELENGTH] = "";
 
164
  int linelen = 0;
 
165
  char *mark = NULL;
 
166
  int rp[2];
 
167
  int nread;
 
168
  char *argv[] = {NULL /* file_name */, "--version", 0};
 
169
  struct spawn_fd_item_s pfd[] = { {0, -1}, {-1, -1} };
 
170
  struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */}, {-1, -1} };
 
171
  int status;
 
172
 
 
173
  if (!file_name)
 
174
    return NULL;
 
175
  argv[0] = (char *) file_name;
 
176
 
 
177
  if (_gpgme_io_pipe (rp, 1) < 0)
 
178
    return NULL;
 
179
 
 
180
  pfd[0].fd = rp[1];
 
181
  cfd[0].fd = rp[1];
 
182
 
 
183
  status = _gpgme_io_spawn (file_name, argv, cfd, pfd);
 
184
  if (status < 0)
 
185
    {
 
186
      _gpgme_io_close (rp[0]);
 
187
      _gpgme_io_close (rp[1]);
 
188
      return NULL;
 
189
    }
 
190
 
 
191
  do
 
192
    {
 
193
      nread = _gpgme_io_read (rp[0], &line[linelen], LINELENGTH - linelen - 1);
 
194
      if (nread > 0)
 
195
        {
 
196
          line[linelen + nread] = '\0';
 
197
          mark = strchr (&line[linelen], '\n');
 
198
          if (mark)
 
199
            {
 
200
              *mark = '\0';
 
201
              break;
 
202
            }
 
203
          linelen += nread;
 
204
        }
 
205
    }
 
206
  while (nread > 0 && linelen < LINELENGTH - 1);
 
207
 
 
208
  _gpgme_io_close (rp[0]);
 
209
 
 
210
  if (mark)
 
211
    {
 
212
      mark = strrchr (line, ' ');
 
213
      if (!mark)
 
214
        return NULL;
 
215
      return strdup (mark + 1);
 
216
    }
 
217
 
 
218
  return NULL;
 
219
}