// license:BSD-3-Clause // copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb //============================================================ // // sdlsocket.c - SDL socket (inet) access functions // // SDLMAME by Olivier Galibert and R. Belmont // //============================================================ #include "posixfile.h" #include #include #include #include #include #include #include #include #include #include #include namespace { char const *const posixfile_socket_identifier = "socket."; class posix_osd_socket : public osd_file { public: posix_osd_socket(posix_osd_socket const &) = delete; posix_osd_socket(posix_osd_socket &&) = delete; posix_osd_socket& operator=(posix_osd_socket const &) = delete; posix_osd_socket& operator=(posix_osd_socket &&) = delete; posix_osd_socket(int sock, bool listening) : m_sock(sock) , m_listening(listening) { assert(m_sock >= 0); } virtual ~posix_osd_socket() { ::close(m_sock); } virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override { #if defined(EMSCRIPTEN) m_listening = false; return error::FAILURE; // TODO: work out what it dislikes about emscripten #else fd_set readfds; FD_ZERO(&readfds); FD_SET(m_sock, &readfds); struct timeval timeout; timeout.tv_sec = timeout.tv_usec = 0; if (select(m_sock + 1, &readfds, nullptr, nullptr, &timeout) < 0) { char line[80]; std::sprintf(line, "%s : %s : %d ", __func__, __FILE__, __LINE__); std::perror(line); return errno_to_file_error(errno); } else if (FD_ISSET(m_sock, &readfds)) { if (!m_listening) { // connected socket ssize_t const result = ::read(m_sock, buffer, count); if (result < 0) { return errno_to_file_error(errno); } else { actual = std::uint32_t(size_t(result)); return error::NONE; } } else { // listening socket int const accepted = ::accept(m_sock, nullptr, nullptr); if (accepted < 0) { return errno_to_file_error(errno); } else { ::close(m_sock); m_sock = accepted; m_listening = false; actual = 0; return error::NONE; } } } else { return error::FAILURE; } #endif } virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override { ssize_t const result = ::write(m_sock, buffer, count); if (result < 0) return errno_to_file_error(errno); actual = std::uint32_t(size_t(result)); return error::NONE; } virtual error truncate(std::uint64_t offset) override { // doesn't make sense on socket return error::INVALID_ACCESS; } virtual error flush() override { // there's no simple way to flush buffers on a socket anyway return error::NONE; } private: int m_sock; bool m_listening; }; } // anonymous namespace /* Checks whether the path is a socket specification. A valid socket specification has the format "socket." host ":" port. Host may be simple or fully qualified. Port must be between 1 and 65535. */ bool posix_check_socket_path(std::string const &path) { if (strncmp(path.c_str(), posixfile_socket_identifier, strlen(posixfile_socket_identifier)) == 0 && strchr(path.c_str(), ':') != nullptr) return true; return false; } osd_file::error posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) { char hostname[256]; int port; std::sscanf(&path[strlen(posixfile_socket_identifier)], "%255[^:]:%d", hostname, &port); struct hostent const *const localhost = ::gethostbyname(hostname); if (!localhost) return osd_file::error::NOT_FOUND; struct sockaddr_in sai; memset(&sai, 0, sizeof(sai)); sai.sin_family = AF_INET; sai.sin_port = htons(port); sai.sin_addr = *reinterpret_cast(localhost->h_addr); int const sock = ::socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) return errno_to_file_error(errno); int const flag = 1; if (::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&flag), sizeof(flag)) < 0) { int const err = errno; ::close(sock); return errno_to_file_error(err); } // listening socket support if (openflags & OPEN_FLAG_CREATE) { //printf("Listening for client at '%s' on port '%d'\n", hostname, port); // bind socket... if (::bind(sock, reinterpret_cast(&sai), sizeof(struct sockaddr)) < 0) { int const err = errno; ::close(sock); return errno_to_file_error(err); } // start to listen... if (::listen(sock, 1) < 0) { int const err = errno; ::close(sock); return errno_to_file_error(err); } // mark socket as "listening" try { file = std::make_unique(sock, true); filesize = 0; return osd_file::error::NONE; } catch (...) { ::close(sock); return osd_file::error::OUT_OF_MEMORY; } } else { //printf("Connecting to server '%s' on port '%d'\n", hostname, port); if (::connect(sock, reinterpret_cast(&sai), sizeof(struct sockaddr)) < 0) { ::close(sock); return osd_file::error::ACCESS_DENIED; // have to return this value or bitb won't try to bind on connect failure } try { file = std::make_unique(sock, false); filesize = 0; return osd_file::error::NONE; } catch (...) { ::close(sock); return osd_file::error::OUT_OF_MEMORY; } } } 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
"""Updates the license text in source file.
"""
from __future__ import print_function

# An existing license is found if the file starts with the string below,
# and ends with the first blank line.
LICENSE_BEGIN = "// Copyright "

BRIEF_LICENSE = LICENSE_BEGIN + """2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE

""".replace('\r\n','\n')

def update_license(path, dry_run, show_diff):
    """Update the license statement in the specified file.
    Parameters:
      path: path of the C++ source file to update.
      dry_run: if True, just print the path of the file that would be updated,
               but don't change it.
      show_diff: if True, print the path of the file that would be modified,
                 as well as the change made to the file. 
    """
    with open(path, 'rt') as fin:
        original_text = fin.read().replace('\r\n','\n')
        newline = fin.newlines and fin.newlines[0] or '\n'
    if not original_text.startswith(LICENSE_BEGIN):
        # No existing license found => prepend it
        new_text = BRIEF_LICENSE + original_text
    else:
        license_end_index = original_text.index('\n\n') # search first blank line
        new_text = BRIEF_LICENSE + original_text[license_end_index+2:]
    if original_text != new_text:
        if not dry_run:
            with open(path, 'wb') as fout:
                fout.write(new_text.replace('\n', newline))
        print('Updated', path)
        if show_diff:
            import difflib
            print('\n'.join(difflib.unified_diff(original_text.split('\n'),
                                                   new_text.split('\n'))))
        return True
    return False

def update_license_in_source_directories(source_dirs, dry_run, show_diff):
    """Updates license text in C++ source files found in directory source_dirs.
    Parameters:
      source_dirs: list of directory to scan for C++ sources. Directories are
                   scanned recursively.
      dry_run: if True, just print the path of the file that would be updated,
               but don't change it.
      show_diff: if True, print the path of the file that would be modified,
                 as well as the change made to the file. 
    """
    from devtools import antglob
    prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist'
    for source_dir in source_dirs:
        cpp_sources = antglob.glob(source_dir,
            includes = '''**/*.h **/*.cpp **/*.inl''',
            prune_dirs = prune_dirs)
        for source in cpp_sources:
            update_license(source, dry_run, show_diff)

def main():
    usage = """%prog DIR [DIR2...]
Updates license text in sources of the project in source files found
in the directory specified on the command-line.

Example of call:
python devtools\licenseupdater.py include src -n --diff
=> Show change that would be made to the sources.

python devtools\licenseupdater.py include src
=> Update license statement on all sources in directories include/ and src/.
"""
    from optparse import OptionParser
    parser = OptionParser(usage=usage)
    parser.allow_interspersed_args = False
    parser.add_option('-n', '--dry-run', dest="dry_run", action='store_true', default=False,
        help="""Only show what files are updated, do not update the files""")
    parser.add_option('--diff', dest="show_diff", action='store_true', default=False,
        help="""On update, show change made to the file.""")
    parser.enable_interspersed_args()
    options, args = parser.parse_args()
    update_license_in_source_directories(args, options.dry_run, options.show_diff)
    print('Done')

if __name__ == '__main__':
    import sys
    import os.path
    sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    main()