ClassesInC : sample C code showing a simple OO Class implementation

Download classesinc.zip

Synopsis:

classesinc.c
classdefs.h
socket.h
socket.c


classesinc.c

Synopsis
//WARNING! NO UNITTESTS
#include <stdio.h>
#include <string.h>
#include "socket.h"

//main line for "classes in C" example
//c++ equivalents are show with a c++: comment
int main()
  {
  char buf[1024];

  //c++: socket* s = new socket("127.0.0.1", 80);
  INSTP s = new_socket("127.0.0.1", 80);
  
  //c++: s->connect();
  connect_socket(s);
  
  sprintf(buf, "GET /cgi-bin/test.cgi HTTP/1.0\r\n\n\n");
  //c++: s->send(buf, strlen(buf));
  send_socket(s, buf, (int) strlen(buf));
  
  for(;;)
    {
    //c++: avail = s->avail();
    unsigned long avail = avail_socket(s);
    if (avail == 0)
      break;

    memset(buf, 0, sizeof(buf));
    //c++: s->recv(buf, sizeof(buf));
    recv_socket(s, buf, sizeof(buf));
    }

  //c++: delete s;
  dtor_socket(s);
  
  return 0;
  }

classdefs.h

Synopsis
#ifndef classdefs_h
#define classdefs_h

//A generic pointer to an instance of a class.
typedef void* INSTP;

//The "hidden" this pointer
#define THISP INSTP thisparm

//all public methods have the class tacked on the end
//i.e. "name mangling"
#define PUBLIC(c, m) m##_##c

//private methods are just static functions
#define PRIVATE(c, m) static m
#endif

socket.h

Synopsis
#ifndef socket_h
#define socket_h

//if socket used other classes,
//they'd be #included here and a #undef CLASS 
//would need to be added just before the #define CLASS

//define some helper macros
#include "classdefs.h"

INSTP PUBLIC(socket, new)    ( char* ipaddr, int port);
void  PUBLIC(socket, dtor)   (THISP);

void PUBLIC(socket, connect) (THISP);
void PUBLIC(socket, send)    (THISP, char* buf, int len);
void PUBLIC(socket, recv)    (THISP, char* buf, int maxlen);
unsigned long PUBLIC(socket, avail) (THISP);
#endif

socket.c

Synopsis
#include <stdio.h>
#include <winsock2.h>
#include "socket.h"
#define SET_THIS()  socket_class* this = (socket_class*) thisparm
#define NEW_THIS() malloc(sizeof(socket_class));

//bool for emulating cpp
typedef enum {false, true} bool;

//define the object instance
typedef struct socket_classt
  {
  SOCKET s;
  bool isOpen;
  SOCKADDR_IN addr;
  u_short port;
  } socket_class;

//private prototypes
void PRIVATE(socket, startup) (THISP);
void PRIVATE(socket, cleanup) (THISP);
void PRIVATE(socket, close)   (THISP);
void PRIVATE(socket, open)    (THISP);
void PRIVATE(socket, fillSocketAddress) (THISP, char* ipaddr);

//public from here on

//the constructor
INSTP PUBLIC(socket, new)(char* ipaddr, int port)
  {
  socket_class* this = NEW_THIS();
  
  this->s = 0;
  this->isOpen = true;
  this->port = port;
  fillSocketAddress(this, ipaddr);
  
  startup(this);

  return this;
  }

//the destructor
void PUBLIC(socket, dtor)(THISP)
  {
  SET_THIS();
  
  cleanup(this);
  free(this);
  }

//establish the connection
void PUBLIC(socket, connect)(THISP)
  {
  SET_THIS();
  
  int rc;
  int gle;

  open(this);
  if (!this->isOpen) return;

  rc = connect(this->s, (SOCKADDR *)&this->addr, sizeof(SOCKADDR_IN));
  if (rc)
    gle = WSAGetLastError();
  }

//send a packet
void PUBLIC(socket, send)(THISP, char* buf, int len)
  {
  SET_THIS();
  int rc;
  int gle;
  if (!this->isOpen) return;

  rc = send(this->s, buf, len, 0);    
  if (rc)
    gle = WSAGetLastError();
  }

//receive a packet
void PUBLIC(socket, recv)(THISP, char* buf, int maxlen)
  {
  SET_THIS();
  int rc;
  int gle;
  if (!this->isOpen) return;
    
  rc = recv(this->s, buf, maxlen, 0);    
  if (rc)
    gle = WSAGetLastError();
  }

//return how many bytes are available to read
unsigned long PUBLIC(socket, avail)(THISP)
  {
  SET_THIS();
  int rc;
  int gle;
  u_long arg;

  if (!this->isOpen) return 0;
  arg = 0;
  rc = ioctlsocket (this->s, FIONREAD, &arg);
  if (rc)
    {
    gle = WSAGetLastError();
    return 0;
    }

  return arg;
  }


//private from here on

//establish the WSA environment
void PRIVATE(socket, startup) (THISP)
  {
  //SET_THIS();

  WORD wVersionRequested;
  WSADATA wsaData;
  wVersionRequested = MAKEWORD( 2, 2 );
  WSAStartup(wVersionRequested,  &wsaData );
  }

//create the socket
void PRIVATE(socket, open) (THISP)
  {
  SET_THIS();
  int gle;

  this->s = socket(AF_INET, SOCK_STREAM, 0);
  if (this->s == INVALID_SOCKET)
    gle = WSAGetLastError();
  else
    this->isOpen = true;
  }

//close the socket
void PRIVATE(socket, close) (THISP)
  {
  SET_THIS();

  if (!this->isOpen) return;
  closesocket(this->s);
  this->isOpen = false;
  }

//ensure the socket is close and kill the WSA environment
void PRIVATE(socket, cleanup) (THISP)
  {
  SET_THIS();
  
  close(this);
  WSACleanup( );
  }

//populate the addr structure based on the ipaddr and port
void PRIVATE(socket, fillSocketAddress) (THISP, char* ipaddr)
  {
  SET_THIS();

  memset(&this->addr, 0, sizeof(SOCKADDR_IN));
  this->addr.sin_family = AF_INET;
  this->addr.sin_port = htons(this->port);

  //todo: convert string to an actual addr
  this->addr.sin_addr.S_un.S_un_b.s_b1 = 127;
  this->addr.sin_addr.S_un.S_un_b.s_b2 = 0;
  this->addr.sin_addr.S_un.S_un_b.s_b3 = 0;
  this->addr.sin_addr.S_un.S_un_b.s_b4 = 1;
  }







Contact me about content on this page using john_web-at-arrizza-dot-com
For Web Master or site problems contact: webadmin-at-arrizza-dot-com
Copyright John Arrizza (c) 2001,2002,2003,2004,2005,2006,2007