I've prepared a small C interface so the rest of my program can access relevant system functions. I am not a C programmer, though - just C++ and D, mainly. I want to make sure that everything here is "C-ish" before committing the rest of my code to this interface.

This is just a plain old C file, compiled with a C compiler (as opposed to C++).

     * This file provides functions to interface with
     * low-level terminal properties such as size and
     * input modes.  Functions meant to be accessible
     * to external "user" code begin with "Terminal."

#include <sys/ioctl.h> // For interfacing with the terminal device.
#include <termios.h> // Ditto.
#include <unistd.h> // For the STDIN_FILENO file descriptor macro.

// This is just used internally, and should not be called directly from D code.
struct winsize Size()
    struct winsize Size;
    return Size;

unsigned short int TerminalColumnCount()
    return Size().ws_col;

unsigned short int TerminalRowCount()
    return Size().ws_row;

// Used to reset the terminal properties to their original state.
// Again, this is only for internal use.
struct termios BackupProperties;

// Removes terminal input buffering so programs can see typed characters before Enter is pressed.
void TerminalMakeRaw() // I wish I could come up with a better name for this.  
    tcgetattr(STDIN_FILENO, &BackupProperties);
    struct termios NewProperties;
    tcsetattr(STDIN_FILENO, TCSANOW, &NewProperties);

void TerminalReset()
    tcsetattr(STDIN_FILENO, TCSANOW, &BackupProperties);
  • \$\begingroup\$ If you're compiling this with a C++ compiler, don't forget to use extern "C". \$\endgroup\$ – R. Martinho Fernandes Oct 18 '11 at 3:07
  • \$\begingroup\$ @MartinhoFernandes It's just a plain C file, compiled with gcc. I'll edit that into the question. \$\endgroup\$ – Maxpm Oct 18 '11 at 3:08

A few quick comments:

  • You should declare all internal functions and variables static to avoid polluting the global namespace. (You'd do this in a C++ program as well, but would probably use an unnamed namespace. I'm not sure what the D equivalent is).
  • Since you have state (implicitly and explicitly via BackupProperties) I'd recommend using an object oriented approach exposing an opaque pointer to maintain it, even if there is only one Terminal instance it's (IMO) a better approach. Otherwise you should at least ensure that TerminalMakeRaw isn't called twice without corresponding calls to TerminalReset.
  • You should also consider that at some point you'll probably want to have callbacks of some sort to notify the users of your library when/if the window size changes and so on.
| improve this answer | |
  • \$\begingroup\$ Pertaining to your second suggestion, I ended up going with a global state solution. I'm aware that it's often considered bad practice, but in this case I think it makes sense and I'm not going to overcomplicate things just on principle. \$\endgroup\$ – Maxpm Oct 19 '11 at 19:45
  • \$\begingroup\$ @Maxpm: As long as you're making an informed decision it's fine by me :) \$\endgroup\$ – user786653 Oct 19 '11 at 19:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.