From: paul@rsi.UUCP (Paul Hite)
Newsgroups: rec.games.mud
Subject: Re: NEW DIKUMUD CLIENT!!! (included/long)
Keywords: TINTIN
Date: 7 Apr 92 20:37:31 GMT
Organization: PRC Realty Systems, McLean VA.

In article <1992Apr1.231303.28120@daimi.aau.dk>, pjunold@daimi.aau.dk (Peter Joachim Unold) writes:

Thanks, Peter!  tintin.c will be the basis for my own private client.  I have
hacked on it just a wee bit so far and I'm including my version below.

> Some people couldn't compile the prog because they used a none-ANSI c-compiler.
> It works fine with GNU's gcc..... try: gcc tintin.c -otintin
I have removed the ansi c contructs and replaced them with classic c constructs.
 
> I've tested the prog. on a sun3 and on a sparc and it worked ok. However it
> it didn't work on the HP I tested it on. I dunno why in the moment but I'll try
> to get it fixed.....
It's the fcntl's.  To get it working on an HP replace both occurances of 
O_NDELAY with O_NONBLOCK.  I just tested this on our 9000/850 running hp-ux 7.0.

> Another thing:
> I use the function stricmp in my prog. I thought it was a ANSI defined
I have included your replacement function.

Also alias was not working for me. "#alias eb=get bread bag;eat bread" would
define the alias as "eb=get bread bag" and attempt an "eat bread" now.  I have
changed the code to allow a backslash to escape a semicolon.  So now
"#alias eb=get bread\;eat bread" works fine.

Paul Hite   PRC Realty Systems  McLean,Va   paul@prcrs.prc.com    (703) 556-2243
	a.k.a.  Perderabo/Wintergreen/Clutch on Dikus
-----------------------------snip-------------------------------------------
/*                 T I N T I N v1.0
 *     (T)he K(I)cki(N) (T)ick D(I)kumud Clie(N)t
 *             Coded by Peter Unold 1992
 *            email: pjunold@daimi.aau.dk
 */
#include <stdio.h>
#include <string.h> 
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <ctype.h>

#define ALIASROOM 30
#define ACTIONROOM 30

/******** PROTOTYPES FOR FUNCTIONS **********/
void runtintin();
void syserr();
void read_coms();
void parseinput();
void infofd();
void tickon();
void tickoff();
void getuserinput();
static void tickfunc();
static void myquitsig();
void parse_input();
void parse_tintin();
void substitute_alias();
int search_alias();
char *space_out();
void check_action();
void gettelnetoutput();
void parse_alias();
void parse_action();
void show_aliases();
void show_actions();

char inputline[50];

char aliasleft[ALIASROOM][20];
char aliasright[ALIASROOM][100];
int aliasno=0;

char actionleft[ACTIONROOM][100];
char actionright[ACTIONROOM][100];
int actionno=0;

int pfdto[2],pfdfrom[2];

char buffer[512], linebuffer[512];
char *cpbufferdest=linebuffer;
char *netaddress, *portnumber;

long time0;
int sec_to_tick,tickswitch=0;

int main(argc,argv)
char *argv[];
{
  if(argc!=3) {
    fprintf(stderr,"USAGE: tintin mudaddress portnumber\n");
    exit(1);
  }

  netaddress=argv[1];
  portnumber=argv[2];
  runtintin();  

  return(0);
}

/**********************************/
/* child process - calling telnet */
/**********************************/
mychild()
{
  if(close(1)==-1)
    syserr("close0");
  if(dup(pfdfrom[1])!=1)
    syserr("dup");
  if(close(pfdfrom[0])==-1 || close(pfdfrom[1])==-1)
    syserr("close");
  if(close(0)==-1)
    syserr("close1");
  if(dup(pfdto[0])!=0)
    syserr("dup");
  if(close(pfdto[0])==-1 || close(pfdto[1])==-1)
    syserr("close2");
  execlp("telnet","telnet",netaddress,portnumber,NULL);
  syserr("execl");
}

/**********************************************************/
/* main function. stays in it until a signal get's it out */
/**********************************************************/
void runtintin()
{
  int i,flag,inputlinelen,dun=0;
  char inputline[80],*argptr,linebuffer[512];
  char *cptr,*cptrs,*cptrd;

  if(pipe(pfdto)==-1)
    syserr("pipe");
  if(pipe(pfdfrom)==-1)
    syserr("pipe"); 

  switch(fork()) {
    case -1:
      syserr("fork");
    case 0:
      mychild();
      break;
  }

   if(close(pfdto[0])==-1)
     syserr("close");
   if(close(pfdfrom[1])==-1)
     syserr("close"); 

  if(signal(SIGCLD,myquitsig)==BADSIG)
    syserr("signal");
  if(signal(SIGINT,myquitsig)==BADSIG)
    syserr("signal");
  if(signal(SIGTERM,myquitsig)==BADSIG)
    syserr("signal");
  if(signal(SIGPIPE,myquitsig)==BADSIG)
    syserr("signal");

/****************MAIN-LOOP***************************/

  cptrd=linebuffer;
  puts("TINTIN IS ON THE ROAD AGAIN!!!!!!! KILLKILLKILL!!!!\n");

  for(;;) {

    gettelnetoutput();

    if(dun==0) {                  /*make pipes none-buffered, only done once */
      flag=fcntl(0,F_GETFL ,0);   /*this is weird, but it MUST be right here*/
      fcntl(0,F_SETFL,flag | O_NDELAY); 
      flag=fcntl(pfdfrom[0],F_GETFL ,0);
      fcntl(pfdfrom[0],F_SETFL,flag | O_NDELAY); 
      dun=1;
    }

    getuserinput();
  }

}

/**********************************************/
/* GET OUTPUT FROM TELNET AND CUT INTO LINES  */
/**********************************************/
void gettelnetoutput()
{
  char *cpbuffersource;
  int chargot;

  if((chargot=read(pfdfrom[0],buffer,512))>0) {
    write(1,buffer,chargot);

    cpbuffersource=buffer;

    while(cpbuffersource<buffer+chargot) {
      if(*cpbuffersource=='\n') {
        *cpbufferdest='\0';
        cpbufferdest=linebuffer;
        cpbuffersource++;
        check_action();
      }
      else
        *cpbufferdest++ = *cpbuffersource++;
    }
  }
}

/***********************/
/* check for an action */
/***********************/
void check_action()
{
  int i;
  char *cp, outtext[512];

  i = -1;
  while(++i<actionno) {
    if(actionleft[i][0]=='&' && (cp=strchr(linebuffer+1,' '))!=NULL &&
    stricmp(&actionleft[i][2], cp+1)==NULL) {
      *cp='\0';
      substitute_alias(actionright[i], outtext, linebuffer+1 );      
      parse_input(outtext);
      break;
    }
    else if(stricmp(&actionleft[i][0], linebuffer+1)==NULL) {
      printf("[%s]\n",actionright[i]);
      parse_input(actionright[i]);
    }
  }
}

/**************************************/
/* READ USER INPUT AND SEND TO PARSER */
/**************************************/
void getuserinput()
{
  char inputline[512];
  int inputlinelen;

  inputlinelen=read(0, inputline, 80);
  if(inputlinelen>=0) { 
    inputline[inputlinelen-1]='\0';
    parse_input(inputline);
  }
}

/********************************/
/* SEND A TEXT-STRING TO TELNET */
/********************************/
void sendtotelnet(cptr)
char *cptr;
{
  char textout[512];
  int i;

  strcpy(textout, cptr);
  textout[i=strlen(cptr)]='\n';
  if(write(pfdto[1], textout, i+1)==-1)
    syserr("write");
}

/****************************/
/* SUB-ROUNTINES FOR TICKER */
/****************************/
void tickon()
{
  tickswitch=1;
  time0=time(NULL);
  if(signal(SIGALRM,tickfunc)==BADSIG)
    syserr("signal");
  alarm(1);
  printf("#TICKER IS NOW RUNNING AND RESET\n>");
}

void tickoff()
{
  tickswitch=0;
  printf("#TICKER IS NOW OFF\n>");
}

static void tickfunc()
{
  if(tickswitch) {
    alarm(1);
    sec_to_tick=75-((time(NULL)-time0)%75);
    if(sec_to_tick==10)
      printf("#10 SECONDS TO TICK!!!!!!!!!!\n>");
    else if(sec_to_tick==5)
      printf("# 5 SECONDS TO TICK!!!!!!!!!!\n>");
  }
}

/*********************************************/
/* this is where we get out when telnet dies */
/*********************************************/
static void myquitsig()
{
  int flag;

  flag=fcntl(0,F_GETFL ,0);
  fcntl(0,F_SETFL,flag & ~O_NDELAY); 
  printf("\n#TINTIN AND SNOWY GOES TO SLEEP.....\n");
  exit(0);
}
 
/*************************************************/
/* print system call error message and terminate */
/* this function was lifted... SO WHAT!?!?!??!   */
/*************************************************/
void syserr(msg)
char *msg;
{
  extern int errno, sys_nerr;
  extern char *sys_errlist[];

  fprintf(stderr,"ERROR: %s (%d",msg, errno);
  if(errno>0 && errno<sys_nerr)
    fprintf(stderr,": %s)\n",sys_errlist[errno]);
  else
    fprintf(stderr,")\n");
  exit(1);
}

/************************************/
/* READ AND PARSE ALIAS/ACTION FILE */
/************************************/
void read_coms(filename)
char *filename;
{
  FILE *myfile;
  char inputline[100],*cptr;
  int aliaslen,actionlen;

  if((myfile=fopen(filename,"rt"))==NULL) {
    printf("#ERROR - couldn't open file:%s\n> ",filename);
    return;
  }

  while(fgets(inputline, 100, myfile)) {
    *(strchr(inputline, '\n'))='\0';
    if(strncmp(inputline, "#alias ", 7)==NULL) 
      parse_alias(inputline+7);
    if(strncmp(inputline, "#action ", 8)==NULL) 
      parse_action(inputline+8);
  }

  fclose(myfile);
}

/********************************************************/
/* Parse input from user and write to telnet input pipe */
/********************************************************/
void parse_input(commandline)
char *commandline;
{
  int aliascomno;
  int escapenext;

  char command[512], arg[512], outtext[512];
  char *cpsource, *cpdest;

  if(*commandline=='\0')
    sendtotelnet(commandline);    

  cpsource=commandline;

  while(*cpsource!='\0') {

    cpsource=space_out(cpsource);
    cpdest=command;

    while(*cpsource!=';' && *cpsource!=' ' && *cpsource!='\0')
      *cpdest++ = *cpsource++;
    *cpdest='\0';

    cpsource=space_out(cpsource);
    cpdest=arg;

    escapenext=0;
    while((*cpsource!=';' || escapenext) && *cpsource!='\0') {
      if(*cpsource == '\\') {
        escapenext=1;
        cpsource++;
      } else {
        *cpdest++ = *cpsource++;
	escapenext=0;
      }
    }
    *cpdest='\0';

    aliascomno=search_alias(command);
    if(aliascomno<aliasno) {
      substitute_alias(aliasright[aliascomno], command, arg);
      parse_input(command);
    }
    else {
      if(*command=='#')      
        parse_tintin(command,arg);
      else {
        if(*arg!='\0') {
          strcat(command, " ");
          strcat(command, arg);
        }
        sendtotelnet(command);
      }
    }

    if(*cpsource==';')
      cpsource++;
  }

}

/**********************************************/
/* Parse Tintin's special commands            */
/* this is where to stuff in your own comands */
/**********************************************/
void parse_tintin(command,arg)
char *command, *arg;
{
  char outtext[100];
  int i;

/*********REPEAT COMMAND*********/
  if(isdigit(*(command+1))) {
    i=atoi(command+1);
    if(i>0 && i<21) {
      while(i-->0)
        parse_input(arg);
    }
    else
      printf("#HEY! ONLY VALUES BETWEEN 1 AND 20 ALLOWED!\n> ");
  return;
  }

/**********TICKON COMMAND**********/
  if(stricmp("#tickon",command)==0) {
    tickon();
    return;
  }

/**********TICKOFF COMMAND**********/
  if(stricmp("#tickoff",command)==0) {
    tickoff();
    return;
  }

/**********TICK COMMAND**********/
  if(stricmp("#tick",command)==0) {
    if(tickswitch)
      printf("#%d SECONDS TO TICK!\n>",sec_to_tick);
    else
      printf("#DUNNO TIME! THE TICKER IS NOT RUNNIN!\n>");
    return;
  }

/**********TICKTELL COMMAND**********/
  if(stricmp("#ticktell",command)==0 && *arg!='\0') {
    sprintf(outtext,"tell %s there is now %d seconds to next tick.",arg,sec_to_tick);
    parse_input(outtext);  
    return;
  }

/**********ALIAS COMMAND**********/
  if(stricmp("#alias",command)==0) {
    if(*arg=='\0')
      show_aliases();
    else
      parse_alias(arg);
    return;
  }

/**********ACTION COMMAND**********/
  if(stricmp("#action",command)==0) {
    if(*arg=='\0')
      show_actions();
    else
      parse_action(arg);
    return;
  }

/**********READCOMS**************/
  if(stricmp("#readcoms",command)==0) {
    if(*arg=='\0')
      printf("#READ WHAT FILE?\n> ");
    else
      read_coms(arg);
    return;
   }

/************HELP************/
  if(stricmp("#help",command)==0) {
    printf("#LIST OF TINTIN-COMMANDS:\n> ");
    printf("#NUMBER COMMAND             :REPEATS 'COMMAND' 'NUMBER' TIMES\n> ");
    printf("#ACTION [TEXT[=[TEXT]]]     :LIST/DELETE/DISPLAY/DEFINE ACTIONS\n> ");
    printf("#ALIAS  [TEXT[=[TEXT]]]     :LIST/DELETE/DISPLAY/DEFINE ALIASES\n> ");
    printf("#HELP                       :THIS TEXT\n> ");
    printf("#READCOMS FILENAME          :READS A FILE WITH ACTIONS/ALIASES DEFS.\n> ");
    printf("#TICKON                     :TURNS TICK-CLOCK/WARNINGS ON\n> ");
    printf("#TICKOFF                    :TURNS TICK-CLOCK/WARNINGS OFF\n> ");
    printf("#TICK                       :SHOWS #SECONDS TO NEXT TICK\n> ");
    printf("#TICKTELL PLAYER            :TELLS 'PLAYER' #SECONDS TO TICK\n> ");
    return;
  }

  printf("#UNKNOWN TINTIN COMMAND!\n> ");
}

/**************************************/
/* Substitute all '&'s with cpsubtext */
/**************************************/
void substitute_alias(cpsource, cpdest, cpsubtext)
char *cpsource, *cpdest, *cpsubtext;
{
  int subtextlen=strlen(cpsubtext);

  while(*cpsource) {
    if(*cpsource=='&') {
      if(*cpsubtext=='\0') {
        *cpdest++=' ';
        cpsource++;
      }
      else {
        strcpy(cpdest, cpsubtext);
        cpdest+=subtextlen;
        cpsource++;
      }
    }
    else
      *cpdest++ = *cpsource++;
  }
  *cpdest='\0';
}

/*********************************************/
/* search for alias in list                  */ 
/* return alias index or aliasno if notfound */
/*********************************************/
int search_alias(cptr)
char *cptr;
{
  int i = -1;
  while(++i<aliasno && stricmp(aliasleft[i], cptr));
  return i;
}

/***********************************************/
/* search for action in list                   */ 
/* return action index or actionno if notfound */
/***********************************************/
int search_action(cptr)
char *cptr;
{
  int i = -1;
  while(++i<actionno && stricmp(actionleft[i], cptr));
  return i;
}

/**************************************/
/* move pointer to next no-space-char */
/**************************************/
char *space_out(cptr)
char *cptr;
{
  while(*cptr==' ')
    cptr++;
  return cptr;
}

/***********************************/
/* PARSE AN ALIAS. ADD/DELETE/SHOW */
/***********************************/
void parse_alias(cptr)
char *cptr;
{
  int i,j;
  char *left,*right,*cptr2;

  left=cptr=space_out(cptr);

  while(*cptr!='=' && *cptr!=' ' && *cptr!='\0')
    cptr++;

  cptr2=strchr(cptr, '=');

  *cptr='\0';

  if(cptr2==NULL) {
    if((i=search_alias(left))<aliasno)
      printf("#ALIAS: %s=%s\n> ",aliasleft[i],aliasright[i]);
    else
      printf("#UNKNOWN ALIAS:%s\n> ",left);
  }

  else {
    right=cptr=space_out(++cptr2);
    if(*right!='\0') {
      if((i=search_alias(left))==aliasno)
	aliasno++;
      strcpy(aliasleft[i], left);
      strcpy(aliasright[i], right);
      printf("#NEW ALIAS:%s=%s\n> ",left,right);
    }

    else {
      if((i=search_alias(left))==aliasno)
	printf("#UNKNOWN ALIAS:%s\n> ",left);
      else {
	j=i;
	while(j<aliasno) {
	  strcpy(aliasleft[i],aliasleft[j]);
	  strcpy(aliasright[i],aliasright[j]);
	  j++;
	}
	aliasno--;
	printf("#ALIAS DELETED\n> ");
      }
    }
  }
}

/************************************/
/* PARSE AN ACTION. ADD/DELETE/SHOW */
/************************************/
void parse_action(cptr)
char *cptr;
{
  int i,j;
  char *left,*right,*cptr2;

  left=cptr=space_out(cptr);

  while(*cptr!='=' && *cptr!='\0')
    cptr++;

  cptr2=strchr(cptr, '=');

  *cptr='\0';

  if(cptr2==NULL) {
    if((i=search_action(left))<actionno)
      printf("#ACTION: %s=%s\n> ",actionleft[i],actionright[i]);
    else
      printf("#UNKNOWN ACTION:%s\n> ",left);
  }

  else {
    right=cptr=space_out(++cptr2);
    if(*right!='\0') {
      if((i=search_action(left))==actionno)
	actionno++;
      strcpy(actionleft[i], left);
      strcpy(actionright[i], right);
      printf("#NEW ACTION:%s=%s\n> ",left,right);
    }

    else {
      if((i=search_action(left))==actionno)
	printf("#UNKNOWN ACTION:%s\n> ",left);
      else {
	j=i;
	while(j<actionno) {
	  strcpy(actionleft[i],actionleft[j]);
	  strcpy(actionright[i],actionright[j]);
	  j++;
	}
	actionno--;
	printf("#ACTION DELETED\n> ");
      }
    }
  }
}


/****************/
/* list aliases */
/****************/
void show_aliases()
{
  int i=0;
  printf("#THE FOLLOWING %d ALIASES IS DEFINED:\n> ",aliasno);

  while(i<aliasno) {
    printf("#ALIAS: %s=%s\n> ",aliasleft[i],aliasright[i]);
    i++;
  }
}

/****************/
/* list actions */
/****************/
void show_actions()
{
  int i=0;
  printf("#THE FOLLOWING %d ACTIONS IS DEFINED:\n> ",actionno);

  while(i<actionno) {
    printf("#ACTION: %s=%s\n> ",actionleft[i],actionright[i]);
    i++;
  }
}


/**************************************/
/* my stricmp. almost lifted from K&C */
/**************************************/
int stricmp(s, t)
char *s, *t;
{
  for(; tolower(*s)==tolower(*t); s++, t++)
    if(*s=='\0')
      return(0);
  return(*s-*t);
}
----------------------------------------last line--------------------------
Newsgroups: rec.games.mud