/* * The contents of this file are subject to the Initial * Developer's Public License Version 1.0 (the "License"); * you may not use this file except in compliance with the * License. You may obtain a copy of the License at * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. * * Software distributed under the License is distributed AS IS, * WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the License for the specific language governing rights * and limitations under the License. * * The Original Code was created by Claudio Valderrama on 5-Oct-2007 * for the Firebird Open Source RDBMS project. * * Copyright (c) 2007 Claudio Valderrama * and all contributors signed below. * * All Rights Reserved. * Contributor(s): ______________________________________. * */ #include "firebird.h" #ifdef DARWIN #if defined(i386) || defined(__x86_64__) #include #else #include #endif #endif #ifdef HAVE_UNISTD_H #include #endif #include "../jrd/common.h" #include "../common/utils_proto.h" #include "InputDevices.h" InputDevices::indev::indev() : indev_fpointer(0), indev_line(0), indev_aux(0), indev_next(0) { indev_fn[0] = 0; } InputDevices::indev::indev(FILE* fp, const char* fn) : indev_fpointer(fp), indev_line(0), indev_aux(0), indev_next(0) { fb_utils::copy_terminate(indev_fn, fn, sizeof(indev_fn)); } // Performs the same task that one of the constructors, but called manually. // File handle and file name are assumed to be valid and the rest of the data // members aren't copied but reset. void InputDevices::indev::init(FILE* fp, const char* fn) { indev_fpointer = fp; indev_line = 0; indev_aux = 0; fb_utils::copy_terminate(indev_fn, fn, sizeof(indev_fn)); indev_next = 0; } // Copies only the file handle and file name from one indev to another. // File handle and file name are assumed to be valid. void InputDevices::indev::init(const indev& src) { indev_fpointer = src.indev_fpointer; indev_line = 0; indev_aux = 0; strcpy(indev_fn, src.indev_fn); indev_next = 0; } //InputDevices::indev::~indev() //{ // Nothing for now. Let the owner or caller close the file pointer if needed. //} // Initializes one indev with another. Useful for method of the owning class // that needs to copy from the input indev to the top of the stack and vice-versa. void InputDevices::indev::copy_from(const indev* src) { fb_assert(src); indev_fpointer = src->indev_fpointer; indev_line = src->indev_line; indev_aux = src->indev_aux; strcpy(indev_fn, src->indev_fn); // indev_next not copied. } // Drop a file associated with an indev. void InputDevices::indev::drop() { fb_assert(indev_fpointer != stdin); fb_assert(indev_fn[0]); // Some name should exist. fclose(indev_fpointer); unlink(indev_fn); } // Save the reading position in the parameter. void InputDevices::indev::getPos(fpos_t* out) const { fb_assert(out); fb_assert(indev_fpointer); fgetpos(indev_fpointer, out); } // Restore a previously stored reading position held in the parameter. void InputDevices::indev::setPos(const fpos_t* in) { fb_assert(in); fb_assert(indev_fpointer); #ifdef SFIO // hack to fix bad sfio header fsetpos(indev_fpointer, const_cast(in)); #else fsetpos(indev_fpointer, in); #endif } // Clear the chain of indev, closing file handles. void InputDevices::clear(FILE* fpointer) { while (m_head) { FILE* const p = m_head->indev_fpointer; if (fpointer && p == fpointer) break; if (p != stdin && p != m_ofp.indev_fpointer) fclose(p); indev* const flist = m_head->indev_next; delete m_head; m_head = flist; --m_count; } if (m_ifp.indev_fpointer && // In case we called clear(NULL) manually before. m_ifp.indev_fpointer != stdin && m_ifp.indev_fpointer != m_ofp.indev_fpointer) { fclose(m_ifp.indev_fpointer); m_ifp.indev_fpointer = 0; } fb_assert(m_count == 0 || fpointer != 0); if (!fpointer) { m_head = 0; m_count = 0; } } // Insert an indev in the chain, always in LIFO way. bool InputDevices::insert(FILE* fp, const char* name) { if (!m_head) { fb_assert(m_count == 0); m_head = new indev(fp, name); } else { fb_assert(m_count > 0); indev* p = m_head; m_head = new indev(fp, name); m_head->indev_next = p; } ++m_count; return true; } // Shortcut for inserting the currently input file in the indev chain. bool InputDevices::insertIfp() { if (insert(0, "")) { m_head->copy_from(&m_ifp); return true; } return false; } // Remove the top (last inserted) indev in the chain. bool InputDevices::remove() { if (m_head) { fb_assert(m_count > 0); indev* p = m_head; m_head = m_head->indev_next; delete p; --m_count; return true; } return false; } // Shortcut for moving the top indev in the chain to the current input file. void InputDevices::removeIntoIfp() { fb_assert(m_head && m_count > 0); m_ifp.copy_from(m_head); // When we come back from inout(), we continue inside the get_statement loop. // If we are inside do_isql() due to Ctrl-C, it doesn't cause any harm. m_ifp.indev_line = m_ifp.indev_aux; remove(); } // Shortcut for testing whether current input and output handles are the same. // This may happen if we are reading from the command history file that's filled // automatically with every interactive SQL command (isql commands aren't logged). bool InputDevices::sameInputAndOutput() const { fb_assert(m_ifp.indev_fpointer); fb_assert(m_ofp.indev_fpointer); return m_ifp.indev_fpointer == m_ofp.indev_fpointer; } // Save SQL command (not isql's own commands) to a history file only if we // are in interactive mode. void InputDevices::saveCommand(const char* statement, const char* term) { if (m_ifp.indev_fpointer == stdin) { FILE* f = m_ofp.indev_fpointer; fb_assert(f); fputs(statement, f); fputs(term, f); // Add newline to make the file more readable. fputc('\n', f); } } // Are we reading from stdin now or from a file? bool InputDevices::readingStdin() const { fb_assert(m_ifp.indev_fpointer); return m_ifp.indev_fpointer == stdin; } // Go to end of file if we are reading from a file (not stdin). void InputDevices::gotoEof() { fb_assert(m_ifp.indev_fpointer); if (m_ifp.indev_fpointer != stdin) fseek(m_ifp.indev_fpointer, 0, SEEK_END); }