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