MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_core.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_core.c : MRTKLIB core context management and logging
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_core.c
18 * @brief Core implementation of MRTKLIB context management and logging.
19 *
20 * This file contains the implementation of the opaque context structure
21 * and all associated lifecycle, logging, and error handling functions.
22 */
23
24#include <stdarg.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include "mrtklib/mrtklib.h"
30
31/*============================================================================
32 * Legacy Migration Support
33 *===========================================================================*/
34
35/**
36 * @brief Global context for legacy RTKLIB trace() bridge.
37 *
38 * @see g_mrtk_legacy_ctx declaration in mrtklib.h
39 */
41
42/*============================================================================
43 * Private Constants
44 *===========================================================================*/
45
46/** @brief Maximum length of error messages stored in context */
47#define MAX_ERROR_LEN 256
48
49/** @brief Maximum length of formatted log messages */
50#define MAX_LOG_LEN 1024
51
52/*============================================================================
53 * Private Structure Definition
54 *===========================================================================*/
55
56/**
57 * @brief Internal context structure.
58 *
59 * This structure holds all per-instance state for the library.
60 * It is intentionally hidden from users to maintain API stability.
61 */
63 mrtk_log_level_t log_level; /**< Minimum log level threshold */
64 mrtk_log_cb_t log_callback; /**< User-defined log handler */
65 char last_error[MAX_ERROR_LEN]; /**< Most recent error message */
66 void* user_data; /**< Application-specific data pointer */
67};
68
69/*============================================================================
70 * Private Functions
71 *===========================================================================*/
72
73/**
74 * @brief Default log callback implementation.
75 *
76 * Outputs log messages to stdout (DEBUG, INFO, WARN) or stderr (ERROR).
77 * This is the default handler used when no custom callback is registered.
78 *
79 * @param ctx Context instance (unused in default implementation)
80 * @param level Severity level of the message
81 * @param msg Formatted message string
82 */
83static void default_log_callback(mrtk_context_t* ctx, mrtk_log_level_t level, const char* msg) {
84 const char* level_str;
85 FILE* output;
86
87 (void)ctx; /* Unused in default implementation */
88
89 switch (level) {
90 case MRTK_LOG_DEBUG:
91 level_str = "[DEBUG]";
92 output = stdout;
93 break;
94 case MRTK_LOG_INFO:
95 level_str = "[INFO] ";
96 output = stdout;
97 break;
98 case MRTK_LOG_WARN:
99 level_str = "[WARN] ";
100 output = stdout;
101 break;
102 case MRTK_LOG_ERROR:
103 level_str = "[ERROR]";
104 output = stderr;
105 break;
106 case MRTK_LOG_NONE:
107 default:
108 /* Should not reach here; MRTK_LOG_NONE messages are filtered earlier */
109 return;
110 }
111
112 fprintf(output, "%s %s\n", level_str, msg);
113}
114
115/**
116 * @brief Set the internal error message.
117 *
118 * Stores a formatted error message in the context for later retrieval
119 * via mrtk_get_last_error(). Also logs the error message at ERROR level.
120 *
121 * @param ctx Context instance
122 * @param fmt printf-style format string
123 * @param ... Format arguments
124 *
125 * @note This is an internal function not exposed in the public API.
126 * Library modules use this to report errors.
127 */
128#if defined(__GNUC__) || defined(__clang__)
129__attribute__((unused, format(printf, 2, 3)))
130#endif
131static void mrtk_set_error(mrtk_context_t* ctx, const char* fmt, ...) {
132 va_list args;
133
134 if (ctx == NULL || fmt == NULL) {
135 return;
136 }
137
138 va_start(args, fmt);
139 vsnprintf(ctx->last_error, MAX_ERROR_LEN, fmt, args);
140 va_end(args);
141
142 /* Also log the error */
143 mrtk_log(ctx, MRTK_LOG_ERROR, "%s", ctx->last_error);
144}
145
146/*============================================================================
147 * Lifecycle Management Implementation
148 *===========================================================================*/
149
150/**
151 * @brief Create a new library context.
152 *
153 * Allocates memory for a new context and initializes it with default values.
154 * The default configuration is:
155 * - log_level: MRTK_LOG_INFO
156 * - log_callback: default_log_callback (stdout/stderr output)
157 * - last_error: empty string
158 * - user_data: NULL
159 *
160 * @return Newly allocated context, or NULL if memory allocation fails.
161 */
164 if (ctx == NULL) {
165 return NULL;
166 }
167
168 /* Initialize with default settings */
171 ctx->last_error[0] = '\0';
172 ctx->user_data = NULL;
173
174 return ctx;
175}
176
177/**
178 * @brief Free the library context.
179 *
180 * Releases all memory associated with the context. Safe to call with NULL.
181 *
182 * @param ctx Context to free, or NULL (no-op)
183 */
185 if (ctx != NULL) {
186 /* Clear sensitive data before freeing (defense in depth) */
187 memset(ctx, 0, sizeof(mrtk_context_t));
188 free(ctx);
189 }
190}
191
192/*============================================================================
193 * Logging Configuration Implementation
194 *===========================================================================*/
195
196/**
197 * @brief Set a custom log callback.
198 *
199 * @param ctx Context instance
200 * @param cb Callback function, or NULL to restore default logger
201 */
203 if (ctx == NULL) {
204 return;
205 }
206
207 if (cb != NULL) {
208 ctx->log_callback = cb;
209 } else {
210 /* Restore default logger when NULL is passed */
212 }
213}
214
215/**
216 * @brief Set the minimum log level.
217 *
218 * @param ctx Context instance
219 * @param level New minimum log level
220 */
222 if (ctx != NULL) {
223 ctx->log_level = level;
224 }
225}
226
227/**
228 * @brief Get the current log level.
229 *
230 * @param ctx Context instance
231 * @return Current log level, or MRTK_LOG_NONE if ctx is NULL
232 */
234 if (ctx == NULL) {
235 return MRTK_LOG_NONE;
236 }
237 return ctx->log_level;
238}
239
240/**
241 * @brief Log a formatted message using a pre-initialized va_list.
242 *
243 * This is the core formatting and dispatch function. Both mrtk_log() and
244 * the legacy trace() bridge delegate to this function.
245 *
246 * @param ctx Context instance
247 * @param level Message severity level
248 * @param fmt printf-style format string
249 * @param args Pre-initialized va_list
250 */
251void mrtk_log_v(mrtk_context_t* ctx, mrtk_log_level_t level, const char* fmt, va_list args) {
252 char buf[MAX_LOG_LEN];
253 int written;
254
255 /* Validate parameters and check log level threshold */
256 if (ctx == NULL || ctx->log_callback == NULL) {
257 return;
258 }
259
260 /* Filter messages below the minimum level.
261 * MRTK_LOG_NONE is the maximum sentinel value — setting log_level to NONE
262 * disables all output, and passing level=NONE to this function is a no-op. */
263 if (level < ctx->log_level || level == MRTK_LOG_NONE) {
264 return;
265 }
266
267 /* Format the message */
268 written = vsnprintf(buf, sizeof(buf), fmt, args);
269
270 /* Ensure null termination on encoding error */
271 if (written < 0) {
272 buf[0] = '\0';
273 }
274
275 /* Dispatch to the registered callback */
276 ctx->log_callback(ctx, level, buf);
277}
278
279/**
280 * @brief Log a formatted message.
281 *
282 * Convenience wrapper around mrtk_log_v() that accepts variadic arguments.
283 *
284 * @param ctx Context instance
285 * @param level Message severity level
286 * @param fmt printf-style format string
287 * @param ... Format arguments
288 */
289void mrtk_log(mrtk_context_t* ctx, mrtk_log_level_t level, const char* fmt, ...) {
290 va_list args;
291
292 va_start(args, fmt);
293 mrtk_log_v(ctx, level, fmt, args);
294 va_end(args);
295}
296
297/*============================================================================
298 * Error Handling Implementation
299 *===========================================================================*/
300
301/**
302 * @brief Get the last error message.
303 *
304 * @param ctx Context instance
305 * @return Error message string, or "Invalid context" if ctx is NULL
306 */
307const char* mrtk_get_last_error(const mrtk_context_t* ctx) {
308 if (ctx == NULL) {
309 return "Invalid context";
310 }
311 return ctx->last_error;
312}
313
314/**
315 * @brief Clear the last error message.
316 *
317 * @param ctx Context instance
318 */
320 if (ctx != NULL) {
321 ctx->last_error[0] = '\0';
322 }
323}
324
325/*============================================================================
326 * User Data Management Implementation
327 *===========================================================================*/
328
329/**
330 * @brief Set user-defined data.
331 *
332 * @param ctx Context instance
333 * @param user_data Pointer to associate with context
334 */
335void mrtk_context_set_user_data(mrtk_context_t* ctx, void* user_data) {
336 if (ctx != NULL) {
337 ctx->user_data = user_data;
338 }
339}
340
341/**
342 * @brief Get user-defined data.
343 *
344 * @param ctx Context instance
345 * @return Associated user data, or NULL if ctx is NULL or no data was set
346 */
348 if (ctx == NULL) {
349 return NULL;
350 }
351 return ctx->user_data;
352}
353
354/*============================================================================
355 * Version Information Implementation
356 *===========================================================================*/
357
358/**
359 * @brief Get the library version string.
360 *
361 * @return Static version string (e.g., "0.1.0")
362 */
363const char* mrtk_version_string(void) { return MRTKLIB_VERSION_STRING; }
static void mrtk_set_error(mrtk_context_t *ctx, const char *fmt,...)
Set the internal error message.
Definition mrtk_core.c:131
void * mrtk_context_get_user_data(const mrtk_context_t *ctx)
Get user-defined data.
Definition mrtk_core.c:347
mrtk_context_t * g_mrtk_legacy_ctx
Global context for legacy RTKLIB trace() bridge.
Definition mrtk_core.c:40
void mrtk_log(mrtk_context_t *ctx, mrtk_log_level_t level, const char *fmt,...)
Log a formatted message.
Definition mrtk_core.c:289
#define MAX_ERROR_LEN
Maximum length of error messages stored in context.
Definition mrtk_core.c:47
void mrtk_context_set_log_callback(mrtk_context_t *ctx, mrtk_log_cb_t cb)
Set a custom log callback.
Definition mrtk_core.c:202
mrtk_context_t * mrtk_context_new(void)
Create a new library context.
Definition mrtk_core.c:162
mrtk_log_level_t mrtk_context_get_log_level(const mrtk_context_t *ctx)
Get the current log level.
Definition mrtk_core.c:233
static void default_log_callback(mrtk_context_t *ctx, mrtk_log_level_t level, const char *msg)
Default log callback implementation.
Definition mrtk_core.c:83
#define MAX_LOG_LEN
Maximum length of formatted log messages.
Definition mrtk_core.c:50
const char * mrtk_version_string(void)
Get the library version string.
Definition mrtk_core.c:363
void mrtk_clear_error(mrtk_context_t *ctx)
Clear the last error message.
Definition mrtk_core.c:319
void mrtk_log_v(mrtk_context_t *ctx, mrtk_log_level_t level, const char *fmt, va_list args)
Log a formatted message using a pre-initialized va_list.
Definition mrtk_core.c:251
void mrtk_context_free(mrtk_context_t *ctx)
Free the library context.
Definition mrtk_core.c:184
void mrtk_context_set_log_level(mrtk_context_t *ctx, mrtk_log_level_t level)
Set the minimum log level.
Definition mrtk_core.c:221
void mrtk_context_set_user_data(mrtk_context_t *ctx, void *user_data)
Set user-defined data.
Definition mrtk_core.c:335
const char * mrtk_get_last_error(const mrtk_context_t *ctx)
Get the last error message.
Definition mrtk_core.c:307
MRTKLIB Public API — Context Management and Logging.
mrtk_log_level_t
Log severity levels.
Definition mrtklib.h:76
@ MRTK_LOG_WARN
Definition mrtklib.h:79
@ MRTK_LOG_INFO
Definition mrtklib.h:78
@ MRTK_LOG_DEBUG
Definition mrtklib.h:77
@ MRTK_LOG_ERROR
Definition mrtklib.h:80
@ MRTK_LOG_NONE
Definition mrtklib.h:81
void(* mrtk_log_cb_t)(mrtk_context_t *ctx, mrtk_log_level_t level, const char *msg)
Log callback function signature.
Definition mrtklib.h:98
struct mrtk_context_s mrtk_context_t
Opaque library context structure.
Definition mrtklib.h:63
Internal context structure.
Definition mrtk_core.c:62
mrtk_log_level_t log_level
Definition mrtk_core.c:63
char last_error[256]
Definition mrtk_core.c:65
void * user_data
Definition mrtk_core.c:66
mrtk_log_cb_t log_callback
Definition mrtk_core.c:64
#define calloc(x, y)
Definition toml.c:54
#define free(x)
Definition toml.c:53