- if (json != NULL && fout != NULL) {
- if (!expand || json[0] != '"' && json[0] != '\'')
- fputs(json, fout);
- else for (size_t i(0); i != size; ++i)
- if (json[i] != '\\')
- fputc(json[i], fout);
- else switch(json[++i]) {
- case '\0': goto done;
- case '\\': fputc('\\', fout); break;
- case '\'': fputc('\'', fout); break;
- case '"': fputc('"', fout); break;
- case 'b': fputc('\b', fout); break;
- case 'f': fputc('\f', fout); break;
- case 'n': fputc('\n', fout); break;
- case 'r': fputc('\r', fout); break;
- case 't': fputc('\t', fout); break;
- case 'v': fputc('\v', fout); break;
- default: fputc('\\', fout); --i; break;
+ ~History() { try {
+ for (HIST_ENTRY *history((history_set_pos(0), current_history())); history; history = next_history())
+ for (char *character(history->line); *character; ++character)
+ if (*character == '\n') *character = '\x01';
+
+ if (append_history$ != NULL) {
+ int fd(_syscall(open(histfile_.c_str(), O_CREAT | O_WRONLY, 0600)));
+ _syscall(close(fd));
+ _assert((*append_history$)(histlines_, histfile_.c_str()) == 0);
+ } else {
+ _assert(write_history(histfile_.c_str()) == 0);
+ }
+ } catch (const CYException &error) {
+ CYPool pool;
+ std::cout << error.PoolCString(pool) << std::endl;
+ } }
+
+ void operator +=(std::string command) {
+ if (HIST_ENTRY *entry = history_get(where_history()))
+ if (command == entry->line)
+ return;
+ add_history(command.c_str());
+ ++histlines_;
+ }
+};
+
+template <typename Type_>
+static Type_ *CYmemrchr(Type_ *data, Type_ value, size_t size) {
+ while (size != 0)
+ if (data[--size] == value)
+ return data + size;
+ return NULL;
+}
+
+static void _lblcall(int (*command)(int, int), int count, int key) {
+ int last(_rl_last_c_pos);
+ // rl_rubout crashes in _rl_erase_at_end_of_line if _rl_last_c_pos != 0
+ if (command == &rl_rubout)
+ _rl_last_c_pos = 0;
+ for (int i(0); i != count; ++i)
+ if (command(1, key) != 0)
+ _assert(false);
+ _rl_last_c_pos = last;
+}
+
+static int CYConsoleKeyReturn(int count, int key) {
+ if (rl_point != rl_end) {
+ if (memchr(rl_line_buffer, '\n', rl_end) == NULL) {
+ _lblcall(&rl_newline, count, key);
+ return 0;
+ }
+
+ insert:
+ char *before(CYmemrchr(rl_line_buffer, '\n', rl_point));
+ if (before == NULL)
+ before = rl_line_buffer;
+
+ int space(before + 1 - rl_line_buffer);
+ while (space != rl_point && rl_line_buffer[space] == ' ')
+ ++space;
+
+ int adjust(rl_line_buffer + space - 1 - before);
+ if (space == rl_point && adjust != 0)
+ _lblcall(&rl_rubout, adjust, '\b');
+
+ _lblcall(&rl_insert, count, '\n');
+ if (adjust != 0)
+ _lblcall(&rl_insert, adjust, ' ');
+
+ return 0;
+ }
+
+ bool done(false);
+ if (rl_line_buffer[0] == '?')
+ done = true;
+ else {
+ std::string command(rl_line_buffer, rl_end);
+ command += '\n';
+ std::stringbuf stream(command);
+
+ size_t last(std::string::npos);
+ for (size_t i(0); i != std::string::npos; i = command.find('\n', i + 1))
+ ++last;
+
+ CYPool pool;
+ CYDriver driver(pool, stream);
+ if (driver.Parse() || !driver.errors_.empty())
+ for (CYDriver::Errors::const_iterator error(driver.errors_.begin()); error != driver.errors_.end(); ++error) {
+ if (error->location_.begin.line != last + 1)
+ done = true;
+ break;
+ }
+ else
+ done = true;
+ }
+
+ if (done) {
+ _lblcall(&rl_newline, count, key);
+ return 0;
+ }
+
+ // XXX: this was the most obvious fix, but is seriously dumb
+ goto insert;
+}
+
+static int CYConsoleKeyUp(int count, int key) {
+ for (; count != 0; --count) {
+ char *after(CYmemrchr(rl_line_buffer, '\n', rl_point));
+ if (after == NULL) {
+ if (int value = rl_get_previous_history(1, key))
+ return value;
+ continue;
+ }
+
+ char *before(CYmemrchr(rl_line_buffer, '\n', after - rl_line_buffer));
+ if (before == NULL)
+ before = rl_line_buffer - 1;
+
+ ptrdiff_t offset(rl_line_buffer + rl_point - after);
+ if (offset > after - before)
+ rl_point = after - rl_line_buffer;
+ else
+ rl_point = before + offset - rl_line_buffer;
+ }
+
+ return 0;
+}
+
+static int CYConsoleKeyDown(int count, int key) {
+ for (; count != 0; --count) {
+ char *after(static_cast<char *>(memchr(rl_line_buffer + rl_point, '\n', rl_end - rl_point)));
+ if (after == NULL) {
+ int where(where_history());
+ if (int value = rl_get_next_history(1, key))
+ return value;
+ if (where != where_history()) {
+ char *first(static_cast<char *>(memchr(rl_line_buffer, '\n', rl_end)));
+ if (first != NULL)
+ rl_point = first - 1 - rl_line_buffer;