1 1.8 christos /* $NetBSD: shquote.c,v 1.8 2006/03/19 02:33:02 christos Exp $ */ 2 1.1 cgd 3 1.1 cgd /* 4 1.1 cgd * Copyright (c) 2001 Christopher G. Demetriou 5 1.1 cgd * All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.1 cgd * 3. All advertising materials mentioning features or use of this software 16 1.1 cgd * must display the following acknowledgement: 17 1.1 cgd * This product includes software developed for the 18 1.5 salo * NetBSD Project. See http://www.NetBSD.org/ for 19 1.1 cgd * information about NetBSD. 20 1.1 cgd * 4. The name of the author may not be used to endorse or promote products 21 1.1 cgd * derived from this software without specific prior written permission. 22 1.1 cgd * 23 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 1.1 cgd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 1.1 cgd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 1.1 cgd * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 1.1 cgd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 1.1 cgd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 1.1 cgd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 1.1 cgd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 1.1 cgd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 1.1 cgd * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 1.1 cgd * 34 1.1 cgd * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>> 35 1.1 cgd */ 36 1.1 cgd 37 1.7 lukem #include <sys/cdefs.h> 38 1.7 lukem #if defined(LIBC_SCCS) && !defined(lint) 39 1.8 christos __RCSID("$NetBSD: shquote.c,v 1.8 2006/03/19 02:33:02 christos Exp $"); 40 1.7 lukem #endif /* LIBC_SCCS and not lint */ 41 1.7 lukem 42 1.1 cgd /* 43 1.1 cgd * Define SHQUOTE_USE_MULTIBYTE if you want shquote() to handle multibyte 44 1.1 cgd * characters using mbrtowc(). 45 1.1 cgd * 46 1.1 cgd * Please DO NOT rip this #ifdef out of the code. It's also here to help 47 1.1 cgd * portability. 48 1.1 cgd */ 49 1.3 cgd #undef SHQUOTE_USE_MULTIBYTE 50 1.1 cgd 51 1.6 kleink #include "namespace.h" 52 1.1 cgd #include <stdlib.h> 53 1.4 simonb #include <string.h> 54 1.1 cgd #ifdef SHQUOTE_USE_MULTIBYTE 55 1.2 christos #include <limits.h> 56 1.1 cgd #include <stdio.h> 57 1.1 cgd #include <wchar.h> 58 1.1 cgd #endif 59 1.1 cgd 60 1.6 kleink #ifdef __weak_alias 61 1.6 kleink __weak_alias(shquote,_shquote) 62 1.6 kleink #endif 63 1.6 kleink 64 1.1 cgd /* 65 1.1 cgd * shquote(): 66 1.1 cgd * 67 1.1 cgd * Requotes arguments so that they'll be interpreted properly by the 68 1.1 cgd * shell (/bin/sh). 69 1.1 cgd * 70 1.1 cgd * Wraps single quotes around the string, and replaces single quotes 71 1.1 cgd * in the string with the sequence: 72 1.1 cgd * '\'' 73 1.1 cgd * 74 1.1 cgd * Returns the number of characters required to hold the resulting quoted 75 1.1 cgd * argument. 76 1.1 cgd * 77 1.1 cgd * The buffer supplied is filled in and NUL-terminated. If 'bufsize' 78 1.1 cgd * indicates that the buffer is too short to hold the output string, the 79 1.1 cgd * first (bufsize - 1) bytes of quoted argument are filled in and the 80 1.1 cgd * buffer is NUL-terminated. 81 1.1 cgd * 82 1.1 cgd * Changes could be made to optimize the length of strings output by this 83 1.1 cgd * function: 84 1.1 cgd * 85 1.1 cgd * * if there are no metacharacters or whitespace in the input, 86 1.1 cgd * the output could be the input string. 87 1.1 cgd */ 88 1.1 cgd 89 1.1 cgd #ifdef SHQUOTE_USE_MULTIBYTE 90 1.1 cgd 91 1.1 cgd #define XLATE_OUTCH(x) wcrtomb(outch, (x), &mbso) 92 1.1 cgd #define XLATE_INCH() \ 93 1.1 cgd do { \ 94 1.1 cgd n = mbrtowc(&c, arg, MB_CUR_MAX, &mbsi); \ 95 1.2 christos } while (/*LINTED const cond*/0) 96 1.1 cgd 97 1.1 cgd #else 98 1.1 cgd 99 1.1 cgd #define XLATE_OUTCH(x) (outch[0] = (x), 1) 100 1.1 cgd #define XLATE_INCH() \ 101 1.1 cgd do { \ 102 1.1 cgd n = ((c = *arg) != '\0') ? 1 : 0; \ 103 1.2 christos } while (/*LINTED const cond*/0) 104 1.1 cgd 105 1.1 cgd #endif 106 1.1 cgd 107 1.1 cgd #define PUT(x) \ 108 1.1 cgd do { \ 109 1.1 cgd outchlen = XLATE_OUTCH(x); \ 110 1.1 cgd if (outchlen == (size_t)-1) \ 111 1.1 cgd goto bad; \ 112 1.1 cgd rv += outchlen; \ 113 1.1 cgd if (bufsize != 0) { \ 114 1.1 cgd if (bufsize < outchlen || \ 115 1.1 cgd (bufsize == outchlen && \ 116 1.1 cgd outch[outchlen - 1] != '\0')) { \ 117 1.1 cgd *buf = '\0'; \ 118 1.1 cgd bufsize = 0; \ 119 1.1 cgd } else { \ 120 1.1 cgd memcpy(buf, outch, outchlen); \ 121 1.1 cgd buf += outchlen; \ 122 1.1 cgd bufsize -= outchlen; \ 123 1.1 cgd } \ 124 1.1 cgd } \ 125 1.2 christos } while (/*LINTED const cond*/0) 126 1.1 cgd 127 1.1 cgd size_t 128 1.1 cgd shquote(const char *arg, char *buf, size_t bufsize) 129 1.1 cgd { 130 1.1 cgd #ifdef SHQUOTE_USE_MULTIBYTE 131 1.2 christos char outch[MB_LEN_MAX]; 132 1.1 cgd mbstate_t mbsi, mbso; 133 1.1 cgd wchar_t c, lastc; 134 1.1 cgd size_t outchlen; 135 1.1 cgd #else 136 1.1 cgd char outch[1]; 137 1.1 cgd char c, lastc; 138 1.1 cgd size_t outchlen; 139 1.1 cgd #endif 140 1.1 cgd size_t rv; 141 1.1 cgd int n; 142 1.1 cgd 143 1.1 cgd rv = 0; 144 1.1 cgd lastc = 0; 145 1.1 cgd #ifdef SHQUOTE_USE_MULTIBYTE 146 1.1 cgd memset(&mbsi, 0, sizeof mbsi); 147 1.1 cgd memset(&mbso, 0, sizeof mbso); 148 1.1 cgd #endif 149 1.1 cgd 150 1.1 cgd if (*arg != '\'') 151 1.1 cgd PUT('\''); 152 1.1 cgd for (;;) { 153 1.1 cgd XLATE_INCH(); 154 1.1 cgd if (n <= 0) 155 1.1 cgd break; 156 1.1 cgd arg += n; 157 1.1 cgd lastc = c; 158 1.1 cgd 159 1.1 cgd if (c == '\'') { 160 1.1 cgd if (rv != 0) 161 1.1 cgd PUT('\''); 162 1.1 cgd PUT('\\'); 163 1.1 cgd PUT('\''); 164 1.1 cgd for (;;) { 165 1.1 cgd XLATE_INCH(); 166 1.1 cgd if (n <= 0 || c != '\'') 167 1.1 cgd break; 168 1.1 cgd PUT('\\'); 169 1.1 cgd PUT('\''); 170 1.1 cgd arg += n; 171 1.1 cgd } 172 1.1 cgd if (n > 0) 173 1.1 cgd PUT('\''); 174 1.1 cgd } else 175 1.1 cgd PUT(c); 176 1.1 cgd } 177 1.1 cgd if (lastc != '\'') 178 1.1 cgd PUT('\''); 179 1.1 cgd 180 1.1 cgd /* Put multibyte or NUL terminator, but don't count the NUL. */ 181 1.1 cgd PUT('\0'); 182 1.1 cgd rv--; 183 1.1 cgd 184 1.1 cgd return rv; 185 1.1 cgd 186 1.1 cgd bad: 187 1.1 cgd /* A multibyte character encoding or decoding error occurred. */ 188 1.2 christos return (size_t)-1; 189 1.1 cgd } 190