3
\$\begingroup\$

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;
 ioctl(STDIN_FILENO, TIOCGWINSZ, &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;
 cfmakeraw(&NewProperties);
 tcsetattr(STDIN_FILENO, TCSANOW, &NewProperties);
}
void TerminalReset()
{
 tcsetattr(STDIN_FILENO, TCSANOW, &BackupProperties);
}
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Oct 18, 2011 at 3:03
\$\endgroup\$
2
  • \$\begingroup\$ If you're compiling this with a C++ compiler, don't forget to use extern "C". \$\endgroup\$ Commented Oct 18, 2011 at 3:07
  • \$\begingroup\$ @MartinhoFernandes It's just a plain C file, compiled with gcc. I'll edit that into the question. \$\endgroup\$ Commented Oct 18, 2011 at 3:08

1 Answer 1

3
\$\begingroup\$

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.
answered Oct 18, 2011 at 16:00
\$\endgroup\$
2
  • \$\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\$ Commented Oct 19, 2011 at 19:45
  • \$\begingroup\$ @Maxpm: As long as you're making an informed decision it's fine by me :) \$\endgroup\$ Commented Oct 19, 2011 at 19:55

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.