6060 * "duration" // NOSHELL_FSON_TYPE_DURATION
6161 * };
6262 * ```
63- * - The function `noshell_fson_type_to_string` converts a type enum to its string name.
6463 *
6564 * ## .noshell File Format Overview
6665 * - Each .noshell file is a plain text file with lines representing key-value pairs
@@ -158,12 +157,6 @@ static const char *noshell_fson_type_names[] = {
158157 "duration" // NOSHELL_FSON_TYPE_DURATION
159158};
160159
161- static inline const char * noshell_fson_type_to_string (fossil_bluecrab_noshell_fson_type_t type ) {
162- if (type < 0 || type > NOSHELL_FSON_TYPE_DURATION )
163- return "unknown" ;
164- return noshell_fson_type_names [type ];
165- }
166-
167160/**
168161 * Custom strdup implementation.
169162 */
@@ -230,27 +223,41 @@ fossil_bluecrab_noshell_error_t fossil_bluecrab_noshell_insert(
230223 const char * param_list ,
231224 const char * type // type as string parameter
232225) {
233- if (!file_name || !document )
226+ if (!file_name || !document || ! type )
234227 return FOSSIL_NOSHELL_ERROR_INVALID_FILE ;
235228
236229 if (!fossil_bluecrab_noshell_validate_extension (file_name ))
237230 return FOSSIL_NOSHELL_ERROR_INVALID_FILE ;
238231
232+ // Check that type is valid (must match one of noshell_fson_type_names)
233+ bool valid_type = false;
234+ for (size_t i = 0 ; i <= NOSHELL_FSON_TYPE_DURATION ; ++ i ) {
235+ if (strcmp (type , noshell_fson_type_names [i ]) == 0 ) {
236+ valid_type = true;
237+ break ;
238+ }
239+ }
240+ if (!valid_type )
241+ return FOSSIL_NOSHELL_ERROR_INVALID_TYPE ;
242+
239243 // Basic FSON validation: must start with '{' or '['
240244 const char * doc_ptr = document ;
241245 while (isspace ((unsigned char )* doc_ptr )) doc_ptr ++ ;
242246 if (* doc_ptr != '{' && * doc_ptr != '[' )
243247 return FOSSIL_NOSHELL_ERROR_INVALID_TYPE ;
244248
249+ // Generate document ID using hash64 of document string (FSON object)
250+ uint64_t doc_id = noshell_hash64 (document );
251+
245252 FILE * fp = fopen (file_name , "a" );
246253 if (!fp )
247254 return FOSSIL_NOSHELL_ERROR_IO ;
248255
249- // Optionally append param_list if provided, always append #type=TYPE
256+ // Optionally append param_list if provided, always append #type=TYPE and #id=ID
250257 if (param_list && strlen (param_list ) > 0 ) {
251- fprintf (fp , "%s %s #type=%s\n" , document , param_list , type );
258+ fprintf (fp , "%s %s #type=%s #id=%016" PRIx64 " \n" , document , param_list , type , doc_id );
252259 } else {
253- fprintf (fp , "%s #type=%s\n" , document , type );
260+ fprintf (fp , "%s #type=%s #id=%016" PRIx64 " \n" , document , type , doc_id );
254261 }
255262
256263 fclose (fp );
@@ -265,12 +272,23 @@ fossil_bluecrab_noshell_error_t fossil_bluecrab_noshell_insert_with_id(
265272 char * out_id ,
266273 size_t id_size
267274) {
268- if (!file_name || !document || !out_id || id_size < 17 )
275+ if (!file_name || !document || !type || ! out_id || id_size < 17 )
269276 return FOSSIL_NOSHELL_ERROR_INVALID_FILE ;
270277
271278 if (!fossil_bluecrab_noshell_validate_extension (file_name ))
272279 return FOSSIL_NOSHELL_ERROR_INVALID_FILE ;
273280
281+ // Check that type is valid (must match one of noshell_fson_type_names)
282+ bool valid_type = false;
283+ for (size_t i = 0 ; i <= NOSHELL_FSON_TYPE_DURATION ; ++ i ) {
284+ if (strcmp (type , noshell_fson_type_names [i ]) == 0 ) {
285+ valid_type = true;
286+ break ;
287+ }
288+ }
289+ if (!valid_type )
290+ return FOSSIL_NOSHELL_ERROR_INVALID_TYPE ;
291+
274292 // FSON format: must start with '{' or '['
275293 const char * doc_ptr = document ;
276294 while (isspace ((unsigned char )* doc_ptr )) doc_ptr ++ ;
@@ -279,7 +297,7 @@ fossil_bluecrab_noshell_error_t fossil_bluecrab_noshell_insert_with_id(
279297
280298 // Generate document ID using hash64 of document string (FSON object)
281299 uint64_t doc_id = noshell_hash64 (document );
282- snprintf (out_id , id_size , "%016llx" , ( unsigned long long ) doc_id );
300+ snprintf (out_id , id_size , "%016" PRIx64 , doc_id );
283301
284302 FILE * fp = fopen (file_name , "a" );
285303 if (!fp )
@@ -309,6 +327,19 @@ fossil_bluecrab_noshell_error_t fossil_bluecrab_noshell_find(
309327 if (!fossil_bluecrab_noshell_validate_extension (file_name ))
310328 return FOSSIL_NOSHELL_ERROR_INVALID_FILE ;
311329
330+ // If type_id is provided, check it is valid using noshell_fson_type_names
331+ if (type_id && strlen (type_id ) > 0 ) {
332+ bool valid_type = false;
333+ for (size_t i = 0 ; i <= NOSHELL_FSON_TYPE_DURATION ; ++ i ) {
334+ if (strcmp (type_id , noshell_fson_type_names [i ]) == 0 ) {
335+ valid_type = true;
336+ break ;
337+ }
338+ }
339+ if (!valid_type )
340+ return FOSSIL_NOSHELL_ERROR_INVALID_TYPE ;
341+ }
342+
312343 FILE * fp = fopen (file_name , "r" );
313344 if (!fp )
314345 return FOSSIL_NOSHELL_ERROR_IO ;
@@ -384,6 +415,19 @@ fossil_bluecrab_noshell_error_t fossil_bluecrab_noshell_update(
384415 if (!fossil_bluecrab_noshell_validate_extension (file_name ))
385416 return FOSSIL_NOSHELL_ERROR_INVALID_FILE ;
386417
418+ // If type_id is provided, check it is valid using noshell_fson_type_names
419+ if (type_id && strlen (type_id ) > 0 ) {
420+ bool valid_type = false;
421+ for (size_t i = 0 ; i <= NOSHELL_FSON_TYPE_DURATION ; ++ i ) {
422+ if (strcmp (type_id , noshell_fson_type_names [i ]) == 0 ) {
423+ valid_type = true;
424+ break ;
425+ }
426+ }
427+ if (!valid_type )
428+ return FOSSIL_NOSHELL_ERROR_INVALID_TYPE ;
429+ }
430+
387431 // Basic FSON validation: must start with '{' or '['
388432 const char * doc_ptr = new_document ;
389433 while (isspace ((unsigned char )* doc_ptr )) doc_ptr ++ ;
0 commit comments