LCOV - code coverage report
Current view: top level - src/plugins/lineendings - lineendings.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 60 65 92.3 %
Date: 2019-09-12 12:28:41 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Source for lineendings plugin
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  *
       8             :  */
       9             : 
      10             : 
      11             : #ifndef HAVE_KDBCONFIG
      12             : #include "kdbconfig.h"
      13             : #endif
      14             : 
      15             : #include "lineendings.h"
      16             : #include <kdberrors.h>
      17             : #include <stdio.h>
      18             : #include <string.h>
      19             : #include <unistd.h>
      20             : 
      21             : #define LF_BYTE 0x0A
      22             : #define CR_BYTE 0x0D
      23             : 
      24             : typedef enum
      25             : {
      26             :         NA,
      27             :         CR,
      28             :         LF,
      29             :         CRLF,
      30             :         LFCR,
      31             :         NUM_TYPES
      32             : } Lineending;
      33             : 
      34             : static inline char * LEString (Lineending index)
      35             : {
      36             :         static char * strings[] = { "NA", "CR", "LF", "CRLF", "LFCR" };
      37          56 :         if (index > NUM_TYPES) return NULL;
      38          56 :         return strings[index];
      39             : }
      40          12 : static Lineending strToLE (const char * str)
      41             : {
      42          12 :         uint8_t counter = 0;
      43          64 :         for (; counter < NUM_TYPES; ++counter)
      44             :         {
      45         112 :                 if (!strcmp (LEString (counter), str)) return counter;
      46             :         }
      47             :         return NA;
      48             : }
      49          12 : static int checkLineEndings (const char * fileName, Lineending validLineEnding, Key * parentKey)
      50             : {
      51             :         FILE * fp;
      52          12 :         fp = fopen (fileName, "rb");
      53          12 :         if (fp == NULL)
      54             :         {
      55             :                 return -1;
      56             :         }
      57             : 
      58          12 :         Lineending lineEnding = NA;
      59          12 :         Lineending found = NA;
      60             :         uint8_t fc, sc;
      61          12 :         unsigned long line = 1;
      62          12 :         fc = sc = 0;
      63          12 :         (void) fread (&fc, 1, 1, fp);
      64         132 :         while (!feof (fp))
      65             :         {
      66         116 :                 (void) fread (&sc, 1, 1, fp);
      67         116 :                 switch (fc)
      68             :                 {
      69             :                 case LF_BYTE:
      70           8 :                         if (sc == CR_BYTE)
      71             :                                 found = LFCR;
      72           8 :                         else if (sc == LF_BYTE)
      73             :                                 found = LF;
      74           4 :                         else if (sc)
      75           4 :                                 found = LF;
      76             :                         break;
      77             :                 case CR_BYTE:
      78          12 :                         if (sc == LF_BYTE)
      79             :                                 found = CRLF;
      80           0 :                         else if (sc == CR_BYTE)
      81             :                                 found = CR;
      82           0 :                         else if (sc)
      83           0 :                                 found = CR;
      84             :                         break;
      85             :                 }
      86         116 :                 if (found == CRLF || found == LFCR)
      87             :                 {
      88          12 :                         (void) fread (&sc, 1, 1, fp);
      89             :                 }
      90         116 :                 if (lineEnding == NA && found != NA)
      91             :                 {
      92          12 :                         lineEnding = found;
      93          12 :                         if (validLineEnding != NA && lineEnding != validLineEnding)
      94             :                         {
      95           4 :                                 fclose (fp);
      96           4 :                                 ELEKTRA_SET_VALIDATION_SYNTACTIC_ERRORF (parentKey, "Invalid line ending at line %lu", line);
      97           4 :                                 return -2;
      98             :                         }
      99           8 :                         ++line;
     100             :                 }
     101         104 :                 else if (lineEnding != found && found != NA)
     102             :                 {
     103           4 :                         fclose (fp);
     104           4 :                         ELEKTRA_SET_VALIDATION_SYNTACTIC_ERRORF (parentKey, "Inconsistent line endings at line %lu", line);
     105           4 :                         return -3;
     106             :                 }
     107         108 :                 fc = sc;
     108         108 :                 found = NA;
     109             :         }
     110           4 :         fclose (fp);
     111           4 :         return 0;
     112             : }
     113             : 
     114          26 : int elektraLineendingsGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned ELEKTRA_UNUSED, Key * parentKey ELEKTRA_UNUSED)
     115             : {
     116          26 :         if (!strcmp (keyName (parentKey), "system/elektra/modules/lineendings"))
     117             :         {
     118          20 :                 KeySet * contract = ksNew (
     119             :                         30, keyNew ("system/elektra/modules/lineendings", KEY_VALUE, "lineendings plugin waits for your orders", KEY_END),
     120             :                         keyNew ("system/elektra/modules/lineendings/exports", KEY_END),
     121             :                         keyNew ("system/elektra/modules/lineendings/exports/get", KEY_FUNC, elektraLineendingsGet, KEY_END),
     122             :                         keyNew ("system/elektra/modules/lineendings/exports/set", KEY_FUNC, elektraLineendingsSet, KEY_END),
     123             : #include ELEKTRA_README
     124             :                         keyNew ("system/elektra/modules/lineendings/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
     125          20 :                 ksAppend (returned, contract);
     126          20 :                 ksDel (contract);
     127             : 
     128          20 :                 return 1; /* success */
     129             :         }
     130             :         /* get all keys */
     131           6 :         KeySet * config = elektraPluginGetConfig (handle);
     132           6 :         Key * valid = ksLookupByName (config, "/valid", 0);
     133           6 :         Lineending validLineEnding = strToLE (keyString (valid));
     134             :         int ret;
     135           6 :         ret = checkLineEndings (keyString (parentKey), validLineEnding, parentKey);
     136           6 :         if (ret == (-3))
     137             :         {
     138             :                 return -1;
     139             :         }
     140             :         else
     141           4 :                 return 1;
     142             : }
     143             : 
     144           6 : int elektraLineendingsSet (Plugin * handle, KeySet * returned ELEKTRA_UNUSED, Key * parentKey)
     145             : {
     146           6 :         KeySet * config = elektraPluginGetConfig (handle);
     147           6 :         Key * valid = ksLookupByName (config, "/valid", 0);
     148           6 :         Lineending validLineEnding = strToLE (keyString (valid));
     149             :         int ret;
     150           6 :         ret = checkLineEndings (keyString (parentKey), validLineEnding, parentKey);
     151           6 :         switch (ret)
     152             :         {
     153             :         case (-1):
     154           0 :                 ELEKTRA_SET_RESOURCE_ERRORF (parentKey, "Couldn't open file %s\n", keyString (parentKey));
     155           0 :                 return 1;
     156             :                 break;
     157             :         case (-2):
     158             :                 return -1;
     159             :                 break;
     160             :         case (-3):
     161             :                 return -1;
     162             :                 break;
     163             :         case 0:
     164             :         default:
     165           2 :                 return 1;
     166             :                 break;
     167             :         }
     168             : }
     169             : 
     170          26 : Plugin * ELEKTRA_PLUGIN_EXPORT
     171             : {
     172             :         // clang-format off
     173          26 :         return elektraPluginExport("lineendings",
     174             :                         ELEKTRA_PLUGIN_GET,     &elektraLineendingsGet,
     175             :                         ELEKTRA_PLUGIN_SET,     &elektraLineendingsSet,
     176             :                         //      ELEKTRA_PLUGIN_ERROR,   &elektraLineendingsError,
     177             :                         ELEKTRA_PLUGIN_END);
     178             : }
     179             : 

Generated by: LCOV version 1.13