| Server IP : 217.160.0.135 / Your IP : 216.73.217.25 Web Server : Apache System : Linux www 6.18.52-i1-ampere #1203 SMP Mon Sep 14 18:29:59 CEST 2026 aarch64 User : sws1074145052 ( 1074145052) PHP Version : 8.3.32 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /lib/python3/dist-packages/pythran/pythonic/types/ |
Upload File : |
#ifndef PYTHONIC_TYPES_FILE_HPP
#define PYTHONIC_TYPES_FILE_HPP
#include "pythonic/include/types/file.hpp"
#include "pythonic/types/assignable.hpp"
#include "pythonic/utils/shared_ref.hpp"
#include "pythonic/types/str.hpp"
#include "pythonic/types/list.hpp"
#include "pythonic/types/NoneType.hpp"
#include "pythonic/types/attr.hpp"
#include "pythonic/builtins/IOError.hpp"
#include "pythonic/builtins/ValueError.hpp"
#include "pythonic/builtins/RuntimeError.hpp"
#include "pythonic/builtins/StopIteration.hpp"
#include <fstream>
#include <iterator>
#include <cstring>
#include <string>
#include <cstdio>
#include <memory>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
PYTHONIC_NS_BEGIN
namespace types
{
/// _file implementation
_file::_file() : f(nullptr)
{
}
// TODO : no check on file existance?
_file::_file(types::str const &filename, types::str const &strmode)
: f(fopen(filename.c_str(), strmode.c_str()))
{
}
FILE *_file::operator*() const
{
return f;
}
_file::~_file()
{
if (f)
fclose(f);
}
/// file implementation
// Constructors
file::file() : file_iterator(), data(utils::no_memory())
{
}
file::file(types::str const &filename, types::str const &strmode)
: file_iterator(), data(utils::no_memory()), mode(strmode),
name(filename), newlines('\n')
{
open(filename, strmode);
if (mode.find_first_of("r+") != -1)
*(file_iterator *)this = file_iterator(*this);
}
// Iterators
file::iterator file::begin()
{
return *this;
}
file::iterator file::end()
{
return {};
}
// Modifiers
void file::open(types::str const &filename, types::str const &strmode)
{
const char *smode = strmode.c_str();
// Python enforces that the mode, after stripping 'U', begins with 'r',
// 'w' || 'a'.
if (*smode == 'U') {
++smode;
} // Not implemented yet
data = utils::shared_ref<container_type>(filename, smode);
if (!**data)
throw types::IOError("Couldn't open file " + filename);
is_open = true;
}
void file::close()
{
fclose(**data);
data->f = nullptr;
is_open = false;
}
bool file::closed() const
{
return !is_open;
}
types::str const &file::getmode() const
{
return mode;
}
types::str const &file::getname() const
{
return name;
}
types::str const &file::getnewlines() const
{
// Python seems to always return none... Doing the same here
return newlines;
}
bool file::eof()
{
return ::feof(**data);
}
void file::flush()
{
if (!is_open)
throw ValueError("I/O operation on closed file");
fflush(**data);
}
long file::fileno() const
{
if (!is_open)
throw ValueError("I/O operation on closed file");
return ::fileno(**data);
}
bool file::isatty() const
{
if (!is_open)
throw ValueError("I/O operation on closed file");
return ::isatty(this->fileno());
}
types::str file::read(long size)
{
if (!is_open)
throw ValueError("I/O operation on closed file");
if (mode.find_first_of("r+") == -1)
throw IOError("File not open for reading");
if (size == 0 || (feof(**data) && mode.find_first_of("ra") == -1))
return types::str();
long curr_pos = tell();
seek(0, SEEK_END);
size = size < 0 ? tell() - curr_pos : size;
seek(curr_pos);
std::unique_ptr<char[]> content{new char[size + 1]};
// This part needs a new implementation of types::str(char*) to avoid
// unnecessary copy.
types::str res(content.get(),
fread(content.get(), sizeof(char), size, **data));
return res;
}
types::str file::readline(long size)
{
if (!is_open)
throw ValueError("I/O operation on closed file");
if (mode.find_first_of("r+") == -1)
throw IOError("File not open for reading");
constexpr static long BUFFER_SIZE = 1024;
types::str res;
char read_str[BUFFER_SIZE];
for (long i = 0; i < size; i += BUFFER_SIZE) {
// +1 because we read the last chunk so we don't want to count \0
if (fgets(read_str, std::min(BUFFER_SIZE - 1, size - i) + 1, **data))
res += read_str;
if (feof(**data) || res[res.size() - 1] == "\n")
break;
}
return res;
}
types::list<types::str> file::readlines(long sizehint)
{
// Official python doc specifies that sizehint is used as a max of chars
// But it has not been implemented in the standard python interpreter...
types::str str;
types::list<types::str> lst(0);
while ((str = readline()))
lst.push_back(str);
return lst;
}
void file::seek(long offset, long whence)
{
if (!is_open)
throw ValueError("I/O operation on closed file");
if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END)
throw IOError("file.seek() : Invalid argument.");
fseek(**data, offset, whence);
}
long file::tell() const
{
if (!is_open)
throw ValueError("I/O operation on closed file");
return ftell(**data);
}
void file::truncate(long size)
{
if (!is_open)
throw ValueError("I/O operation on closed file");
if (mode.find_first_of("wa+") == -1)
throw IOError("file.write() : File not open for writing.");
if (size < 0)
size = this->tell();
#ifdef _WIN32
long error = _chsize_s(fileno(), size);
#else
long error = ftruncate(fileno(), size);
#endif
if (error == -1)
throw RuntimeError(strerror(errno));
}
long file::write(types::str const &str)
{
if (!is_open)
throw ValueError("I/O operation on closed file");
if (mode.find_first_of("wa+") == -1)
throw IOError("file.write() : File not open for writing.");
return fwrite(str.c_str(), sizeof(char), str.size(), **data);
}
template <class T>
void file::writelines(T const &seq)
{
auto end = seq.end();
for (auto it = seq.begin(); it != end; ++it)
write(*it);
}
/// file_iterator implementation
// TODO : What if the file disappears before the end?
// Like in :
// for line in open("myfile"):
// print line
file_iterator::file_iterator(file &ref)
: f(&ref), set(false), curr(), position(ref.tell())
{
}
file_iterator::file_iterator()
: f(nullptr), set(false), curr(),
position(std::numeric_limits<long>::max()){};
bool file_iterator::operator==(file_iterator const &f2) const
{
return position == f2.position;
}
bool file_iterator::operator!=(file_iterator const &f2) const
{
return position != f2.position;
}
bool file_iterator::operator<(file_iterator const &f2) const
{
// Not really elegant...
// Equivalent to 'return *this != f2;'
return position < f2.position;
}
file_iterator &file_iterator::operator++()
{
if (f->eof())
return *this;
operator*();
set = false;
operator*();
position = f->eof() ? std::numeric_limits<long>::max() : f->tell();
return *this;
}
types::str file_iterator::operator*() const
{
if (!set) {
curr = f->readline();
set = true;
}
return curr.chars(); // to make a copy
}
}
PYTHONIC_NS_END
/* pythran attribute system { */
PYTHONIC_NS_BEGIN
namespace builtins
{
bool getattr(types::attr::CLOSED, types::file const &f)
{
return f.closed();
}
types::str const &getattr(types::attr::MODE, types::file const &f)
{
return f.getmode();
}
types::str const &getattr(types::attr::NAME, types::file const &f)
{
return f.getname();
}
// Python seems to always return none... Doing the same.
types::none_type getattr(types::attr::NEWLINES, types::file const &f)
{
return builtins::None;
}
}
PYTHONIC_NS_END
/* } */
#endif