nis-util
1.0.D108
|
00001 // 00002 // nis-util - NIS Administration Utilities 00003 // Copyright (C) 2012 Peter Miller 00004 // 00005 // This program is free software; you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation; either version 2 of the License, or (at 00008 // your option) any later version. 00009 // 00010 // This program is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 // General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License along 00016 // with this program. If not, see <http://www.gnu.org/licenses/>. 00017 // 00018 00019 #include <lib/ac/ctype.h> 00020 00021 #include <lib/rcstring.h> 00022 #include <lib/rcstring/accumulator.h> 00023 00024 00025 rcstring 00026 rcstring::quote_shell(void) 00027 const 00028 { 00029 // 00030 // Work out if the string needs quoting. 00031 // and how long the output will be. 00032 // 00033 const char *start = c_str(); 00034 const char *end = start + size(); 00035 bool single_quotes = false; 00036 bool double_quotes = false; 00037 unsigned char mode = '\0'; 00038 for (const char *cp = start; cp < end; ++cp) 00039 { 00040 unsigned char c = *cp; 00041 switch (c) 00042 { 00043 default: 00044 if (!isprint(c)) 00045 { 00046 single_quotes = true; 00047 if (!mode) 00048 mode = '\''; 00049 } 00050 break; 00051 00052 00053 case '\'': 00054 double_quotes = true; 00055 if (!mode) 00056 mode = '"'; 00057 break; 00058 00059 case '!': 00060 // The exclamation mark is special for bash and csh, and can 00061 // only be quoted with single quotes. 00062 // 00063 // Fall through... 00064 00065 case '"': case '$': case '\\': 00066 case '`': case '~': 00067 single_quotes = true; 00068 if (!mode) 00069 mode = '\''; 00070 break; 00071 00072 case '\t': case ' ': case '#': case '&': case '(': case ')': case '*': 00073 case ':': case ';': case '<': case '=': case '>': case '?': case '[': 00074 case ']': case '^': case '{': case '|': case '}': 00075 single_quotes = true; 00076 double_quotes = true; 00077 break; 00078 } 00079 } 00080 00081 // 00082 // If it doesn't need quoting, just pass it through. 00083 // 00084 if (!single_quotes && !double_quotes) 00085 { 00086 return rcstring(start, size()); 00087 } 00088 00089 // 00090 // If we have a choice, use single quote mode, 00091 // it's usually shorter and it's easier to read. 00092 // 00093 if (!mode) 00094 { 00095 // Only use double quotes if we have to. 00096 mode = (double_quotes ? '"' : '\''); 00097 } 00098 00099 // 00100 // Form the quoted string, using the minimum number of escapes. 00101 // 00102 // The gotcha here is the backquote: the `blah` substitution is 00103 // still active within double quotes. And so are a few others. 00104 // 00105 // Also, there are some difficulties: the single quote can't be 00106 // quoted within single quotes, and the exclamation mark can't 00107 // be quoted by anything *except* single quotes. Sheesh. 00108 // 00109 // Also, the rules change depending on which style of quoting 00110 // is in force at the time. 00111 // 00112 rcstring_accumulator buf; 00113 buf.push_back(mode); 00114 for (const char *cp = start; cp < end; ++cp) 00115 { 00116 unsigned char c = *cp; 00117 if (mode == '\'') 00118 { 00119 // within single quotes 00120 if (c == '\'') 00121 { 00122 // 00123 // You can't quote a single quote within single quotes. 00124 // Need to change to double quote mode. 00125 // 00126 buf.push_back("'\"'", 3); 00127 mode = '"'; 00128 } 00129 else 00130 buf.push_back(c); 00131 } 00132 else 00133 { 00134 // within double quotes 00135 switch (c) 00136 { 00137 case '!': 00138 // 00139 // You can't quote an exclamation mark within double 00140 // quotes. Need to change to single quote mode. 00141 // 00142 buf.push_back("\"'!", 3); 00143 mode = '\''; 00144 break; 00145 00146 case '\n': 00147 case '"': 00148 case '\\': 00149 case '`': // stop command substitutions 00150 case '$': // stop variable substitutions 00151 buf.push_back('\\'); 00152 // fall through... 00153 00154 default: 00155 buf.push_back(c); 00156 break; 00157 } 00158 } 00159 } 00160 buf.push_back(mode); 00161 return buf.mkstr(); 00162 } 00163 00164 00165 // vim: set ts=8 sw=4 et :