Line data Source code
1 : // Copyright (c) 2011-2023 Made to Order Software Corp. All Rights Reserved 2 : // 3 : // https://snapwebsites.org/project/as2js 4 : // contact@m2osw.com 5 : // 6 : // This program is free software: you can redistribute it and/or modify 7 : // it under the terms of the GNU General Public License as published by 8 : // the Free Software Foundation, either version 3 of the License, or 9 : // (at your option) any later version. 10 : // 11 : // This program is distributed in the hope that it will be useful, 12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 : // GNU General Public License for more details. 15 : // 16 : // You should have received a copy of the GNU General Public License 17 : // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 : 19 : // self 20 : // 21 : #include <tests/license.h> 22 : 23 : 24 : // snapdev 25 : // 26 : #include <snapdev/pathinfo.h> 27 : #include <snapdev/stringize.h> 28 : 29 : 30 : // as2js 31 : // 32 : #include <as2js/json.h> 33 : #include <as2js/message.h> 34 : #include <as2js/version.h> 35 : 36 : 37 : // C 38 : // 39 : #include <string.h> 40 : #include <unistd.h> 41 : 42 : 43 : // last include 44 : // 45 : #include <snapdev/poison.h> 46 : 47 : 48 : 49 : 50 : 51 : class messages 52 : : public as2js::message_callback 53 : { 54 : public: 55 32 : messages() 56 32 : { 57 32 : as2js::set_message_callback(this); 58 32 : } 59 : 60 : // implementation of the output 61 0 : virtual void output( 62 : as2js::message_level_t message_level 63 : , as2js::err_code_t error_code 64 : , as2js::position const & pos 65 : , std::string const & message) 66 : { 67 0 : std::cerr << "error:" << static_cast<int>(message_level) 68 0 : << ":" << static_cast<int>(error_code) 69 0 : << ":" << pos 70 0 : << ":" << message << std::endl; 71 0 : } 72 : }; 73 : 74 : 75 : 76 : #pragma GCC diagnostic ignored "-Wpedantic" 77 32 : int main(int argc, char **argv) 78 : { 79 32 : int err(0); 80 32 : bool newlines(false); 81 32 : bool keep_comments(false); 82 224 : std::string const progname(snapdev::pathinfo::basename(std::string(argv[0]))); 83 32 : std::string output_filename; 84 32 : std::vector<std::string> input_filenames; 85 : 86 128 : for(int i(1); i < argc; ++i) 87 : { 88 96 : if(strcmp(argv[i], "--license") == 0) 89 : { 90 0 : std::cout << as2js_tools::license; 91 0 : return 1; 92 : } 93 96 : if(strcmp(argv[i], "--help") == 0 94 96 : || strcmp(argv[i], "-h") == 0) 95 : { 96 : std::cout << "Usage: " << progname << " [--opt ...] <input> ...\n" 97 : "where --opt is one of:\n" 98 : " --copyright print this tool copyright notice\n" 99 : " --help | -h print out the help screen\n" 100 : " --license show the license\n" 101 : " --keep-comments keep comments in output\n" 102 : " --newlines insert newlines in the output\n" 103 : " --version print the version of the as2js project\n" 104 0 : " --output | -o <filename> the name of the output file\n" 105 : ; 106 0 : return 1; 107 : } 108 96 : if(strcmp(argv[i], "--version") == 0) 109 : { 110 0 : std::cout << AS2JS_VERSION_STRING << std::endl; 111 0 : return 1; 112 : } 113 96 : if(strcmp(argv[i], "--copyright") == 0) 114 : { 115 : std::cout << "Copyright (c) 2005-" 116 : SNAPDEV_STRINGIZE(UTC_BUILD_YEAR) 117 0 : " by Made to Order Software Corporation, All Rights Reserved"; 118 0 : return 1; 119 : } 120 : 121 96 : if(strcmp(argv[i], "--newlines") == 0) 122 : { 123 32 : newlines = true; 124 : } 125 64 : else if(strcmp(argv[i], "--keep-comments") == 0) 126 : { 127 0 : keep_comments = true; 128 : } 129 64 : else if(strcmp(argv[i], "--output") == 0 130 64 : || strcmp(argv[i], "-o") == 0) 131 : { 132 32 : ++i; 133 32 : if(i >= argc) 134 : { 135 0 : std::cerr << "json-to-string:error: --output must be followed by a filename.\n"; 136 0 : return 1; 137 : } 138 32 : if(!output_filename.empty()) 139 : { 140 0 : std::cerr << "json-to-string:error: --output can only be used once.\n"; 141 0 : return 1; 142 : } 143 32 : output_filename = argv[i]; 144 : } 145 32 : else if(argv[i][0] == '-') 146 : { 147 : std::cerr 148 : << "json-to-string:error: unknown command line option \"" 149 0 : << argv[i] 150 0 : << "\".\n"; 151 0 : return 1; 152 : } 153 32 : else if(argv[i][0] == '\0') 154 : { 155 0 : std::cerr << "json-to-string:error: a filename must be specified (an empty parameter is not acceptable).\n"; 156 0 : return 1; 157 : } 158 : else 159 : { 160 32 : input_filenames.push_back(argv[i]); 161 : } 162 : } 163 : 164 32 : as2js::output_stream<std::ofstream>::pointer_t out(std::make_shared<as2js::output_stream<std::ofstream>>()); 165 32 : out->open(output_filename); 166 32 : if(!out->is_open()) 167 : { 168 : std::cerr 169 : << "error: could not open output file \"" 170 : << output_filename 171 0 : << "\" for writing.\n"; 172 0 : return 1; 173 : } 174 : 175 32 : messages msg; 176 32 : std::size_t max_filenames(input_filenames.size()); 177 64 : for(std::size_t idx(0); idx < max_filenames; ++idx) 178 : { 179 : // first we use JSON to load the file, if we detect an 180 : // error return 1 instead of 0 181 : // 182 32 : std::string filename(input_filenames[idx]); 183 32 : as2js::json::pointer_t load_json(std::make_shared<as2js::json>()); 184 32 : as2js::json::json_value::pointer_t loaded_value(load_json->load(filename)); 185 32 : if(loaded_value != nullptr) 186 : { 187 32 : as2js::input_stream<std::ifstream>::pointer_t in(std::make_shared<as2js::input_stream<std::ifstream>>()); 188 32 : in->open(filename); 189 32 : if(in->is_open()) 190 : { 191 32 : char32_t c(0); 192 39706 : while(c != as2js::CHAR32_EOF) 193 : { 194 : // read one line of JSON 195 39674 : std::string str; 196 39674 : std::string indent; 197 : for(;;) 198 : { 199 1732566 : c = in->get(); 200 1732566 : if(c == as2js::CHAR32_EOF || c == '\n') 201 : { 202 : break; 203 : } 204 1692892 : if((c == ' ' || c == '\t') && str.empty()) 205 : { 206 : // left trim 207 1221167 : indent += c; 208 1221167 : continue; 209 : } 210 471725 : if(str.empty() && c == '/') 211 : { 212 1649 : c = in->get(); 213 1649 : if(c == '/') 214 : { 215 : // read comments 216 1649 : str += "/"; 217 : do 218 : { 219 36205 : str += c; 220 36205 : c = in->get(); 221 : } 222 36205 : while(c != as2js::CHAR32_EOF && c != '\n'); 223 1649 : if(keep_comments) 224 : { 225 : // keep the comments, but not inside the JSON strings 226 0 : out->write_string(indent); 227 0 : out->write_string(str); 228 0 : if(str[str.length() - 1] == '\\') 229 : { 230 : // we add a $ when str ends with a '\' 231 0 : out->write_string("$"); 232 : } 233 0 : out->write_string("\n"); 234 : } 235 1649 : indent.clear(); 236 1649 : str.clear(); 237 1649 : continue; 238 : } 239 : } 240 470076 : if(c == '"') 241 : { 242 : // add 1 '\' characters in front of the '"' 243 62368 : str += "\\\""; 244 : } 245 407708 : else if(c == '\\') 246 : { 247 : // add 2 '\' character for each '\' 248 2958 : str += "\\\\"; 249 : } 250 : else 251 : { 252 404750 : str += c; 253 : } 254 : } 255 39674 : if(!str.empty()) 256 : { 257 : // if string ends with "\" then we need to add a "\n" 258 39006 : if(newlines 259 39006 : || str[str.length() - 1] == '\\') 260 : { 261 39006 : str += "\\n"; 262 : } 263 : 264 : // output this one line as a C++ string 265 : // 266 39006 : out->write_string(indent); 267 39006 : out->write_string("\""); 268 39006 : out->write_string(str); 269 39006 : out->write_string("\"\n"); 270 : } 271 39674 : } 272 : } 273 : else 274 : { 275 0 : as2js::message err_msg(as2js::message_level_t::MESSAGE_LEVEL_FATAL, as2js::err_code_t::AS_ERR_CANNOT_COMPILE, loaded_value->get_position()); 276 0 : err_msg << "could not re-open this JSON input file \"" << filename << "\"."; 277 0 : err = 1; 278 0 : } 279 32 : } 280 : else 281 : { 282 0 : err = 1; 283 : } 284 32 : } 285 : 286 32 : if(err == 1) 287 : { 288 : // on error make sure to delete because otherwise cmake thinks 289 : // that the target is all good. 290 : // 291 0 : unlink(output_filename.c_str()); 292 : } 293 : 294 32 : return err; 295 32 : } 296 : 297 : // vim: ts=4 sw=4 et