/*
 *	$Source: /home/nlfm/Working/Zircon/Released/plugins/Sed/RCS/sed.c,v $
 *	$Date: 1997/01/09 11:27:16 $
 *	$Revision: 1.18.1.1 $
 *
 *	Copyright (c) 1996 L.F. Marshall, University of Newcastle upon tyne
 */

#include "tcl.h"
#include <string.h>

/*
 *	Yes, this is a horrible piece of code isn't it.
 */

#define SED_VERSION "1.18.3"

/*

int Sed_decrypt(clientData, interp, objc, objv)
ClientData clientData;
Tcl_Interp *interp;
int objc;
Tcl_Obj *objv[];
{
    char line[1024];
    char *cp = line, *lp, vern = '\0', *key;
    int klen, len, cycle = 0;
    Tcl_Obj *resPtr = ((Interp *) interp)->objResult;
    
    if (objc != 3) {
	Tcl_StringObjAppend(interp, resPtr, "wrong # args: should be \"", -1);
	Tcl_StringObjAppendObj(interp, resPtr, objv[0]);
	Tcl_StringObjAppend(interp, resPtr,  " string key\"", -1);
	return TCL_ERROR;
    }
    key = Tcl_GetStringFromObj(objv[2], &klen);
    if (klen == 0)
    {
        Tcl_StringObjAppend(interp, resPtr, "<ENCRYPTED TEXT>", -1);
        return TCL_OK;
    }

    lp = Tcl_GetStringFromObj(interp, objv[1], &len);

    while (*lp) 
    {
	if (*lp == '\\')
	{
	    len -= 1;
	    switch (*++lp)
	    {
	    case 'a' :
		*cp++ = '\001';
		break;
	    case '\\' :
		*cp++ = '\\';
		break;
	    case '0' :
		*cp++ = '\0';
		break;
	    case 'n' :
		*cp++ = '\n';
		break;
	    case 'r' :
		*cp++ = '\r';
		break;
	    }
	    lp++;
	}
	else
	{
	    *cp++ = *lp++;
	}
    }
    for (lp = line ; len--; lp++)
    {
	vern ^= *lp = vern ^ *lp ^ key[cycle];
	cycle = (cycle + 1) % klen;
    }
    *lp='\0';
    Tcl_StringObjAppend(interp, resPtr, line, -1);
    return TCL_OK;
}

int Sed_encrypt(clientData, interp, objc, objv)
ClientData clientData;
Tcl_Interp *interp;
int objc;
Tcl_Obj *objv[];
{
    char *lp, vern = '\0', gash, *key, str[2] = {'\0', '\0'};
    int cycle = 0, len, len2, klen;
    Tcl_Obj *resPtr = ((Interp *) interp)->objResult;

    if (objc != 3)
    {
	Tcl_StringObjAppend(interp, resPtr, "wrong # args: should be \"", -1);
	Tcl_StringObjAppendObj(interp, resPtr, objv[0]);
	Tcl_StringObjAppend(interp, resPtr,  " string key\"", -1);
	return TCL_ERROR;
    }
    key = Tcl_GetStringFromObj(interp, objv[2], &klen);
    if (klen == 0)
    {
        Tcl_StringObjAppend(interp, resPtr, "<ENCRYPTED TEXT>", -1);
        return TCL_OK;
    }

    lp = Tcl_GetStringFromObj(interp, objv[1], &len);
    len2 = len;

    for (; len--; lp++)
    {
	gash = *lp;
	*lp = vern ^ *lp ^ key[cycle];
	vern ^= gash;
	cycle = (cycle + 1) % klen;
    }
    Tcl_StringObjAppend(interp, resPtr, "\001SED ", -1);
    lp = Tcl_GetStringFromObj(interp, objv[1], &len);
    while (len2--)
    {
	switch (*lp)
	{
	case '\001' :
	    Tcl_StringObjAppend(interp, resPtr, "\\a", 2);
	    break;
	case '\\' :
	    Tcl_StringObjAppend(interp, resPtr, "\\\\", 2);
	    break;
	case '\0' :
	    Tcl_StringObjAppend(interp, resPtr, "\\0", 2);
	    break;
	case '\n' :
	    Tcl_StringObjAppend(interp, resPtr, "\\n", 2);
	    break;
	case '\r' :
	    Tcl_StringObjAppend(interp, resPtr, "\\r", 2);
	    break;
	default :
 	    str[0] = *lp;
	    Tcl_StringObjAppend(interp, resPtr, str, 1);
	    break;
	}
	lp++;
    }
    Tcl_StringObjAppend(interp, resPtr, "\001", 1);
    return TCL_OK;
}

*/

int Sed_decrypt(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp;
int argc;
char *argv[];
{
    char line[1024];
    char *cp = line, *lp, vern = '\0', *key;
    int klen, len, cycle = 0;
    
    if (argc != 3) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
	  " string key\"", (char *) 0);
	return TCL_ERROR;
    }
    if ((klen = strlen(key = argv[2])) == 0)
    {
        Tcl_AppendResult(interp, "<ENCRYPTED TEXT>", (char *) 0);
        return TCL_OK;
    }

    len = strlen(lp = argv[1]);

    while (*lp) 
    {
	if (*lp == '\\')
	{
	    len -= 1;
	    switch (*++lp)
	    {
	    case 'a' :
		*cp++ = '\001';
		break;
	    case '\\' :
		*cp++ = '\\';
		break;
	    case '0' :
		*cp++ = '\0';
		break;
	    case 'n' :
		*cp++ = '\n';
		break;
	    case 'r' :
		*cp++ = '\r';
		break;
	    }
	    lp++;
	}
	else
	{
	    *cp++ = *lp++;
	}
    }
    for (lp = line ; len--; lp++)
    {
	vern ^= *lp = vern ^ *lp ^ key[cycle];
	cycle = (cycle + 1) % klen;
    }
    *lp='\0';
    Tcl_AppendResult(interp, line, (char *) 0);
    return TCL_OK;
}

int Sed_encrypt(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp;
int argc;
char *argv[];
{
    char *lp, vern = '\0', gash, *key, str[2] = {'\0', '\0'};
    int cycle = 0, len, len2, klen;

    if (argc != 3) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
	  " string key\"", (char *) 0);
	return TCL_ERROR;
    }
    if ((klen = strlen(key = argv[2])) == 0)
    {
        Tcl_AppendResult(interp, argv[1], (char *) 0);
        return TCL_OK;
    }
    len2 = len = strlen(argv[1]);

    for (lp = argv[1] ; len--; lp++)
    {
	gash = *lp;
	*lp = vern ^ *lp ^ key[cycle];
	vern ^= gash;
	cycle = (cycle + 1) % klen;
    }
    Tcl_AppendResult(interp, "\001SED ", (char *) 0);
    lp = argv[1];
    while (len2--)
    {
	switch (*lp)
	{
	case '\001' :
	    Tcl_AppendResult(interp, "\\a", (char *) 0);
	    break;
	case '\\' :
	    Tcl_AppendResult(interp, "\\\\", (char *) 0);
	    break;
	case '\0' :
	    Tcl_AppendResult(interp, "\\0", (char *) 0);
	    break;
	case '\n' :
	    Tcl_AppendResult(interp, "\\n", (char *) 0);
	    break;
	case '\r' :
	    Tcl_AppendResult(interp, "\\r", (char *) 0);
	    break;
	default :
 	    str[0] = *lp;
	    Tcl_AppendResult(interp, str, (char *) 0);
	    break;
	}
	lp++;
    }
    Tcl_AppendResult(interp, "\001", (char *) 0);
    return TCL_OK;
}

int Sed_Init(interp)
Tcl_Interp *interp; /* The current Tcl interpreter */
{
/*
 *	Add the commands encrypt and decrypt.
 */
    Tcl_CreateCommand(interp,"encrypt",Sed_encrypt, (ClientData) 0, 0);
    Tcl_CreateCommand(interp,"decrypt", Sed_decrypt, (ClientData) 0, 0);
/*
 *	Register Sed as a package
 */
    return Tcl_PkgProvide(interp, "Sed", SED_VERSION);
}
