(root)/
util-linux-2.39/
lib/
mangle.c
       1  /*
       2   * Functions for \oct encoding used in mtab/fstab/swaps/etc.
       3   *
       4   * No copyright is claimed.  This code is in the public domain; do with
       5   * it what you wish.
       6   *
       7   * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
       8   */
       9  #include <stdio.h>
      10  #include <stdlib.h>
      11  #include <string.h>
      12  #include <ctype.h>
      13  
      14  #include "mangle.h"
      15  #include "c.h"
      16  
      17  #define isoctal(a)		(((a) & ~7) == '0')
      18  
      19  #define from_hex(c)		(isdigit(c) ? c - '0' : tolower(c) - 'a' + 10)
      20  
      21  #define is_unwanted_char(x)	(strchr(" \t\n\\", (unsigned int) x) != NULL)
      22  
      23  
      24  char *mangle(const char *s)
      25  {
      26  	char *ss, *sp;
      27  
      28  	if (!s)
      29  		return NULL;
      30  
      31  	ss = sp = malloc(4 * strlen(s) + 1);
      32  	if (!sp)
      33  		return NULL;
      34  	while(1) {
      35  		if (!*s) {
      36  			*sp = '\0';
      37  			break;
      38  		}
      39  		if (is_unwanted_char(*s)) {
      40  			*sp++ = '\\';
      41  			*sp++ = '0' + ((*s & 0300) >> 6);
      42  			*sp++ = '0' + ((*s & 070) >> 3);
      43  			*sp++ = '0' + (*s & 07);
      44  		} else
      45  			*sp++ = *s;
      46  		s++;
      47  	}
      48  	return ss;
      49  }
      50  
      51  
      52  void unmangle_to_buffer(const char *s, char *buf, size_t len)
      53  {
      54  	size_t sz = 0;
      55  
      56  	if (!s)
      57  		return;
      58  
      59  	while(*s && sz < len - 1) {
      60  		if (*s == '\\' && sz + 3 < len - 1 && isoctal(s[1]) &&
      61  		    isoctal(s[2]) && isoctal(s[3])) {
      62  
      63  			*buf++ = 64*(s[1] & 7) + 8*(s[2] & 7) + (s[3] & 7);
      64  			s += 4;
      65  			sz += 4;
      66  		} else {
      67  			*buf++ = *s++;
      68  			sz++;
      69  		}
      70  	}
      71  	*buf = '\0';
      72  }
      73  
      74  size_t unhexmangle_to_buffer(const char *s, char *buf, size_t len)
      75  {
      76  	size_t sz = 0;
      77  	const char *buf0 = buf;
      78  
      79  	if (!s)
      80  		return 0;
      81  
      82  	while(*s && sz < len - 1) {
      83  		if (*s == '\\' && sz + 3 < len - 1 && s[1] == 'x' &&
      84  		    isxdigit(s[2]) && isxdigit(s[3])) {
      85  
      86  			*buf++ = from_hex(s[2]) << 4 | from_hex(s[3]);
      87  			s += 4;
      88  			sz += 4;
      89  		} else {
      90  			*buf++ = *s++;
      91  			sz++;
      92  		}
      93  	}
      94  	*buf = '\0';
      95  	return buf - buf0 + 1;
      96  }
      97  
      98  static inline const char *skip_nonspaces(const char *s)
      99  {
     100  	while (s && *s && !(*s == ' ' || *s == '\t'))
     101  		s++;
     102  	return s;
     103  }
     104  
     105  /*
     106   * Returns mallocated buffer or NULL in case of error.
     107   */
     108  char *unmangle(const char *s, const char **end)
     109  {
     110  	char *buf;
     111  	const char *e;
     112  	size_t sz;
     113  
     114  	if (!s)
     115  		return NULL;
     116  
     117  	e = skip_nonspaces(s);
     118  	sz = e - s + 1;
     119  
     120  	if (end)
     121  		*end = e;
     122  	if (e == s)
     123  		return NULL;	/* empty string */
     124  
     125  	buf = malloc(sz);
     126  	if (!buf)
     127  		return NULL;
     128  
     129  	unmangle_to_buffer(s, buf, sz);
     130  	return buf;
     131  }
     132  
     133  #ifdef TEST_PROGRAM_MANGLE
     134  #include <errno.h>
     135  int main(int argc, char *argv[])
     136  {
     137  	char *p = NULL;
     138  	if (argc < 3) {
     139  		fprintf(stderr, "usage: %s --mangle|unmangle <string>\n",
     140  						program_invocation_short_name);
     141  		return EXIT_FAILURE;
     142  	}
     143  
     144  	if (!strcmp(argv[1], "--mangle")) {
     145  		p = mangle(argv[2]);
     146  		printf("mangled: '%s'\n", p);
     147  		free(p);
     148  	}
     149  
     150  	else if (!strcmp(argv[1], "--unmangle")) {
     151  		char *x = unmangle(argv[2], NULL);
     152  
     153  		if (x) {
     154  			printf("unmangled: '%s'\n", x);
     155  			free(x);
     156  		}
     157  
     158  		x = strdup(argv[2]);
     159  		if (x) {
     160  			unmangle_to_buffer(x, x, strlen(x) + 1);
     161  
     162  			printf("self-unmangled: '%s'\n", x);
     163  			free(x);
     164  		}
     165  	}
     166  
     167  	return EXIT_SUCCESS;
     168  }
     169  #endif /* TEST_PROGRAM_MANGLE */