~ubuntu-branches/ubuntu/intrepid/gsmlib/intrepid

« back to all changes in this revision

Viewing changes to gsmlib/gsm_util.cc

  • Committer: Bazaar Package Importer
  • Author(s): Mikael Hedin
  • Date: 2002-01-24 12:59:07 UTC
  • Revision ID: james.westby@ubuntu.com-20020124125907-b7qkpokx5283jdpu
Tags: upstream-1.8
Import upstream version 1.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// *************************************************************************
 
2
// * GSM TA/ME library
 
3
// *
 
4
// * File:    gsm_util.h
 
5
// *
 
6
// * Purpose: Various utilities
 
7
// *
 
8
// * Author:  Peter Hofmann (software@pxh.de)
 
9
// *
 
10
// * Created: 4.5.1999
 
11
// *************************************************************************
 
12
 
 
13
#ifdef HAVE_CONFIG_H
 
14
#include <gsm_config.h>
 
15
#endif
 
16
#include <gsmlib/gsm_nls.h>
 
17
#include <gsmlib/gsm_util.h>
 
18
#include <gsmlib/gsm_sysdep.h>
 
19
#include <sys/stat.h>
 
20
#include <assert.h>
 
21
#include <string.h>
 
22
#include <iostream>
 
23
#include <strstream>
 
24
#include <ctype.h>
 
25
#include <errno.h>
 
26
#if !defined(HAVE_CONFIG_H) || defined(HAVE_UNISTD_H)
 
27
#include <unistd.h>
 
28
#endif
 
29
#if !defined(HAVE_CONFIG_H) || defined(HAVE_MALLOC_H)
 
30
#include <malloc.h>
 
31
#endif
 
32
#include <stdarg.h>
 
33
#ifdef HAVE_VSNPRINTF
 
34
// switch on vsnprintf() prototype in stdio.h
 
35
#define __USE_GNU
 
36
#define _GNU_SOURCE
 
37
#endif
 
38
#include <stdio.h>
 
39
#include <sys/stat.h>
 
40
 
 
41
using namespace std;
 
42
using namespace gsmlib;
 
43
 
 
44
// Latin-1 undefined character (code 172 (Latin-1 boolean not, "�"))
 
45
const int NOP = 172;
 
46
 
 
47
// GSM undefined character (code 16 (GSM Delta))
 
48
const int GSM_NOP = 16;
 
49
 
 
50
// conversion tables, Latin1 to GSM and GSM to Latin1
 
51
 
 
52
static unsigned char gsmToLatin1Table[] =
 
53
{
 
54
  //  0 '@', '�', '$', '�', '�', '�', '�', '�', 
 
55
        '@', 163, '$', 165, 232, 233, 249, 236,
 
56
  //  8 '�', '�',  LF, '�', '�',  CR, '�', '�', 
 
57
        242, 199,  10, 216, 248,  13, 197, 229,
 
58
  // 16 '�', '_', '�', '�', '�', '�', '�', '�',
 
59
        NOP, '_', NOP, NOP, NOP, NOP, NOP, NOP, 
 
60
  // 24 '�', '�', '�', '�', '�', '�', '�', '�',
 
61
        NOP, NOP, NOP, NOP, 198, 230, 223, 201, 
 
62
  // 32 ' ', '!', '"', '#', '�', '%', '&', ''',
 
63
        ' ', '!', '"', '#', 164, '%', '&', '\'',
 
64
  // 40 '(', ')', '*', '+', ',', '-', '.', '/',
 
65
        '(', ')', '*', '+', ',', '-', '.', '/',
 
66
  // 48 '0', '1', '2', '3', '4', '5', '6', '7',
 
67
         '0', '1', '2', '3', '4', '5', '6', '7',
 
68
  // 56 '8', '9', ':', ';', '<', '=', '>', '?', 
 
69
        '8', '9', ':', ';', '<', '=', '>', '?', 
 
70
  // 64 '�', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 
 
71
        161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 
 
72
  // 72 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 
 
73
        'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
 
74
  // 80 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
 
75
         'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
 
76
  // 88 'X', 'Y', 'Z', '�', '�', '�', '�', '�', 
 
77
        'X', 'Y', 'Z', 196, 214, 209, 220, 167,
 
78
  // 96 '�', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
 
79
        191, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
 
80
  // 104 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 
 
81
         'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 
 
82
  // 112 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 
 
83
         'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 
 
84
  // 120 'x', 'y', 'z', '�', '�', '�', '�', '�', 
 
85
         'x', 'y', 'z', 228, 246, 241, 252, 224
 
86
};
 
87
 
 
88
static unsigned char latin1ToGsmTable[256];
 
89
 
 
90
static class Latin1ToGsmTableInit
 
91
{
 
92
public:
 
93
  Latin1ToGsmTableInit()
 
94
  {
 
95
    memset((void*)latin1ToGsmTable, GSM_NOP, 256);
 
96
    for (int i = 0; i < 128; i++)
 
97
      if (gsmToLatin1Table[i] != NOP)
 
98
        latin1ToGsmTable[gsmToLatin1Table[i]] = i;
 
99
  }
 
100
} latin1ToGsmTableInit;
 
101
 
 
102
string gsmlib::gsmToLatin1(string s)
 
103
{
 
104
  string result(s.length(), 0);
 
105
  for (string::size_type i = 0; i < s.length(); i++)
 
106
    result[i] = (unsigned char)s[i] > 127 ? NOP : gsmToLatin1Table[s[i]];
 
107
  return result;
 
108
}
 
109
 
 
110
string gsmlib::latin1ToGsm(string s)
 
111
{
 
112
  string result(s.length(), 0);
 
113
  for (string::size_type i = 0; i < s.length(); i++)
 
114
    result[i] = latin1ToGsmTable[(unsigned char)s[i]];
 
115
  return result;
 
116
}
 
117
 
 
118
static unsigned char byteToHex[] =
 
119
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 
120
 'A', 'B', 'C', 'D', 'E', 'F'};
 
121
 
 
122
string gsmlib::bufToHex(const unsigned char *buf, unsigned long length)
 
123
{
 
124
  const unsigned char *bb = buf;
 
125
  string result;
 
126
  result.reserve(length * 2);
 
127
 
 
128
  for (unsigned long i = 0; i < length; ++i)
 
129
  {
 
130
    result += byteToHex[*bb >> 4];
 
131
    result += byteToHex[*bb++ & 0xf];
 
132
  }
 
133
  return result;
 
134
}
 
135
 
 
136
bool gsmlib::hexToBuf(const string &hexString, unsigned char *buf)
 
137
{
 
138
  if (hexString.length() % 2 != 0)
 
139
    return false;
 
140
 
 
141
  unsigned char *bb = buf;
 
142
  for (unsigned int i = 0; i < hexString.length(); i += 2)
 
143
  {
 
144
    unsigned char c = hexString[i];
 
145
    if (! isdigit(c) && ! ('a' <= c && c <= 'f') && ! ('A' <= c && c <= 'F'))
 
146
      return false;
 
147
    *bb = (isdigit(c) ? c - '0' :
 
148
           ((('a' <= c && c <= 'f') ? c - 'a' : c - 'A')) + 10) << 4;
 
149
    c = hexString[i + 1];
 
150
    if (! isdigit(c) && ! ('a' <= c && c <= 'f') && ! ('A' <= c && c <= 'F'))
 
151
      return false;
 
152
    *bb++ |= isdigit(c) ? c - '0' :
 
153
      ((('a' <= c && c <= 'f') ? c - 'a' : c - 'A') + 10);
 
154
  }
 
155
  return true;
 
156
}
 
157
 
 
158
string gsmlib::intToStr(int i)
 
159
{
 
160
  ostrstream os;
 
161
  os << i << ends;
 
162
  char *ss = os.str();
 
163
  string s(ss);
 
164
  delete[] ss;
 
165
  return s;
 
166
}
 
167
 
 
168
string gsmlib::removeWhiteSpace(string s)
 
169
{
 
170
  string result;
 
171
  for (unsigned int i = 0; i < s.length(); ++i)
 
172
    if (! isspace(s[i]))
 
173
      result += s[i];
 
174
  return result;
 
175
}
 
176
 
 
177
#ifdef WIN32
 
178
 
 
179
// helper routine, find out whether filename starts with "COM"
 
180
static bool isCom(string filename)
 
181
{
 
182
  filename = removeWhiteSpace(lowercase(filename));
 
183
  // remove UNC begin
 
184
  if ( filename.compare(0,4,"\\\\.\\") == 0 )
 
185
    filename.erase(0,4);
 
186
  return filename.length() < 3 || filename.substr(0, 3) == "com";
 
187
}
 
188
#endif
 
189
 
 
190
bool gsmlib::isFile(string filename)
 
191
{
 
192
#ifdef WIN32
 
193
  // stat does not work reliably under Win32 to indicate devices
 
194
  if (isCom(filename))
 
195
    return false;
 
196
#endif
 
197
 
 
198
  struct stat statBuf;
 
199
  int retries = 0;
 
200
 
 
201
  while (retries < 10)
 
202
  {
 
203
    if (stat(filename.c_str(), &statBuf) != 0)
 
204
      throw GsmException(
 
205
        stringPrintf(_("error when calling stat('%s') (errno: %d/%s)"), 
 
206
                     filename.c_str(), errno, strerror(errno)),
 
207
        OSError);
 
208
    
 
209
#ifndef WIN32
 
210
    if (S_ISLNK(statBuf.st_mode))
 
211
    {
 
212
      int size = 100;
 
213
      while (1)
 
214
      {
 
215
        char *buffer = (char*)malloc(size);
 
216
        int nchars = readlink(filename.c_str(), buffer, size);
 
217
        if (nchars < size)
 
218
        {
 
219
          filename.assign(buffer, nchars);
 
220
          free(buffer);
 
221
          break;
 
222
        }
 
223
        free(buffer);
 
224
        size *= 2;
 
225
      }
 
226
      ++retries;
 
227
    }
 
228
    else if (S_ISCHR(statBuf.st_mode))
 
229
      return false;
 
230
    else 
 
231
#endif
 
232
    if (S_ISREG(statBuf.st_mode))
 
233
      return true;
 
234
    else
 
235
      throw GsmException(
 
236
        stringPrintf(_("file '%s' is neither file nor character device"),
 
237
                     filename.c_str()),
 
238
        ParameterError);
 
239
  }
 
240
  throw GsmException(_("maxmimum number of symbolic links exceeded"),
 
241
                     ParameterError);
 
242
}
 
243
 
 
244
void gsmlib::renameToBackupFile(string filename) throw(GsmException)
 
245
{
 
246
  string backupFilename = filename + "~";
 
247
  unlink(backupFilename.c_str());
 
248
  if (rename(filename.c_str(), backupFilename.c_str()) < 0)
 
249
    throw GsmException(
 
250
      stringPrintf(_("error renaming '%s' to '%s'"),
 
251
                   filename.c_str(), backupFilename.c_str()),
 
252
      OSError, errno);
 
253
}
 
254
 
 
255
// NoCopy members
 
256
 
 
257
#ifndef NDEBUG
 
258
 
 
259
NoCopy::NoCopy(NoCopy &n)
 
260
{
 
261
  cerr << "ABORT: NoCopy copy constructor used" << endl;
 
262
  abort();
 
263
}
 
264
 
 
265
NoCopy &NoCopy::operator=(NoCopy &n)
 
266
{
 
267
  cerr << "ABORT: NoCopy::operator= used" << endl;
 
268
  abort();
 
269
}
 
270
 
 
271
#endif // NDEBUG
 
272
 
 
273
string gsmlib::lowercase(string s)
 
274
{
 
275
  string result;
 
276
  for (unsigned int i = 0; i < s.length(); ++i)
 
277
    result += tolower(s[i]);
 
278
  return result;
 
279
}
 
280
 
 
281
int gsmlib::checkNumber(string s) throw(GsmException)
 
282
{
 
283
  for (unsigned int i = 0; i < s.length(); ++i)
 
284
    if (! isdigit(s[i]))
 
285
      throw GsmException(stringPrintf(_("expected number, got '%s'"),
 
286
                                      s.c_str()), ParameterError);
 
287
  int result;
 
288
  istrstream is(s.c_str());
 
289
  is >> result;
 
290
  return result;
 
291
}
 
292
 
 
293
#ifdef HAVE_VSNPRINTF
 
294
string gsmlib::stringPrintf(const char *format, ...)
 
295
{
 
296
  va_list args;
 
297
  va_start(args, format);
 
298
  int size = 1024;
 
299
  while (1)
 
300
  {
 
301
    char *buf = (char*)alloca(sizeof(char) * size);
 
302
    int nchars = vsnprintf(buf, size, format, args);
 
303
    if (nchars < size)
 
304
    {
 
305
      va_end(args);
 
306
      return string(buf, nchars);
 
307
    }
 
308
    size *= 2;
 
309
  }
 
310
  return "";
 
311
}
 
312
 
 
313
#else
 
314
char gsmlib::__s[20000];        // buffer for the replacement macro
 
315
#endif // HAVE_VSNPRINTF
 
316
 
 
317
#ifndef NDEBUG
 
318
int gsmlib::debugLevel()
 
319
{
 
320
  char *s = getenv("GSMLIB_DEBUG");
 
321
  if (s == NULL) return 0;
 
322
  return checkNumber(s);
 
323
}
 
324
#endif
 
325
 
 
326
// interrupt interface
 
327
 
 
328
namespace gsmlib
 
329
{
 
330
  static InterruptBase *interruptObject = NULL;
 
331
}
 
332
 
 
333
void gsmlib::setInterruptObject(InterruptBase *intObject)
 
334
{
 
335
  interruptObject = intObject;
 
336
}
 
337
  
 
338
bool gsmlib::interrupted()
 
339
{
 
340
  return interruptObject != NULL && interruptObject->interrupted();
 
341
}
 
342
 
 
343
void gsmlib::checkTextAndTelephone(string text, string telephone)
 
344
  throw(GsmException)
 
345
{
 
346
  if (text.find('"') != string::npos)
 
347
    throw GsmException(
 
348
      stringPrintf(_("text '%s' contains illegal character '\"'"),
 
349
                   text.c_str()),
 
350
      ParameterError);
 
351
 
 
352
  for (unsigned int i = 0; i < telephone.length(); ++i)
 
353
    if (! isdigit(telephone[i]) && ! (telephone[i] == '+') &&
 
354
        ! (telephone[i] == '*') && ! (telephone[i] == '#') &&
 
355
        ! (telephone[i] == 'p') && ! (telephone[i] == 'w') &&
 
356
        ! (telephone[i] == 'P') && ! (telephone[i] == 'W'))
 
357
      throw GsmException(
 
358
        stringPrintf(_("illegal character in telephone number '%s'"),
 
359
                     telephone.c_str()), ParameterError);
 
360
}
 
361
 
 
362
// progress interface
 
363
 
 
364
namespace gsmlib
 
365
{
 
366
  static ProgressBase *progressObject = NULL;
 
367
}
 
368
 
 
369
void gsmlib::setProgressObject(ProgressBase *progObject)
 
370
{
 
371
  progressObject = progObject;
 
372
}
 
373
 
 
374
void gsmlib::reportProgress(int part, int total)
 
375
{
 
376
  if (progressObject != NULL)
 
377
    progressObject->reportProgress(part, total);
 
378
}