/*
 *
 *
 *    termios.h
 *
 *    C++ header file for class 'termios.'
 *
 *    =========================================================================
 *
 *    Copyright (C) 2001-2003 by Matt Roberts, KK5JY.
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation; either
 *    version 2.1 of the License, or (at your option) any later version.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *    =========================================================================
 *
 *
 */


#ifndef __TERMIOS_H
#define __TERMIOS_H

#include <termios.h>
#include <unistd.h>
#include <iosfwd>

	namespace my {

		/*
		 *
		 *
		 *    class my::termios
		 *
		 *
		 */

		class termios {
			private:
				::termios t_ios;

			private: /* used to manipulate 't_ios' */
				void __c_lflag_option_mask_bit  (int val, bool state) { state ? t_ios.c_lflag |= val : t_ios.c_lflag &= ~val; };
				void __c_lflag_option_mask_word (int val, int state)  { t_ios.c_lflag &= ~val; t_ios.c_lflag |= state;        };
				bool __c_lflag_option_get_bit (int val)               { return (t_ios.c_lflag & val) ? true : false;          };
				int  __c_lflag_option_get_word (int val)              { return (t_ios.c_lflag & val);                         };

				void __c_cflag_option_mask_bit  (int val, bool state) { state ? t_ios.c_cflag |= val : t_ios.c_cflag &= ~val; };
				void __c_cflag_option_mask_word (int val, int state)  { t_ios.c_cflag &= ~val; t_ios.c_cflag |= state;        };
				bool __c_cflag_option_get_bit (int val)               { return (t_ios.c_cflag & val) ? true : false;          };
				int  __c_cflag_option_get_word (int val)              { return (t_ios.c_cflag & val);                         };

				void __c_iflag_option_mask_bit  (int val, bool state) { state ? t_ios.c_iflag |= val : t_ios.c_iflag &= ~val; };
				void __c_iflag_option_mask_word (int val, int state)  { t_ios.c_iflag &= ~val; t_ios.c_iflag |= state;        };
				bool __c_iflag_option_get_bit (int val)               { return (t_ios.c_iflag & val) ? true : false;          };
				int  __c_iflag_option_get_word (int val)              { return (t_ios.c_iflag & val);                         };

				void __c_oflag_option_mask_bit  (int val, bool state) { state ? t_ios.c_oflag |= val : t_ios.c_oflag &= ~val; };
				void __c_oflag_option_mask_word (int val, int state)  { t_ios.c_oflag &= ~val; t_ios.c_oflag |= state;        };
				bool __c_oflag_option_get_bit (int val)               { return (t_ios.c_oflag & val) ? true : false;          };
				int  __c_oflag_option_get_word (int val)              { return (t_ios.c_oflag & val);                         };

			protected:
				// The 'optionInputxxxx functions set 'c_iflag' parameters:
				void optionInputIgnoreBreak      (bool arg) { __c_iflag_option_mask_bit  (IGNBRK,  arg); };
				void optionInputAllowBreakSignal (bool arg) { __c_iflag_option_mask_bit  (BRKINT,  arg); };
				void optionInputIgnoreParity     (bool arg) { __c_iflag_option_mask_bit  (IGNPAR,  arg); };
				void optionInputMarkParityErrors (bool arg) { __c_iflag_option_mask_bit  (PARMRK,  arg); };
				void optionInputParityCheck      (bool arg) { __c_iflag_option_mask_bit  (INPCK,   arg); };
				void optionInputStripBitEight    (bool arg) { __c_iflag_option_mask_bit  (ISTRIP,  arg); };
				void optionInputNLtoCR           (bool arg) { __c_iflag_option_mask_bit  (INLCR,   arg); };
				void optionInputIgnoreCR         (bool arg) { __c_iflag_option_mask_bit  (IGNCR,   arg); };
				void optionInputCRtoNL           (bool arg) { __c_iflag_option_mask_bit  (ICRNL,   arg); };
				void optionInputToLower          (bool arg) { __c_iflag_option_mask_bit  (IUCLC,   arg); };
				void optionInputXFlow            (bool arg) { __c_iflag_option_mask_bit  (IXOFF,   arg); };
				void optionInputAnyXFlowRestart  (bool arg) { __c_iflag_option_mask_bit  (IXANY,   arg); };
				void optionInputOutputXFlow      (bool arg) { __c_iflag_option_mask_bit  (IXON,    arg); };
				void optionInputRingOnFullQueue  (bool arg) { __c_iflag_option_mask_bit  (IMAXBEL, arg); };

				bool optionInputIgnoreBreak      (void) { return __c_iflag_option_get_bit (IGNBRK);  };
				bool optionInputAllowBreakSignal (void) { return __c_iflag_option_get_bit (BRKINT);  };
				bool optionInputIgnoreParity     (void) { return __c_iflag_option_get_bit (IGNPAR);  };
				bool optionInputMarkParityErrors (void) { return __c_iflag_option_get_bit (PARMRK);  };
				bool optionInputParityCheck      (void) { return __c_iflag_option_get_bit (INPCK);   };
				bool optionInputStripBitEight    (void) { return __c_iflag_option_get_bit (ISTRIP);  };
				bool optionInputNLtoCR           (void) { return __c_iflag_option_get_bit (INLCR);   };
				bool optionInputIgnoreCR         (void) { return __c_iflag_option_get_bit (IGNCR);   };
				bool optionInputCRtoNL           (void) { return __c_iflag_option_get_bit (ICRNL);   };
				bool optionInputToLower          (void) { return __c_iflag_option_get_bit (IUCLC);   };
				bool optionInputXFlow            (void) { return __c_iflag_option_get_bit (IXOFF);   };
				bool optionInputAnyXFlowRestart  (void) { return __c_iflag_option_get_bit (IXANY);   };
				bool optionInputOutputXFlow      (void) { return __c_iflag_option_get_bit (IXON);    };
				bool optionInputRingOnFullQueue  (void) { return __c_iflag_option_get_bit (IMAXBEL); };

				// The 'optionOutputxxx' functions set 'c_oflag' flag constants.
				void optionOutputProcessing (bool arg) { __c_oflag_option_mask_bit (OPOST, arg);   };
				void optionOutputToUpper (bool arg)    { __c_oflag_option_mask_bit (OLCUC, arg);   };
				void optionOutputNLtoCRNL (bool arg)   { __c_oflag_option_mask_bit (ONLCR, arg);   };
				void optionOutputCRtoNL (bool arg)     { __c_oflag_option_mask_bit (OCRNL, arg);   };
				void optionOutputNoCRatLeft (bool arg) { __c_oflag_option_mask_bit (ONOCR, arg);   };
				void optionOutputNoCR (bool arg)       { __c_oflag_option_mask_bit (ONLRET, arg);  };
				void optionOutputFill (bool arg)       { __c_oflag_option_mask_bit (OFILL, arg);   };
				void optionOutputFillChar (bool arg)   { __c_oflag_option_mask_bit (OFDEL, arg);   };
				void optionOutputNLDelay (int arg)     { __c_oflag_option_mask_word (NLDLY, arg);  };
				void optionOutputCRDelay (int arg)     { __c_oflag_option_mask_word (CRDLY, arg);  };
				void optionOutputTabDelay (int arg)    { __c_oflag_option_mask_word (TABDLY, arg); };
				void optionOutputBSDelay (int arg)     { __c_oflag_option_mask_word (BSDLY, arg);  };
				void optionOutputVTDelay (int arg)     { __c_oflag_option_mask_word (VTDLY, arg);  };
				void optionOutputFFDelay (int arg)     { __c_oflag_option_mask_word (FFDLY, arg);  };

				bool optionOutputProcessing (void) { return __c_oflag_option_get_bit (OPOST);   };
				bool optionOutputToUpper (void)    { return __c_oflag_option_get_bit (OLCUC);   };
				bool optionOutputNLtoCRNL (void)   { return __c_oflag_option_get_bit (ONLCR);   };
				bool optionOutputCRtoNL (void)     { return __c_oflag_option_get_bit (OCRNL);   };
				bool optionOutputNoCRatLeft (void) { return __c_oflag_option_get_bit (ONOCR);   };
				bool optionOutputNoCR (void)       { return __c_oflag_option_get_bit (ONLRET);  };
				bool optionOutputFill (void)       { return __c_oflag_option_get_bit (OFILL);   };
				bool optionOutputFillChar (void)   { return __c_oflag_option_get_bit (OFDEL);   };
				int optionOutputNLDelay (void)     { return __c_oflag_option_get_word (NLDLY);  };
				int optionOutputCRDelay (void)     { return __c_oflag_option_get_word (CRDLY);  };
				int optionOutputTabDelay (void)    { return __c_oflag_option_get_word (TABDLY); };
				int optionOutputBSDelay (void)     { return __c_oflag_option_get_word (BSDLY);  };
				int optionOutputVTDelay (void)     { return __c_oflag_option_get_word (VTDLY);  };
				int optionOutputFFDelay (void)     { return __c_oflag_option_get_word (FFDLY);  };

				// The 'optionCommxxx' functions set 'c_cflag' flag constants, and set speed.
				void optionCommSpeed          (int arg);
				void optionCommCharSize       (int arg);
				void optionCommStopBits       (int arg);
				void optionCommReceiver       (bool arg) { __c_cflag_option_mask_bit (CREAD, arg);   };
				void optionCommParity         (bool arg) { __c_cflag_option_mask_bit (PARENB, arg);  };
				void optionCommOddParity      (bool arg) { __c_cflag_option_mask_bit (PARODD, arg);  };
				void optionCommHardHangup     (bool arg) { __c_cflag_option_mask_bit (HUPCL, arg);   };
				void optionCommIgnoreModemCtl (bool arg) { __c_cflag_option_mask_bit (CLOCAL, arg);  };
				void optionCommHardFlowCtl    (bool arg) { __c_cflag_option_mask_bit (CRTSCTS, arg); };

				int  optionCommSpeed          (void);
				int  optionCommCharSize       (void);
				int  optionCommStopBits       (void);
				bool optionCommReceiver       (void) { return __c_cflag_option_get_bit (CREAD);   };
				bool optionCommParity         (void) { return __c_cflag_option_get_bit (PARENB);  };
				bool optionCommOddParity      (void) { return __c_cflag_option_get_bit (PARODD);  };
				bool optionCommHardHangup     (void) { return __c_cflag_option_get_bit (HUPCL);   };
				bool optionCommIgnoreModemCtl (void) { return __c_cflag_option_get_bit (CLOCAL);  };
				bool optionCommHardFlowCtl    (void) { return __c_cflag_option_get_bit (CRTSCTS); };

				// The 'optionLocalxxxx' functions set local terminal display and signal options.
				void optionLocalGenerateSignals   (bool arg) { __c_lflag_option_mask_bit (ISIG, arg);    };
				void optionLocalCanonicalMode     (bool arg) { __c_lflag_option_mask_bit (ICANON, arg);  };
				void optionLocalUppercase         (bool arg) { __c_lflag_option_mask_bit (XCASE, arg);   };
				void optionLocalEcho              (bool arg) { __c_lflag_option_mask_bit (ECHO, arg);    };
				void optionLocalErase             (bool arg) { __c_lflag_option_mask_bit (ECHOE, arg);   };
				void optionLocalKill              (bool arg) { __c_lflag_option_mask_bit (ECHOK, arg);   };
				void optionLocalEchoNewline       (bool arg) { __c_lflag_option_mask_bit (ECHONL, arg);  };
				void optionLocalXformCtl          (bool arg) { __c_lflag_option_mask_bit (ECHOCTL, arg); };
				void optionLocalPrintErase        (bool arg) { __c_lflag_option_mask_bit (ECHOPRT, arg); };
				void optionLocalPrintKill         (bool arg) { __c_lflag_option_mask_bit (ECHOKE, arg);  };
				void optionLocalEnableFlushing    (bool arg) { __c_lflag_option_mask_bit (FLUSHO, arg);  };
				void optionLocalDisableFlushing   (bool arg) { __c_lflag_option_mask_bit (NOFLSH, arg);  };
				void optionLocalSignalOnWrite     (bool arg) { __c_lflag_option_mask_bit (TOSTOP, arg);  };
				void optionLocalEchoPending       (bool arg) { __c_lflag_option_mask_bit (PENDIN, arg);  };
				void optionLocalExtendedInputProc (bool arg) { __c_lflag_option_mask_bit (IEXTEN, arg);  };

				bool optionLocalGenerateSignals   (void) { return __c_lflag_option_get_word (ISIG);    };
				bool optionLocalCanonicalMode     (void) { return __c_lflag_option_get_word (ICANON);  };
				bool optionLocalUppercase         (void) { return __c_lflag_option_get_word (XCASE);   };
				bool optionLocalEcho              (void) { return __c_lflag_option_get_word (ECHO);    };
				bool optionLocalErase             (void) { return __c_lflag_option_get_word (ECHOE);   };
				bool optionLocalKill              (void) { return __c_lflag_option_get_word (ECHOK);   };
				bool optionLocalEchoNewline       (void) { return __c_lflag_option_get_word (ECHONL);  };
				bool optionLocalXformCtl          (void) { return __c_lflag_option_get_word (ECHOCTL); };
				bool optionLocalPrintErase        (void) { return __c_lflag_option_get_word (ECHOPRT); };
				bool optionLocalPrintKill         (void) { return __c_lflag_option_get_word (ECHOKE);  };
				bool optionLocalEnableFlushing    (void) { return __c_lflag_option_get_word (FLUSHO);  };
				bool optionLocalDisableFlushing   (void) { return __c_lflag_option_get_word (NOFLSH);  };
				bool optionLocalSignalOnWrite     (void) { return __c_lflag_option_get_word (TOSTOP);  };
				bool optionLocalEchoPending       (void) { return __c_lflag_option_get_word (PENDIN);  };
				bool optionLocalExtendedInputProc (void) { return __c_lflag_option_get_word (IEXTEN);  };

			protected: /* override init() to change default behaviour */
				virtual void init (void);

			public:
				#ifdef LINUX
				void makeRaw  (void) { return ::cfmakeraw (&t_ios); };
				#endif /* LINUX */

				void clearInputFlags  (void) { t_ios.c_iflag = 0; };
				void clearOutputFlags (void) { t_ios.c_oflag = 0; };
				void clearLocalFlags  (void) { t_ios.c_lflag = 0; };
				void clearCommFlags   (void) { t_ios.c_cflag = 0; };

				void setInterbyteTimeout(int i) { t_ios.c_cc[VTIME] = i; };
				void setMinimumByteCount(int i) { t_ios.c_cc[VMIN]  = i;  };

				const my::termios & copy_to (::termios &t) const;

			public:
				termios (void) { init(); };
				termios (const my::termios &t) { t.copy_to(t_ios); };
				termios (const ::termios &t) { t_ios = t; };

				virtual ~termios (void) { /* noop */ };

				friend std::ostream &operator << (std::ostream &stream, my::termios &obj);

		};

	}

#endif /* __TERMIOS_H */
