2008-01-16 08:23:29 +01:00
|
|
|
/*
|
|
|
|
* 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"
|
2008-10-22 15:15:00 +02:00
|
|
|
#ifdef DARWIN
|
|
|
|
#if defined(i386) || defined(__x86_64__)
|
|
|
|
#include <architecture/i386/io.h>
|
|
|
|
#else
|
2008-01-16 08:23:29 +01:00
|
|
|
#include <io.h>
|
2008-10-22 15:15:00 +02:00
|
|
|
#endif
|
|
|
|
#endif
|
2008-01-16 08:23:29 +01:00
|
|
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#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);
|
2008-12-30 18:58:30 +01:00
|
|
|
#ifdef SFIO
|
|
|
|
// hack to fix bad sfio header
|
|
|
|
fsetpos(indev_fpointer, const_cast<fpos_t*>(in));
|
|
|
|
#else
|
2008-01-16 08:23:29 +01:00
|
|
|
fsetpos(indev_fpointer, in);
|
2008-12-30 18:58:30 +01:00
|
|
|
#endif
|
2008-01-16 08:23:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|