MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_sys.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_sys.c : system utility functions
3 *
4 * Copyright (C) 2026 H.SHIONO (MRTKLIB Project)
5 * Copyright (C) 2023-2025 Cabinet Office, Japan
6 * Copyright (C) 2024-2025 Lighthouse Technology & Consulting Co. Ltd.
7 * Copyright (C) 2023-2025 Japan Aerospace Exploration Agency
8 * Copyright (C) 2023-2025 TOSHIBA ELECTRONIC TECHNOLOGIES CORPORATION
9 * Copyright (C) 2015- Mitsubishi Electric Corp.
10 * Copyright (C) 2014 Geospatial Information Authority of Japan
11 * Copyright (C) 2014 T.SUZUKI
12 * Copyright (C) 2007-2023 T.TAKASU
13 *
14 * SPDX-License-Identifier: BSD-2-Clause
15 *----------------------------------------------------------------------------*/
16/**
17 * @file mrtk_sys.c
18 * @brief MRTKLIB System Module — Implementation.
19 *
20 * All functions and static data in this file are cut-and-paste extractions
21 * from the legacy rtkcmn.c with zero algorithmic changes.
22 */
23
24#define _POSIX_C_SOURCE 199506
25
26#include "mrtklib/mrtk_sys.h"
27
28#include <ctype.h>
29#include <dirent.h>
30#include <errno.h>
31#include <math.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/stat.h>
36#include <sys/types.h>
37
38#include "mrtklib/mrtk_trace.h"
39
40/*============================================================================
41 * Forward Declarations (resolved at link time from rtkcmn.c)
42 *===========================================================================*/
43
44/*============================================================================
45 * Platform Constants
46 *===========================================================================*/
47
48#define FILEPATHSEP '/'
49
50/*============================================================================
51 * String Conversion Functions
52 *===========================================================================*/
53
54/* string to number ------------------------------------------------------------
55 * convert substring in string to number
56 * args : char *s I string ("... nnn.nnn ...")
57 * int i,n I substring position and width
58 * return : converted number (0.0:error)
59 *-----------------------------------------------------------------------------*/
60extern double str2num(const char* s, int i, int n) {
61 double value;
62 char str[256], *p = str;
63
64 if (i < 0 || (int)strlen(s) < i || (int)sizeof(str) - 1 < n) {
65 return 0.0;
66 }
67 for (s += i; *s && --n >= 0; s++) {
68 *p++ = *s == 'd' || *s == 'D' ? 'E' : *s;
69 }
70 *p = '\0';
71 return sscanf(str, "%lf", &value) == 1 ? value : 0.0;
72}
73
74/*============================================================================
75 * Command / Path Functions
76 *===========================================================================*/
77
78/* execute command -------------------------------------------------------------
79 * execute command line by operating system shell
80 * args : char *cmd I command line
81 * return : execution status (0:ok,0>:error)
82 *-----------------------------------------------------------------------------*/
83extern int execcmd(const char* cmd) {
84 trace(NULL, 3, "execcmd: cmd=%s\n", cmd);
85
86 return system(cmd);
87}
88/* expand file path ------------------------------------------------------------
89 * expand file path with wild-card (*) in file
90 * args : char *path I file path to expand (captal insensitive)
91 * char *paths O expanded file paths
92 * int nmax I max number of expanded file paths
93 * return : number of expanded file paths
94 * notes : the order of expanded files is alphabetical order
95 *-----------------------------------------------------------------------------*/
96extern int expath(const char* path, char* paths[], int nmax) {
97 int i, j, n = 0;
98 char tmp[1024];
99 struct dirent* d;
100 DIR* dp;
101 const char* file = path;
102 char dir[1024] = "", s1[1024], s2[1024], *p, *q, *r;
103
104 trace(NULL, 3, "expath : path=%s nmax=%d\n", path, nmax);
105
106 if ((p = strrchr(path, '/')) || (p = strrchr(path, '\\'))) {
107 file = p + 1;
108 strncpy(dir, path, p - path + 1);
109 dir[p - path + 1] = '\0';
110 }
111 if (!(dp = opendir(*dir ? dir : "."))) {
112 return 0;
113 }
114 while ((d = readdir(dp))) {
115 if (*(d->d_name) == '.') {
116 continue;
117 }
118 sprintf(s1, "^%s$", d->d_name);
119 sprintf(s2, "^%s$", file);
120 for (p = s1; *p; p++) {
121 *p = (char)tolower((int)*p);
122 }
123 for (p = s2; *p; p++) {
124 *p = (char)tolower((int)*p);
125 }
126
127 for (p = s1, q = strtok_r(s2, "*", &r); q; q = strtok_r(NULL, "*", &r)) {
128 if ((p = strstr(p, q))) {
129 p += strlen(q);
130 } else {
131 break;
132 }
133 }
134 if (p && n < nmax) {
135 sprintf(paths[n++], "%s%s", dir, d->d_name);
136 }
137 }
138 closedir(dp);
139 /* sort paths in alphabetical order */
140 for (i = 0; i < n - 1; i++) {
141 for (j = i + 1; j < n; j++) {
142 if (strcmp(paths[i], paths[j]) > 0) {
143 strcpy(tmp, paths[i]);
144 strcpy(paths[i], paths[j]);
145 strcpy(paths[j], tmp);
146 }
147 }
148 }
149 for (i = 0; i < n; i++) {
150 trace(NULL, 3, "expath : file=%s\n", paths[i]);
151 }
152
153 return n;
154}
155/* generate local directory recursively --------------------------------------*/
156static int mkdir_r(const char* dir) {
157 char pdir[1024], *p;
158 FILE* fp;
159
160 if (!*dir) {
161 return 1;
162 }
163
164 sprintf(pdir, "%.1023s", dir);
165 if ((p = strrchr(pdir, FILEPATHSEP))) {
166 *p = '\0';
167 if (!(fp = fopen(pdir, "r"))) {
168 if (!mkdir_r(pdir)) {
169 return 0;
170 }
171 } else {
172 fclose(fp);
173 }
174 }
175 if (!mkdir(dir, 0777) || errno == EEXIST) {
176 return 1;
177 }
178 trace(NULL, 2, "directory generation error: dir=%s\n", dir);
179 return 0;
180}
181/* create directory ------------------------------------------------------------
182 * create directory if not exists
183 * args : char *path I file path to be saved
184 * return : none
185 * notes : recursively.
186 *-----------------------------------------------------------------------------*/
187extern void createdir(const char* path) {
188 char buff[1024], *p;
189
190 tracet(NULL, 3, "createdir: path=%s\n", path);
191
192 strcpy(buff, path);
193 if (!(p = strrchr(buff, FILEPATHSEP))) {
194 return;
195 }
196 *p = '\0';
197
198 mkdir_r(buff);
199}
200/* replace string ------------------------------------------------------------*/
201static int repstr(char* str, const char* pat, const char* rep) {
202 int len = (int)strlen(pat);
203 char buff[1024], *p, *q, *r;
204
205 for (p = str, r = buff; *p; p = q + len) {
206 if (!(q = strstr(p, pat))) {
207 break;
208 }
209 strncpy(r, p, q - p);
210 r += q - p;
211 r += sprintf(r, "%s", rep);
212 }
213 if (p <= str) {
214 return 0;
215 }
216 strcpy(r, p);
217 strcpy(str, buff);
218 return 1;
219}
220/* replace keywords in file path -----------------------------------------------
221 * replace keywords in file path with date, time, rover and base station id
222 * args : char *path I file path (see below)
223 * char *rpath O file path in which keywords replaced (see below)
224 * gtime_t time I time (gpst) (time.time==0: not replaced)
225 * char *rov I rover id string ("": not replaced)
226 * char *base I base station id string ("": not replaced)
227 * return : status (1:keywords replaced, 0:no valid keyword in the path,
228 * -1:no valid time)
229 * notes : the following keywords in path are replaced by date, time and name
230 * %Y -> yyyy : year (4 digits) (1900-2099)
231 * %y -> yy : year (2 digits) (00-99)
232 * %m -> mm : month (01-12)
233 * %d -> dd : day of month (01-31)
234 * %h -> hh : hours (00-23)
235 * %M -> mm : minutes (00-59)
236 * %S -> ss : seconds (00-59)
237 * %n -> ddd : day of year (001-366)
238 * %W -> wwww : gps week (0001-9999)
239 * %D -> d : day of gps week (0-6)
240 * %H -> h : hour code (a=0,b=1,c=2,...,x=23)
241 * %ha-> hh : 3 hours (00,03,06,...,21)
242 * %hb-> hh : 6 hours (00,06,12,18)
243 * %hc-> hh : 12 hours (00,12)
244 * %t -> mm : 15 minutes (00,15,30,45)
245 * %r -> rrrr : rover id
246 * %b -> bbbb : base station id
247 *-----------------------------------------------------------------------------*/
248extern int reppath(const char* path, char* rpath, gtime_t time, const char* rov, const char* base) {
249 double ep[6], ep0[6] = {2000, 1, 1, 0, 0, 0};
250 int week, dow, doy, stat = 0;
251 char rep[64];
252
253 strcpy(rpath, path);
254
255 if (!strstr(rpath, "%")) {
256 return 0;
257 }
258 if (*rov) {
259 stat |= repstr(rpath, "%r", rov);
260 }
261 if (*base) {
262 stat |= repstr(rpath, "%b", base);
263 }
264 if (time.time != 0) {
265 time2epoch(time, ep);
266 ep0[0] = ep[0];
267 dow = (int)floor(time2gpst(time, &week) / 86400.0);
268 doy = (int)floor(timediff(time, epoch2time(ep0)) / 86400.0) + 1;
269 sprintf(rep, "%02d", ((int)ep[3] / 3) * 3);
270 stat |= repstr(rpath, "%ha", rep);
271 sprintf(rep, "%02d", ((int)ep[3] / 6) * 6);
272 stat |= repstr(rpath, "%hb", rep);
273 sprintf(rep, "%02d", ((int)ep[3] / 12) * 12);
274 stat |= repstr(rpath, "%hc", rep);
275 sprintf(rep, "%04.0f", ep[0]);
276 stat |= repstr(rpath, "%Y", rep);
277 sprintf(rep, "%02.0f", fmod(ep[0], 100.0));
278 stat |= repstr(rpath, "%y", rep);
279 sprintf(rep, "%02.0f", ep[1]);
280 stat |= repstr(rpath, "%m", rep);
281 sprintf(rep, "%02.0f", ep[2]);
282 stat |= repstr(rpath, "%d", rep);
283 sprintf(rep, "%02.0f", ep[3]);
284 stat |= repstr(rpath, "%h", rep);
285 sprintf(rep, "%02.0f", ep[4]);
286 stat |= repstr(rpath, "%M", rep);
287 sprintf(rep, "%02.0f", floor(ep[5]));
288 stat |= repstr(rpath, "%S", rep);
289 sprintf(rep, "%03d", doy);
290 stat |= repstr(rpath, "%n", rep);
291 sprintf(rep, "%04d", week);
292 stat |= repstr(rpath, "%W", rep);
293 sprintf(rep, "%d", dow);
294 stat |= repstr(rpath, "%D", rep);
295 sprintf(rep, "%c", 'a' + (int)ep[3]);
296 stat |= repstr(rpath, "%H", rep);
297 sprintf(rep, "%02d", ((int)ep[4] / 15) * 15);
298 stat |= repstr(rpath, "%t", rep);
299 } else if (strstr(rpath, "%ha") || strstr(rpath, "%hb") || strstr(rpath, "%hc") || strstr(rpath, "%Y") ||
300 strstr(rpath, "%y") || strstr(rpath, "%m") || strstr(rpath, "%d") || strstr(rpath, "%h") ||
301 strstr(rpath, "%M") || strstr(rpath, "%S") || strstr(rpath, "%n") || strstr(rpath, "%W") ||
302 strstr(rpath, "%D") || strstr(rpath, "%H") || strstr(rpath, "%t")) {
303 return -1; /* no valid time */
304 }
305 return stat;
306}
307/* replace keywords in file path and generate multiple paths -------------------
308 * replace keywords in file path with date, time, rover and base station id
309 * generate multiple keywords-replaced paths
310 * args : char *path I file path (see below)
311 * char *rpath[] O file paths in which keywords replaced
312 * int nmax I max number of output file paths
313 * gtime_t ts I time start (gpst)
314 * gtime_t te I time end (gpst)
315 * char *rov I rover id string ("": not replaced)
316 * char *base I base station id string ("": not replaced)
317 * return : number of replaced file paths
318 * notes : see reppath() for replacements of keywords.
319 * minimum interval of time replaced is 900s.
320 *-----------------------------------------------------------------------------*/
321extern int reppaths(const char* path, char* rpath[], int nmax, gtime_t ts, gtime_t te, const char* rov,
322 const char* base) {
323 gtime_t time;
324 double tow, tint = 86400.0;
325 int i, n = 0, week;
326
327 trace(NULL, 3, "reppaths: path =%s nmax=%d rov=%s base=%s\n", path, nmax, rov, base);
328
329 if (ts.time == 0 || te.time == 0 || timediff(ts, te) > 0.0) {
330 return 0;
331 }
332
333 if (strstr(path, "%S") || strstr(path, "%M") || strstr(path, "%t")) {
334 tint = 900.0;
335 } else if (strstr(path, "%h") || strstr(path, "%H")) {
336 tint = 3600.0;
337 }
338
339 tow = time2gpst(ts, &week);
340 time = gpst2time(week, floor(tow / tint) * tint);
341
342 while (timediff(time, te) <= 0.0 && n < nmax) {
343 reppath(path, rpath[n], time, rov, base);
344 if (n == 0 || strcmp(rpath[n], rpath[n - 1])) {
345 n++;
346 }
347 time = timeadd(time, tint);
348 }
349 for (i = 0; i < n; i++) {
350 trace(NULL, 3, "reppaths: rpath=%s\n", rpath[i]);
351 }
352 return n;
353}
354
355/*============================================================================
356 * File Compression Functions
357 *===========================================================================*/
358
359/* uncompress file -------------------------------------------------------------
360 * uncompress (uncompress/unzip/uncompact hatanaka-compression/tar) file
361 * args : char *file I input file
362 * char *uncfile O uncompressed file
363 * return : status (-1:error,0:not compressed file,1:uncompress completed)
364 * note : creates uncompressed file in tempolary directory
365 * gzip, tar and crx2rnx commands have to be installed in commands path
366 *-----------------------------------------------------------------------------*/
367extern int rtk_uncompress(const char* file, char* uncfile) {
368 int stat = 0;
369 char *p, cmd[64 + 2048] = "", tmpfile[1024] = "", buff[1024], *fname, *dir = "";
370
371 trace(NULL, 3, "rtk_uncompress: file=%s\n", file);
372
373 strcpy(tmpfile, file);
374 if (!(p = strrchr(tmpfile, '.'))) {
375 return 0;
376 }
377
378 /* uncompress by gzip */
379 if (!strcmp(p, ".z") || !strcmp(p, ".Z") || !strcmp(p, ".gz") || !strcmp(p, ".GZ") || !strcmp(p, ".zip") ||
380 !strcmp(p, ".ZIP")) {
381 strcpy(uncfile, tmpfile);
382 uncfile[p - tmpfile] = '\0';
383 sprintf(cmd, "gzip -f -d -c \"%s\" > \"%s\"", tmpfile, uncfile);
384
385 if (execcmd(cmd)) {
386 remove(uncfile);
387 return -1;
388 }
389 strcpy(tmpfile, uncfile);
390 stat = 1;
391 }
392 /* extract tar file */
393 if ((p = strrchr(tmpfile, '.')) && !strcmp(p, ".tar")) {
394 strcpy(uncfile, tmpfile);
395 uncfile[p - tmpfile] = '\0';
396 strcpy(buff, tmpfile);
397 fname = buff;
398 if ((p = strrchr(buff, '/'))) {
399 *p = '\0';
400 dir = fname;
401 fname = p + 1;
402 }
403 sprintf(cmd, "tar -C \"%s\" -xf \"%s\"", dir, tmpfile);
404 if (execcmd(cmd)) {
405 if (stat) {
406 remove(tmpfile);
407 }
408 return -1;
409 }
410 if (stat) {
411 remove(tmpfile);
412 }
413 stat = 1;
414 }
415 /* extract hatanaka-compressed file by cnx2rnx */
416 else if ((p = strrchr(tmpfile, '.')) &&
417 ((strlen(p) > 3 && (*(p + 3) == 'd' || *(p + 3) == 'D')) || !strcmp(p, ".crx") || !strcmp(p, ".CRX"))) {
418 strcpy(uncfile, tmpfile);
419 uncfile[p - tmpfile + 3] = *(p + 3) == 'D' ? 'O' : 'o';
420 sprintf(cmd, "crx2rnx < \"%s\" > \"%s\"", tmpfile, uncfile);
421
422 if (execcmd(cmd)) {
423 remove(uncfile);
424 if (stat) {
425 remove(tmpfile);
426 }
427 return -1;
428 }
429 if (stat) {
430 remove(tmpfile);
431 }
432 stat = 1;
433 }
434 trace(NULL, 3, "rtk_uncompress: stat=%d\n", stat);
435 return stat;
436}
#define FILEPATHSEP
Definition mrtk_sys.c:48
int expath(const char *path, char *paths[], int nmax)
Expand file path with wild-card (*) in file.
Definition mrtk_sys.c:96
int rtk_uncompress(const char *file, char *uncfile)
Uncompress file (gzip/zip/tar/Hatanaka).
Definition mrtk_sys.c:367
int execcmd(const char *cmd)
Execute command line by operating system shell.
Definition mrtk_sys.c:83
void createdir(const char *path)
Create directory if not exists (recursively).
Definition mrtk_sys.c:187
int reppath(const char *path, char *rpath, gtime_t time, const char *rov, const char *base)
Replace keywords in file path with date, time, rover and base station id.
Definition mrtk_sys.c:248
static int mkdir_r(const char *dir)
Definition mrtk_sys.c:156
double str2num(const char *s, int i, int n)
Convert substring in string to number.
Definition mrtk_sys.c:60
int reppaths(const char *path, char *rpath[], int nmax, gtime_t ts, gtime_t te, const char *rov, const char *base)
Replace keywords in file path and generate multiple paths.
Definition mrtk_sys.c:321
static int repstr(char *str, const char *pat, const char *rep)
Definition mrtk_sys.c:201
MRTKLIB System Module — OS/filesystem utility functions.
gtime_t epoch2time(const double *ep)
Convert calendar day/time to gtime_t struct.
Definition mrtk_time.c:113
gtime_t gpst2time(int week, double sec)
Convert GPS week/tow to gtime_t.
Definition mrtk_time.c:165
void time2epoch(gtime_t t, double *ep)
Convert gtime_t struct to calendar day/time.
Definition mrtk_time.c:136
double timediff(gtime_t t1, gtime_t t2)
Compute time difference (t1 - t2).
Definition mrtk_time.c:279
double time2gpst(gtime_t t, int *week)
Convert gtime_t to GPS week/tow.
Definition mrtk_time.c:181
gtime_t timeadd(gtime_t t, double sec)
Add seconds to gtime_t.
Definition mrtk_time.c:265
void tracet(mrtk_ctx_t *ctx, int level, const char *format,...)
Output trace message with elapsed time.
Definition mrtk_trace.c:91
void trace(mrtk_ctx_t *ctx, int level, const char *format,...)
Output trace message.
Definition mrtk_trace.c:78
MRTKLIB Trace Module — debug trace and logging functions.
GNSS time representation.
Definition mrtk_time.h:49
time_t time
Definition mrtk_time.h:50