LCOV - code coverage report
Current view: top level - src - parse_source.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 95.5 % 44 42
Test Date: 2026-10-20 14:27:43 Functions: 100.0 % 2 2
Branches: 94.7 % 19 18

             Branch data     Line data    Source code
       1                 :             : #include "precizer.h"
       2                 :             : #include <sysexits.h>
       3                 :             : 
       4                 :             : /**
       5                 :             :  * @brief Collect the config path and detect other arguments without applying settings
       6                 :             :  *
       7                 :             :  * The shared option table lets argp distinguish options from their values.
       8                 :             :  * Lifecycle events do not count as arguments. Information requests are recorded
       9                 :             :  * for source selection; the main parser handles their output. A nonzero quoted
      10                 :             :  * value rejects the invocation silently so no file is read and the main parser reports it
      11                 :             :  *
      12                 :             :  * @param key Option key or argp event
      13                 :             :  * @param arg Option value or positional argument
      14                 :             :  * @param state Preliminary parser state with ArgumentParseContext in input
      15                 :             :  * @return EX_OK on success, EX_USAGE for argp-marked --, or ARGP_ERR_UNKNOWN for bulk operands
      16                 :             :  */
      17                 :        8419 : error_t parse_source_option(
      18                 :             :         int               key,
      19                 :             :         char              *arg,
      20                 :             :         struct argp_state *state)
      21                 :             : {
      22                 :        8419 :         ArgumentParseContext *context = state->input;
      23                 :             : 
      24   [ +  +  +  +  :        8419 :         switch(key)
                +  -  + ]
      25                 :             :         {
      26                 :         369 :                 case 'g':
      27                 :             :                         /* Repeated selections replace the path; no file has been opened */
      28                 :         369 :                         config->config_file_path = arg;
      29                 :         369 :                         break;
      30                 :         151 :                 case 'h':
      31                 :             :                 case '?':
      32                 :             :                 case 'z':
      33                 :             :                 case 'V':
      34                 :             :                         /* Information requests bypass file selection; output stays in the main pass */
      35                 :         151 :                         context->information_mode_requested = true;
      36                 :         151 :                         context->has_other_arguments = true;
      37                 :         151 :                         break;
      38                 :        1128 :                 case ARGP_KEY_END:
      39                 :             :                         /* Rely on argp's marker without distinguishing option values from delimiters */
      40         [ +  + ]:        1128 :                         if(state->quoted != 0)
      41                 :             :                         {
      42                 :          34 :                                 return(EX_USAGE);
      43                 :             :                         }
      44                 :        1094 :                         break;
      45                 :        1094 :                 case ARGP_KEY_SUCCESS:
      46                 :             :                         /* Argp has initialized the diagnostic name and stream by this event.
      47                 :             :                            Retain only these fields: the name refers to argv storage, and the
      48                 :             :                            stream remains open after this pass. The parser state itself expires
      49                 :             :                            when argp_parse() returns and must not be retained */
      50                 :        1094 :                         context->diagnostic_state.name = state->name;
      51                 :        1094 :                         context->diagnostic_state.err_stream = state->err_stream;
      52                 :        1094 :                         break;
      53                 :        2822 :                 case ARGP_KEY_INIT:
      54                 :             :                 case ARGP_KEY_NO_ARGS:
      55                 :             :                 case ARGP_KEY_ERROR:
      56                 :             :                 case ARGP_KEY_FINI:
      57                 :        2822 :                         break;
      58                 :           0 :                 case ARGP_KEY_ARGS:
      59                 :           0 :                         return(ARGP_ERR_UNKNOWN);
      60                 :        2855 :                 default:
      61                 :             :                         /* Every other option and each positional operand selects CLI settings */
      62                 :        2855 :                         context->has_other_arguments = true;
      63                 :        2855 :                         break;
      64                 :             :         }
      65                 :             : 
      66                 :        8385 :         return(EX_OK);
      67                 :             : }
      68                 :             : 
      69                 :             : /**
      70                 :             :  * @brief Select a configuration file or CLI-only parsing without opening files
      71                 :             :  *
      72                 :             :  * Config supplies the last explicit config path; the context records whether
      73                 :             :  * other CLI arguments were found. Information requests discard the path and use
      74                 :             :  * CLI only. Otherwise, an explicit path conflicts with any other arguments.
      75                 :             :  * Without an explicit path, only an argument-free invocation selects the
      76                 :             :  * optional default file. A preliminary parse error discards partial results
      77                 :             :  * silently so the main CLI parser can report the error.
      78                 :             :  * Paths are borrowed from argv or static storage; this function does not copy
      79                 :             :  * or validate them. An empty explicit path still selects a required file
      80                 :             :  *
      81                 :             :  * @param argc Original CLI argument count, including the program name
      82                 :             :  * @param preliminary_error Return code from preliminary argp parsing
      83                 :             :  * @param[in,out] context Preliminary flags; receives whether the selected file is required
      84                 :             :  * @return SUCCESS for a selected source or deferred CLI error, FAILURE for a source conflict
      85                 :             :  */
      86                 :        1174 : Return select_settings_source(
      87                 :             :         const int            argc,
      88                 :             :         error_t              preliminary_error,
      89                 :             :         ArgumentParseContext *context)
      90                 :             : {
      91                 :             :         /* Status returned by this function through deliver()
      92                 :             :            Default value assumes successful completion */
      93                 :        1174 :         Return status = SUCCESS;
      94                 :             : 
      95                 :             :         /* Start with no requirement for a file to exist. Only an explicit config
      96                 :             :            path accepted without conflicting arguments makes the file required */
      97                 :        1174 :         context->config_required = false;
      98                 :             : 
      99         [ +  + ]:        1174 :         if(preliminary_error != EX_OK)
     100                 :             :         {
     101                 :             :                 /* Preliminary parsing may have collected only part of the arguments.
     102                 :             :                    Discard those results so no file is selected. Leave SUCCESS and print
     103                 :             :                    nothing here; the main CLI parser must diagnose the original arguments */
     104                 :          69 :                 config->config_file_path = NULL;
     105                 :          69 :                 context->has_other_arguments = false;
     106                 :          69 :                 context->information_mode_requested = false;
     107                 :             : 
     108         [ +  + ]:        1105 :         } else if(context->information_mode_requested){
     109                 :             :                 /* Ignore even an explicit file and leave information output and CLI
     110                 :             :                    value validation to the main parser */
     111                 :         136 :                 config->config_file_path = NULL;
     112                 :             : 
     113         [ +  + ]:         969 :         } else if(config->config_file_path != NULL){
     114                 :             : 
     115                 :             :                 /* A non-NULL path records an explicit --config or -g selection.
     116                 :             :                    Even an empty string counts as explicit; the reader handles opening */
     117         [ +  + ]:         286 :                 if(context->has_other_arguments)
     118                 :             :                 {
     119                 :             :                         /* An explicit file cannot be combined with other CLI arguments.
     120                 :             :                            Report the conflict and clear the path before any file is opened.
     121                 :             :                            FAILURE tells the caller to stop instead of applying either source */
     122                 :         115 :                         argp_failure(&context->diagnostic_state,0,0,"ERROR: --config cannot be combined with other arguments. Use either a config file or CLI arguments");
     123                 :         115 :                         config->config_file_path = NULL;
     124                 :         115 :                         status = FAILURE;
     125                 :             : 
     126                 :             :                 } else {
     127                 :             :                         /* Keep the explicit path as the sole settings source. Its absence
     128                 :             :                            must be reported as an error when the reader attempts to open it */
     129                 :         171 :                         context->config_required = true;
     130                 :             :                 }
     131                 :             : 
     132         [ +  + ]:         683 :         } else if(argc == 1){
     133                 :             :                 /* argc includes the program name, so 1 means no CLI arguments.
     134                 :             :                    Select the default file in the working directory and keep it optional */
     135                 :          19 :                 config->config_file_path = APP_NAME ".conf";
     136                 :             :         }
     137                 :             : 
     138                 :             :         /* With other CLI arguments and no explicit config path, the path stays
     139                 :             :            NULL and only CLI settings apply. Return the source-selection status */
     140                 :        1174 :         deliver(status);
     141                 :             : }
        

Generated by: LCOV version 2.0-1