Subversion Repositories SvarDOS

Rev

Rev 240 | Rev 251 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
219 mateuszvis 1
/*
225 mateuszvis 2
 * This file is part of pkginst
3
 * Copyright (C) 2012-2021 Mateusz Viste
219 mateuszvis 4
 *
5
 * It contains a few helper function...
6
 */
7
 
8
 
9
#include <ctype.h>    /* tolower() */
240 mateuszvis 10
#include <direct.h>   /* provides the mkdir() prototype */
219 mateuszvis 11
#include <string.h>   /* */
12
#include <stdio.h>    /* sprintf() */
13
#include <stdlib.h>   /* atoi() */
14
#include <sys/stat.h> /* mkdir() */
15
 
248 mateuszvis 16
#include "rtrim.h"
219 mateuszvis 17
#include "helpers.h"
18
 
19
 
20
/* translates a version string into a array of integer values. The array must be 8-position long.
21
   returns 0 if parsing was successful, non-zero otherwise.
22
   Accepted formats follow:
23
    300.12.1
24
    1
25
    12.2.34.2-4.5
26
    1.2c
27
    1.01
28
    2013-12-31   */
29
static int versiontointarr(char *verstr, int *arr) {
30
  int i, vlen, dotcounter = 1, firstcharaftersep = 0;
31
  char *digits[8];
32
  char verstrcopy[16];
33
 
34
  /* fill the array with zeroes first */
35
  for (i = 0; i < 8; i++) arr[i] = 0;
36
 
37
  /* first extensively validate the input */
38
  if (verstr == NULL) return(-1);
39
  vlen = strlen(verstr);
40
  if (vlen == 0) return(-1);
41
  if (vlen > 15) return(-1);
42
  if ((verstr[0] < '0') || (verstr[0] > '9')) return(-1); /* a version string must start with a 0..9 digit */
43
  if ((tolower(verstr[vlen - 1]) >= 'a') && (tolower(verstr[vlen - 1]) <= 'z') && (vlen > 1)) { /* remove any letter from the end, and use it as a (very) minor differenciator */
44
    vlen -= 1;
45
    arr[7] = tolower(verstr[vlen]);
46
  }
47
  if ((verstr[vlen - 1] < '0') || (verstr[vlen - 1] > '9')) return(-1); /* a version string must end with a 0..9 digit */
48
 
49
  digits[0] = verstrcopy;
50
  for (i = 0; i < vlen; i++) {
51
    verstrcopy[i] = verstr[i];
52
    switch (verstr[i]) {
53
      case '.':
54
      case '-':
55
        if (i == 0) return(-1);
56
        if (verstrcopy[i-1] == 0) return(-1); /* do not allow two separators in a row */
57
        if (dotcounter > 6) return(-1);
58
        digits[dotcounter++] = &verstrcopy[i + 1];
59
        verstrcopy[i] = 0;
60
        firstcharaftersep = 1;
61
        break;
62
      case '0':
63
        /* if this is a zero right after a separator, and trailed with a digit
64
         * (as in '1.01'), then enforce a separator first */
65
        if ((firstcharaftersep != 0) && (verstr[i+1] >= '0') && (verstr[i+1] <= '9')) {
66
          if (dotcounter > 6) return(-1);
67
          digits[dotcounter++] = &verstrcopy[i + 1];
68
          verstrcopy[i] = 0;
69
        }
70
        break;
71
      case '1':
72
      case '2':
73
      case '3':
74
      case '4':
75
      case '5':
76
      case '6':
77
      case '7':
78
      case '8':
79
      case '9':
80
        firstcharaftersep = 0;
81
        break;
82
      default: /* do not allow any character different than 0..9 or '.' */
83
        return(-1);
84
        break;
85
    }
86
  }
87
  verstrcopy[i] = 0;
88
  /* now that we know the input is sane, let's process it */
89
  for (i = 0; i < dotcounter; i++) {
90
    int tmpint;
91
    tmpint = atoi(digits[i]);
92
    if ((tmpint < 0) || (tmpint > 32000)) return(-1);
93
    arr[i] = tmpint;
94
  }
95
  return(0);
96
}
97
 
98
 
99
/* compares version strings v1 and v2. Returns 1 if v2 is newer than v1, 0 otherwise, and -1 if comparison is unable to tell */
100
int isversionnewer(char *v1, char *v2) {
101
  int x1[8], x2[8], i;
102
  if ((v1 == NULL) || (v2 == NULL)) return(-1); /* if input is invalid (NULL), don't continue */
103
  if (strcasecmp(v1, v2) == 0) return(0);  /* if both versions are the same, don't continue */
104
  /* check versions of the decimal format 1.23... */
105
  if ((versiontointarr(v1, x1) != 0) || (versiontointarr(v2, x2) != 0)) return(-1);
106
  for (i = 0; i < 8; i++) {
107
    if (x2[i] > x1[i]) return(1);
108
    if (x2[i] < x1[i]) return(0);
109
  }
110
  return(0);
111
}
112
 
113
 
114
/* change all / to \ in a string */
115
void slash2backslash(char *str) {
116
  int x;
117
  for (x = 0; str[x] != 0; x++) {
118
    if (str[x] == '/') str[x] = '\\';
119
  }
120
}
121
 
122
 
123
/* change all \ to / in a string */
124
void backslash2slash(char *str) {
125
  int x;
126
  for (x = 0; str[x] != 0; x++) {
127
    if (str[x] == '\\') str[x] = '/';
128
  }
129
}
130
 
131
 
132
void removeDoubleBackslashes(char *str) {
133
  char *curpos;
134
  int x;
135
  for (;;) {
136
    curpos = fdnpkg_strcasestr(str, "\\\\");
137
    if (curpos == NULL) return; /* job done */
138
    for (x = 1; curpos[x] != 0; x++) {
139
      curpos[x - 1] = curpos[x];
140
    }
141
    curpos[x - 1] = 0;
142
  }
143
}
144
 
145
 
146
/* converts a string to all lowercase */
147
void strtolower(char *mystring) {
148
  int x;
149
  for (x = 0; mystring[x] != 0; x++) mystring[x] = tolower(mystring[x]);
150
}
151
 
152
 
153
/* Find the first occurrence of find in s, ignore case. */
154
char *fdnpkg_strcasestr(const char *s, const char *find) {
155
  char c, sc;
156
  size_t len;
157
  if ((c = *find++) != 0) {
158
    c = tolower((unsigned char)c);
159
    len = strlen(find);
160
    do {
161
      do {
162
        if ((sc = *s++) == 0) return(NULL);
163
      } while ((char)tolower((unsigned char)sc) != c);
164
    } while (strncasecmp(s, find, len) != 0);
165
    s--;
166
  }
167
  return((char *)s);
168
}
169
 
170
 
171
/* Creates directories recursively */
172
void mkpath(char *dirs) {
173
  int x;
174
  char savechar;
175
  for (x = 0; dirs[x] != 0; x++) {
176
    if (((dirs[x] == '/') || (dirs[x] == '\\')) && (x > 0)) {
177
      if (dirs[x - 1] != ':') { /* avoid d:\ stuff */
178
        savechar = dirs[x];
179
        dirs[x] = 0;
180
        /* make the dir */
240 mateuszvis 181
        mkdir(dirs);
219 mateuszvis 182
        dirs[x] = savechar;
183
      }
184
    }
185
  }
186
}
187
 
188
 
189
/* returns a pointer to the start of the filename, out of a path\to\file string, and
190
   fills respath with the local folder where the file should be placed. */
231 mateuszvis 191
char *computelocalpath(char *longfilename, char *respath, const char *dosdir, const struct customdirs *dirlist) {
219 mateuszvis 192
  int x, lastsep = 0, firstsep = -1;
193
  char savedchar;
194
  char *shortfilename, *pathstart;
195
  pathstart = longfilename;
196
  for (x = 0; longfilename[x] != 0; x++) {
197
    if ((longfilename[x] == '/') || (longfilename[x] == '\\')) {
198
      lastsep = x;
199
      if (firstsep < 0) firstsep = x;
200
    }
201
  }
202
  shortfilename = &longfilename[lastsep + 1];
203
  /* look for possible custom path */
204
  if (firstsep > 0) {
205
    savedchar = longfilename[firstsep];
206
    longfilename[firstsep] = 0;
207
    for (; dirlist != NULL; dirlist = dirlist->next) {
208
      if (fdnpkg_strcasestr(longfilename, dirlist->name) == longfilename) { /* found! */
209
        /* sprintf(respath, "%s\\%s", dirlist->location, &longfilename[firstsep + 1]); */
210
        pathstart = &longfilename[firstsep + 1];
211
        dosdir = dirlist->location;
212
        break;
213
      }
214
    }
215
    longfilename[firstsep] = savedchar; /* restore longfilename as it was */
216
  }
217
  /* apply the default (DOSDIR) path */
218
  savedchar = longfilename[lastsep + 1];
219
  longfilename[lastsep + 1] = 0;
220
  sprintf(respath, "%s\\%s", dosdir, pathstart);
221
  slash2backslash(respath);
222
  removeDoubleBackslashes(respath);
223
  longfilename[lastsep + 1] = savedchar;
224
  return(shortfilename);
225
}
226
 
227
 
228
/* detect local paths (eg. C:\REPO). Returns 1 if the url looks like a local path, zero otherwise. */
229
int detect_localpath(char *url) {
230
  if (url[0] != 0) {
231
    if (url[1] != 0) {
232
      if ((url[1] == ':') && ((url[2] == '\\') || (url[2] == '/'))) return(1);
233
    }
234
  }
235
  return(0);
236
}
237
 
238
 
239
/* analyzes a filename string and returns the pointer to the file's extension
240
 * (which can be empty) */
241
char *getfext(char *fname) {
242
  char *res = NULL;
243
  for (; *fname != 0; fname++) {
244
    if (*fname == '.') res = fname + 1;
245
  }
246
  /* if no dot found, then point to the string's null terminator */
247
  if (res == NULL) return(fname);
248
  return(res);
249
}
248 mateuszvis 250
 
251
 
252
/* reads a line from a "token = value" file, returns 0 on success
253
 * val (if not NULL) is updated with a pointer to the "value" part
254
 * delim is the delimiter char (typically ':' or '=' but can be anything) */
255
int freadtokval(FILE *fd, char *line, size_t maxlen, char **val, char delim) {
256
  int bytebuff, linelen = 0;
257
  if (val != NULL) *val = NULL;
258
  for (;;) {
259
    bytebuff = fgetc(fd);
260
    if (bytebuff == EOF) {
261
      if (linelen == 0) return(-1);
262
      break;
263
    }
264
    if (bytebuff < 0) return(-1);
265
    if ((*val == NULL) && (bytebuff == delim)) {
266
      line[linelen++] = 0;
267
      *val = line + linelen;
268
      continue;
269
    }
270
    if (bytebuff == '\r') continue; /* ignore CR */
271
    if (bytebuff == '\n') break;
272
    if (linelen < maxlen - 1) line[linelen++] = bytebuff;
273
  }
274
  /* terminate line and trim token and value (if any) */
275
  line[linelen] = 0;
276
  trim(line);
277
  if ((val != NULL) && (*val != NULL)) trim(*val);
278
  return(0);
279
}