LCOV - code coverage report
Current view: top level - libs/rational/src - rational_logger.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 90.0 % 60 54
Test Date: 2026-01-12 05:34:38 Functions: 100.0 % 3 3

            Line data    Source code
       1              : #include "rational.h"
       2              : 
       3              : // Global flag to manage output of all logging messages
       4              : // in an application and its default value
       5              : _Atomic char rational_logger_mode = REGULAR;
       6              : _Atomic Return global_return_status = SUCCESS;
       7              : 
       8              : /**
       9              :  * @brief Converts LOGMODES bit flags to their string representation
      10              :  *
      11              :  * @details This function takes a combination of LOGMODES flags and converts them
      12              :  *          into a human-readable string representation where individual flags
      13              :  *          are separated by " | ". For example, (VERBOSE | SILENT) will be
      14              :  *          converted to "VERBOSE | SILENT"
      15              :  *
      16              :  * @param mode Integer containing the combination of LOGMODES flags
      17              :  * @return char* Pointer to static string containing flag names
      18              :  *
      19              :  * @note The function uses a static buffer which means:
      20              :  *       1. No memory allocation/deallocation is needed
      21              :  *       2. The buffer contents will be overwritten on next function call
      22              :  *       3. The function is not thread-safe
      23              :  *       4. The returned pointer should not be freed
      24              :  *
      25              :  * @warning Maximum resulting string length is limited to 256 characters
      26              :  */
      27          619 : char *rational_reconvert(int mode)
      28              : {
      29              :         /* Static buffer to store the resulting string */
      30              :         static char buffer[MAX_CHARACTERS];
      31          619 :         buffer[0] = '\0';  /* Initialize buffer as empty string */
      32              : 
      33              :         /* Flag to track if we're adding the first item (for | separator) */
      34          619 :         int first = 1;
      35              : 
      36              :         /* Define mapping between flag values and their string representations
      37              :          * The array is terminated with {0, NULL} for easy iteration
      38              :          */
      39              :         struct {
      40              :                 int flag;          /* Flag value from LOGMODES enum */
      41              :                 const char *name;  /* String representation of the flag */
      42          619 :         } mapping[] = {
      43              :                 {REGULAR,"REGULAR"},
      44              :                 {VERBOSE,"VERBOSE"},
      45              :                 {TESTING,"TESTING"},
      46              :                 {ERROR,"ERROR"},
      47              :                 {SILENT,"SILENT"},
      48              :                 {UNDECOR,"UNDECOR"},
      49              :                 {0,NULL}   /* Terminator element */
      50              :         };
      51              : 
      52              :         /* Iterate through all possible flags */
      53         4333 :         for(int i = 0; mapping[i].name != NULL; i++)
      54              :         {
      55              :                 /* Check if current flag is set in mode using bitwise AND */
      56         3714 :                 if(mode & mapping[i].flag)
      57              :                 {
      58              :                         /* Add separator before all elements except the first one */
      59          627 :                         if(!first)
      60              :                         {
      61            8 :                                 strcat(buffer," | ");
      62              :                         }
      63              : 
      64              :                         /* Add flag name to the result string */
      65          627 :                         strcat(buffer,mapping[i].name);
      66              : 
      67              :                         /* Clear first flag as we've added an element */
      68          627 :                         first = 0;
      69              :                 }
      70              :         }
      71              : 
      72          619 :         return buffer;
      73              : }
      74              : 
      75              : /**
      76              :  *
      77              :  * @brief Print out current date and time in ISO format
      78              :  * @param out_buffer Pointer to the destination buffer that receives the timestamp.
      79              :  * @param buffer_size Size of the destination buffer in bytes.
      80              :  * @return Return SUCCESS on success, FAILURE on error (buffer contents will contain fallback value).
      81              :  *
      82              :  */
      83          218 : static Return logger_show_time(
      84              :         char   *time_string,
      85              :         size_t buffer_size)
      86              : {
      87              :         /** Return status
      88              :          *  The status that will be passed to return() before exiting
      89              :          *  By default, the function worked without errors
      90              :          */
      91          218 :         Return status = SUCCESS;
      92              : 
      93              :         struct timeval current_time;
      94              :         struct tm local_time;
      95              : 
      96          218 :         if(gettimeofday(&current_time,NULL) != 0)
      97              :         {
      98            0 :                 time_string[0] = '\0';
      99            0 :                 status = FAILURE;
     100              :         }
     101              : 
     102          218 :         if(SUCCESS == status)
     103              :         {
     104          218 :                 if(localtime_r(&current_time.tv_sec,&local_time) == NULL)
     105              :                 {
     106            0 :                         time_string[0] = '\0';
     107            0 :                         status = FAILURE;
     108              :                 }
     109              :         }
     110              : 
     111          218 :         if(SUCCESS == status)
     112              :         {
     113          218 :                 const int milliseconds = (int)(current_time.tv_usec / 1000);
     114              : 
     115          218 :                 if(snprintf(time_string,
     116              :                         buffer_size,
     117              :                         "%04d-%02d-%02d %02d:%02d:%02d:%03d",
     118          218 :                         local_time.tm_year + 1900,
     119          218 :                         local_time.tm_mon + 1,
     120              :                         local_time.tm_mday,
     121              :                         local_time.tm_hour,
     122              :                         local_time.tm_min,
     123              :                         local_time.tm_sec,
     124              :                         milliseconds) < 0)
     125              :                 {
     126            0 :                         time_string[0] = '\0';
     127            0 :                         status = FAILURE;
     128              :                 }
     129              :         }
     130              : 
     131          218 :         return(status);
     132              : }
     133              : 
     134              : /**
     135              :  *
     136              :  * @brief Logging to the screen with the source file name, line number
     137              :  * and name of the function that generated the message itself
     138              :  *
     139              :  */
     140              : __attribute__((format(printf,5,6))) // Without this we will get warning
     141        15478 : void rational_logger(
     142              :         const char        level,
     143              :         const char *const filename,
     144              :         size_t            line,
     145              :         const char *const funcname,
     146              :         const char        *fmt,
     147              :         ...)
     148              : {
     149        15478 :         if(rational_logger_mode & SILENT)
     150              :         {
     151              :                 // Output nothing
     152         1458 :                 return;
     153              :         }
     154              : 
     155        14020 :         if(!(level & UNDECOR) && (level & TESTING) && (rational_logger_mode & TESTING))
     156              :         {
     157              :                 // Print out the word "TESTING:"
     158         8109 :                 printf("TESTING:");
     159              :         }
     160              : 
     161        14020 :         if(!(level & UNDECOR) && (level & (VERBOSE|ERROR)) && (rational_logger_mode & VERBOSE))
     162              :         {
     163              :                 char time_string[sizeof "2011-10-18 07:07:09:000"];
     164          218 :                 (void)logger_show_time(time_string,sizeof(time_string));
     165              : 
     166              :                 // Print out current time
     167          218 :                 printf("%s ",time_string);
     168              : 
     169              :                 // Print out the source file name
     170          218 :                 printf("%s:",filename);
     171              : 
     172              :                 // Print out line number in source file
     173          218 :                 printf("%03zu:",line);
     174              : 
     175              :                 // Print out name of the function itself
     176          218 :                 printf("%s:",funcname);
     177              :         }
     178              : 
     179        14020 :         if(!(level & UNDECOR) && (level & ERROR) && (rational_logger_mode & (REGULAR | ERROR)))
     180              :         {
     181              :                 // Print out error prefix
     182            5 :                 printf("ERROR: ");
     183              : 
     184        14015 :         } else if(!(level & UNDECOR) && (level & ERROR) && (rational_logger_mode & (TESTING | VERBOSE))){
     185              :                 // Print out the word "ERROR:"
     186           77 :                 printf("ERROR:");
     187              :         }
     188              : 
     189        14020 :         if(level & ERROR && rational_logger_mode & ERROR)
     190            2 :         {
     191              :                 // Print out other arguments
     192              :                 va_list args;
     193            2 :                 va_start(args,fmt);
     194            2 :                 vprintf(fmt,args);
     195            2 :                 va_end(args);
     196              : 
     197        14018 :         } else if(level & (REGULAR|ERROR) && rational_logger_mode & REGULAR){
     198              :                 // Print out other arguments
     199              :                 va_list args;
     200          389 :                 va_start(args,fmt);
     201          389 :                 vprintf(fmt,args);
     202          389 :                 va_end(args);
     203              : 
     204        13629 :         } else if(level & (VERBOSE|ERROR) && rational_logger_mode & VERBOSE){
     205              :                 // Print out other arguments
     206              :                 va_list args;
     207          489 :                 va_start(args,fmt);
     208          489 :                 vprintf(fmt,args);
     209          489 :                 va_end(args);
     210              : 
     211        13140 :         } else if(level & (TESTING|ERROR) && rational_logger_mode & TESTING){
     212              :                 // Print out other arguments
     213              :                 va_list args;
     214        10275 :                 va_start(args,fmt);
     215        10275 :                 vprintf(fmt,args);
     216        10275 :                 va_end(args);
     217              :         }
     218              : }
     219              : 
     220              : #ifdef TEST
     221              : /**
     222              :  * @file test_slog.c
     223              :  * @brief Complete test suite for log functionality
     224              :  */
     225              : int main(void)
     226              : {
     227              :         printf("All available combinations:\n");
     228              :         printf("%s\n",rational_convert(REGULAR));
     229              :         printf("%s\n",rational_convert(VERBOSE));
     230              :         printf("%s\n",rational_convert(TESTING));
     231              :         printf("%s\n",rational_convert(SILENT));
     232              :         printf("%s\n",rational_convert(REGULAR|VERBOSE));
     233              :         printf("%s\n",rational_convert(REGULAR|TESTING));
     234              :         printf("%s\n",rational_convert(VERBOSE|TESTING));
     235              :         printf("%s\n",rational_convert(REGULAR|VERBOSE|TESTING));
     236              :         printf("%s\n",rational_convert(ERROR));
     237              :         printf("%s\n",rational_convert(UNDECOR));
     238              :         printf("%s\n",rational_convert(EVERY|UNDECOR));
     239              :         printf("%s\n",rational_convert(ERROR|UNDECOR));
     240              : 
     241              :         /* Test REGULAR mode combinations */
     242              :         rational_logger_mode = REGULAR;
     243              :         printf("Mode: %s\n",rational_reconvert(rational_logger_mode));
     244              :         printf("1.  Must print:"); slog(REGULAR,"true"); printf("\n");
     245              :         printf("2. Won't print:"); slog(VERBOSE,"but printed!"); printf("\n");
     246              :         printf("3. Won't print:"); slog(TESTING,"but printed!"); printf("\n");
     247              :         printf("4.  Must print:");   slog(ERROR,"true"); printf("\n");
     248              : 
     249              :         /* Test VERBOSE mode combinations */
     250              :         rational_logger_mode = VERBOSE;
     251              :         printf("Mode: %s\n",rational_reconvert(rational_logger_mode));
     252              :         printf("5. Won't print:"); slog(REGULAR,"but printed!"); printf("\n");
     253              :         printf("6.  Must print:"); slog(VERBOSE,"true"); printf("\n");
     254              :         printf("7. Won't print:"); slog(TESTING,"but printed!"); printf("\n");
     255              :         printf("8.  Must print:");   slog(ERROR,"true"); printf("\n");
     256              : 
     257              :         /* Test TESTING mode combinations */
     258              :         rational_logger_mode = TESTING;
     259              :         printf("Mode: %s\n",rational_reconvert(rational_logger_mode));
     260              :         printf("9.  Won't print:"); slog(REGULAR,"but printed!"); printf("\n");
     261              :         printf("10. Won't print:"); slog(VERBOSE,"but printed!"); printf("\n");
     262              :         printf("11.  Must print:"); slog(TESTING,"true"); printf("\n");
     263              :         printf("12.  Must print:");   slog(ERROR,"true"); printf("\n");
     264              : 
     265              :         /* Test SILENT mode combinations */
     266              :         rational_logger_mode = SILENT;
     267              :         printf("Mode: %s\n",rational_reconvert(rational_logger_mode));
     268              :         printf("13. Won't print:"); slog(REGULAR,"but printed!"); printf("\n");
     269              :         printf("14. Won't print:"); slog(VERBOSE,"but printed!"); printf("\n");
     270              :         printf("15. Won't print:"); slog(TESTING,"but printed!"); printf("\n");
     271              :         printf("16. Won't print:");   slog(ERROR,"but printed!"); printf("\n");
     272              : 
     273              :         /* Test REGULAR|VERBOSE combinations */
     274              :         rational_logger_mode = REGULAR|VERBOSE;
     275              :         printf("Mode: %s\n",rational_reconvert(rational_logger_mode));
     276              :         printf("17.  Must print:"); slog(REGULAR,"true"); printf("\n");
     277              :         printf("18.  Must print:"); slog(VERBOSE,"true"); printf("\n");
     278              :         printf("19. Won't print:"); slog(TESTING,"but printed!"); printf("\n");
     279              :         printf("20.  Must print:");   slog(ERROR,"true"); printf("\n");
     280              : 
     281              :         /* Test REGULAR|TESTING combinations */
     282              :         rational_logger_mode = REGULAR|TESTING;
     283              :         printf("Mode: %s\n",rational_reconvert(rational_logger_mode));
     284              :         printf("21.  Must print:"); slog(REGULAR,"true"); printf("\n");
     285              :         printf("22. Won't print:"); slog(VERBOSE,"but printed!"); printf("\n");
     286              :         printf("23.  Must print:"); slog(TESTING,"true"); printf("\n");
     287              :         printf("24.  Must print:"); slog(ERROR,"true"); printf("\n");
     288              : 
     289              :         /* Test VERBOSE|TESTING combinations */
     290              :         rational_logger_mode = VERBOSE|TESTING;
     291              :         printf("Mode: %s\n",rational_reconvert(rational_logger_mode));
     292              :         printf("25. Won't print:"); slog(REGULAR,"but printed!"); printf("\n");
     293              :         printf("26.  Must print:"); slog(VERBOSE,"true"); printf("\n");
     294              :         printf("27.  Must print:"); slog(TESTING,"true"); printf("\n");
     295              :         printf("28.  Must print:");   slog(ERROR,"true"); printf("\n");
     296              : 
     297              :         /* Test REGULAR|VERBOSE|TESTING combinations */
     298              :         rational_logger_mode = REGULAR|VERBOSE|TESTING;
     299              :         printf("Mode: %s\n",rational_reconvert(rational_logger_mode));
     300              :         printf("29. Must print:"); slog(REGULAR,"true"); printf("\n");
     301              :         printf("30. Must print:"); slog(VERBOSE,"true"); printf("\n");
     302              :         printf("31. Must print:"); slog(TESTING,"true"); printf("\n");
     303              :         printf("32. Must print:");   slog(ERROR,"true"); printf("\n");
     304              : 
     305              :         /* Test ERROR mode combinations */
     306              :         rational_logger_mode = ERROR;
     307              :         printf("Mode: %s\n",rational_reconvert(rational_logger_mode));
     308              :         printf("33. Won't print:"); slog(REGULAR,"but printed!"); printf("\n");
     309              :         printf("34. Won't print:"); slog(VERBOSE,"but printed!"); printf("\n");
     310              :         printf("35. Won't print:"); slog(TESTING,"but printed!"); printf("\n");
     311              :         printf("36.  Must print:");   slog(ERROR,"true"); printf("\n");
     312              : 
     313              :         /*
     314              :          * Test UNDECOR flag: suppress logger prefixes (TESTING:, time/file/line/func, ERROR:)
     315              :          * The output between the '|' markers should contain only the message payload.
     316              :          */
     317              : 
     318              :         rational_logger_mode = EVERY|ERROR;
     319              :         printf("Mode: %s\n",rational_reconvert(rational_logger_mode));
     320              :         printf("37. Must print no prefixes:|"); slog(EVERY|UNDECOR,"true"); printf("|\n");
     321              :         printf("38. Must print no ERROR prefix:|"); slog(ERROR|UNDECOR,"true"); printf("|\n");
     322              : 
     323              :         rational_logger_mode = VERBOSE;
     324              :         printf("Mode: %s\n",rational_reconvert(rational_logger_mode));
     325              :         printf("39. Must print no time/file/line/func:|"); slog(VERBOSE|UNDECOR,"true"); printf("|\n");
     326              : 
     327              :         rational_logger_mode = TESTING;
     328              :         printf("Mode: %s\n",rational_reconvert(rational_logger_mode));
     329              :         printf("40. Must print no TESTING prefix:|"); slog(TESTING|UNDECOR,"true"); printf("|\n");
     330              : 
     331              :         rational_logger_mode = REGULAR;
     332              :         printf("Mode: %s\n",rational_reconvert(rational_logger_mode));
     333              :         printf("41. Must not print (VERBOSE not enabled):|"); slog(VERBOSE|UNDECOR,"but printed!"); printf("|\n");
     334              : 
     335              :         return 0;
     336              : }
     337              : #endif
        

Generated by: LCOV version 2.0-1