Category : Recently Uploaded Files
Archive   : MSQ320.ZIP
Filename : WRAP.C

 
Output of file : WRAP.C contained in archive : MSQ320.ZIP
/* wrap.c
**
** released into the PUBLIC DOMAIN 30 jul 1990 by jim nutt
** Changes released into the PUBLIC DOMAIN 10 jul 1994 by John Dennis
**
** editor for msgedsq
*/

/* include files */

#include

#include "msged.h"
#include "editmail.h"
#include "main.h"
#include "keys.h"
#include "menu.h"
#include "help.h"
#include "wrap.h"
#include "nshow.h"
#include "dialogs.h"
#include "makemsgn.h"

/* prototypes */

void shell_to_dos(void); /* msged.c */
msg * duplicatemsg(msg *); /* maintmsg.c */

/* local variables */

static LINE *current = NULL; /* current line */
static LINE *pagetop = NULL; /* top line of page */
static LINE *msgtop = NULL; /* top line of file */
static LINE *udel = NULL; /* deleted line buffer */
static LINE *clip = NULL; /* for blocks of text */
static char line_buf[255]; /* buffer for the current line */
static int x = 1; /* x coordinate, 1 based */
static int y = 1; /* y coordinate, 1 based */
static int ed_miny = 1; /* logical min y value */
static int ed_maxy = 1; /* logical max y value */
static int edmaxy = 0; /* real min x value */
static int edminy = 0; /* real max y value */
static int quote_len = 14; /* length to look for quote */
static int done = 0; /* finished editing? */
static int insert = 1; /* insert = on ? */
static int blocking = 0; /* block on? */
static msg *messg; /* message being edited */

/*
**
** These functions are called externally.
**
*/

static void rotate(void)
{
rot13 = (rot13 + 1) % 3;
}


static void nada(void)
{
/* null */
}


char * e_getbind(unsigned int key)
{
unsigned int i = 0;
void ( *action)();

if (key & 0xff)
action = editckeys[key & 0xff];
else
action = editakeys[(key >> 8) & 0xff];

while ((editcmds[i].label != NULL) && (action != editcmds[i].action))
{
i++;
}
return editcmds[i].label;
}


char * e_getlabels(int i)
{
return editcmds[i].label;
}


void e_assignkey(unsigned int key, char *label)
{
unsigned int i = 0;

while ((editcmds[i].label != NULL) && (strncmp(editcmds[i].label,label,strlen(editcmds[i].label)) != 0))
{
i++;
}
if (editcmds[i].label != NULL)
if (key & 0xff)
editckeys[key & 0xff] = editcmds[i].action;
else
editakeys[(key >> 8) & 0xff] = editcmds[i].action;
}


LINE * insline(LINE *cl)
{
LINE *nl;

if ((nl = calloc(1, sizeof(LINE))) == NULL)
return nl;

if (cl == NULL)
return nl;

nl->next = cl;
nl->prev = cl->prev;
cl->prev = nl;

if (nl->prev != NULL)
nl->prev->next = nl;

return nl;
}


/*
**
** Functions that are local to this file (excepting wrap and editmsg).
**
*/

/*
**
** Displays a line, translating the display type.
**
*/

static void EdPutLine(LINE *line, int y)
{
line->quote = isquote(line->text);
if (y <= ed_maxy) /* check line coords! */
PutLine(line, y + edminy);
else
ed_error("EdPutLine", "illegal coordinates - y = %d!", y);
}


/*
**
** Scrolls down one line.
**
*/

void ScrollDown(int y1, int y2)
{
if (y1 <= ed_maxy && y2 <= ed_maxy)
WScroll(0 , y1 + edminy, maxx-1, y2 + edminy, 0);
else
ed_error("ScrollDown", "illegal coordinates - y1 = %d!, y2 = %d", y1, y2);
}


/*
**
** Scrolls up one line.
**
*/

void ScrollUp(int y1, int y2)
{
if (y1 <= ed_maxy && y2 <= ed_maxy)
WScroll(0 , y1 + edminy, maxx-1, y2 + edminy, 1);
else
ed_error("ScrollUp", "illegal coordinates - y1 = %d!, y2 = %d", y1, y2);
}


/*
**
** Goes to a position on the screen.
**
*/

static void GotoXY(int x, int y)
{
if (x >= 1 && x <= maxx && y <= ed_maxy && y >= ed_miny)
Wgotoxy(x - 1, y + edminy);
}


/*
**
** Redraws the page, starting from the line passed and the y coord.
**
*/

void RedrawPage(LINE *start, int wherey)
{
LINE *cur = start;
LINE blank = {"", 0, 0, 0, 0, 0, NULL, NULL};
int cury = wherey;

if (start != NULL && wherey <= ed_maxy)
{
while (cur != NULL && cury <= ed_maxy)
{
EdPutLine(cur, cury);
cur = cur->next;
cury++;
}

/* if we have lines left on the screen, clear them - */
/* simple to just write over them with blank lines */

if (cury <= ed_maxy)
{
while (cury <= ed_maxy)
{
EdPutLine(&blank, cury);
cury++;
}
}
}
}


/*
**
** Inserts a line AFTER the current line.
**
*/

LINE *InsertLine(LINE *current)
{
LINE *new;

if ((new = calloc(1, sizeof(LINE))) == NULL)
return NULL;

new->next = current->next;
new->prev = current;
current->next = new;

if (new->next)
new->next->prev = new;

return new;
}


/*
**
** Copies the line_buf to the current line structure,
**
*/

void UnmarkLineBuf(void)
{
release(current->text);
current->text = strdup(line_buf);
}


/*
**
** Copies the current line text to the line_buf.
**
*/

void SetLineBuf(void)
{
memset(line_buf, 0, 254);
if (current->text)
strcpy(line_buf, current->text);
}


/*
**
** Determines if this is a white space.
**
*/

int iswhspace(char c) /* handle all non-space type chars */
{
if (c == ' ' || c == '\t')
return 1;

return 0;
}


/*
**
** Determines if the eol has a trailing space...
**
*/

int trailspace(char *text)
{
if (text == NULL || strlen(text) == 0)
return 1;

if (*(text + strlen(text) - 1) == ' ' || *(text + strlen(text) - 1) == '\n')
return 1;

return 0;
}


/*
**
** Determins if the line is a quote.
**
*/

int isquote(char *text)
{
char *s;

if (text == NULL || strlen(text) == 0)
return 0;

s = text;
while (*s && (s - text) < quote_len)
{
if (*s == '>')
return 1;

if (*s == '<')
return 0;
s++;
}
return 0;
}


/*
**
** Finds and returns the end of the quote_string on
** the past line of text.
**
*/

char *FindQuoteEnd(char *txt)
{
char *s, *c;

if (txt == NULL || strlen(txt) == 0)
return txt;

if (strlen(txt) <= quote_len)
{
s = txt + strlen(txt) - 1;
}
else
s = txt + quote_len;

if ((c = strchr(txt, '<')) != NULL)
{
/*
** Check for the special case of '' or some such similar
** text stuffing up the quoting process.
*/

if (c < s) /* mods by PE 1995-04-26 */
{
if (c > txt)
{
s = c - 1;
}
else if (c == txt)
{
return (txt);
}
}
}

while (s > txt && *s != '>') s--;

if (s == txt)
return txt;

if (*s == '>' && *(s + 1)) /* go past the '>' character */
{
/*
** We only want to increment two characters... this saves trouble
** when we encounter indents in the quotes. We could strip spaces
** when finding indents, but why bother...??
*/

s++;
if (*s == ' ' && *(s + 1))
s++;
}
return s;
}


/*
**
** Finds the best point to break a line.
**
*/

char *GetWrapPoint(char *text, int rm)
{
char *s, *sp;
int slen;

if (text == NULL || strlen(text) == 0)
return NULL;

/* find the point to look for a wrap & save the spot */

slen = strlen(text);
sp = text + ((slen > rm) ? rm - 1 : slen - 1);
s = sp;

if (*s == '\0' || *s == '\n' || *s == '\r')
return NULL;

if (!iswhspace(*s))
{
/* search backward for beginning of word */

while (*s && !iswhspace(*s))
{
if ((s - text) < (rm / 2))
{
/*
** Can't wrap any further, so split at EOL.
*/

s = (sp > text) ? sp - 1 : sp;
break;
}
s--;
}
s++;
}
else
{
/* search forward for the beginning of next word */

while (*s && iswhspace(*s))
{
if ((s - text) < (rm / 2))
break;

s++;
}
if (*s == '\0' || *s == '\n' || *s == '\r')
return NULL;
}
return s;
}



/*
**
** This is a VERY big procedure... Wraps a line & following ones.
**
*/

int wrap(LINE *cl, int x, int y, int rm)
{
LINE *l, *nl;
char *s, *t, *tl, ch;
int wrapped_line = 0;
int slen, space;

unused(x);
unused(y);
l = cl;

while (l != NULL) /* stop when no more lines to process */
{
/* get the next line for later use */

nl = l->next;

if (l->text == NULL || strlen(l->text) < rm)
{
/* we may want to copy stuff from the next line to this one */

if (nl == NULL || nl->text == NULL)
return wrapped_line; /* nothing we can do */

/*
** a '\n' terminates a para, so if we have one on this
** line, we want to stop wrapping and return.
*/

if (l->text != NULL && strchr(l->text, '\n') != NULL)
return wrapped_line;

/*
** Get the length of the current line.
*/

s = FindQuoteEnd(nl->text);

if (l->text != NULL)
slen = strlen(l->text);
else
slen = 0;

/*
** If the next line can fit on this line, then we may
** as well simply copy the entire line and delete the
** next line, otherwise we copy only what we have space
** for.
*/

if ((space = rm - slen) > strlen(s))
{
/* then we move the entire line up */

if ((tl = calloc(1, strlen(s) + slen + 2)) == NULL)
ed_error("wrap", "Memory allocation failed!");

/*
** Copy the text to the new memory.
*/

if (l->text)
strcpy(tl, l->text);
else
strcpy(tl, "");

if (trailspace(tl) == 0 && !iswhspace(*(s)))
if (*(s) != '\0' && *(s) != '\n')
strcat(tl, " ");

strcat(tl, s);

/*
** Delete the old line.
*/

l->next = nl->next;

if (l->next)
l->next->prev = l;

release(nl->text);
release(nl);
release(l->text);

l->text = tl;
wrapped_line = 1;
}
else
{
if (space == 0)
return wrapped_line;

/*
** We want to copy some words up to this line;
*/

t = s + space - 1;
tl = t;

/*
** We start the wrap at the amount of space left
** on the previous line. If that spot is on a
** word, then we move to the beginning of that
** word & wrap anything before that. If the word
** goes to the beginning of the line, then it is
** too big to wrap (we only wrap whole words).
*/

if (!iswhspace(*t))
{
while (t > s && !iswhspace(*t))
{
t--;
}
if (t == s) /* word too big */
return wrapped_line;
else
t++;
}
else
{
while (*t && iswhspace(*t)) t++;

if (*t == '\0' || *t == '\n')
t = tl;
}


/*
** Save current position.
*/

ch = *t;
*t = '\0';

if ((tl = calloc(1, slen + strlen(s) + 2)) == NULL)
ed_error("wrap", "Memory allocation failed!");

/*
** Copy stuff to be wrapped to the new memory.
*/

if (l->text)
strcpy(tl, l->text);
else
strcpy(tl, "");

if (trailspace(tl) == 0 && !iswhspace(*s))
strcat(tl, " ");

strcat(tl, s);

/*
** Assign new memory and move what is left on
** next line to beginning of that line (we don't
** bother to reallocate it).
*/

release(l->text);
l->text = tl;
wrapped_line = 1;
*t = ch;
memmove(s, t, strlen(t) + 1);
}
}
else
{
/*
** We want to wrap stuff on current line to the
** next line because current line is overflowing.
*/

if ((t = GetWrapPoint(l->text, rm)) == NULL)
return wrapped_line;

if (nl != NULL && nl->text != NULL && strchr(l->text, '\n') == NULL && l->quote == nl->quote)
{
if ((s = calloc(1, strlen(t) + strlen(nl->text) + 2)) == NULL)
ed_error("wrap", "Memory allocation failed!");

tl = FindQuoteEnd(nl->text);

if (t == NULL)
ed_error("wrap","logic error wrapping to next line!");

ch = *tl;
*tl = '\0';

strcpy(s, nl->text);
strcat(s, t);

if (trailspace(s) == 0)
strcat(s, " ");

*tl = ch;
strcat(s, tl);
release(nl->text);
nl->text = s;
*t = '\0';
wrapped_line = 1;
}
else
{
nl = InsertLine(l);
if (cl->quote)
{
nl->quote = 1;
s = FindQuoteEnd(l->text);
ch = *s;
*s = '\0';

if ((tl = calloc(1, strlen(t) + strlen(l->text) + 2)) == NULL)
ed_error("wrap", "Memory allocation failed!");

strcpy(tl, l->text);
strcat(tl, t);
*s = ch;
nl->text = tl;
}
else
nl->text = strdup(t);

*t = '\0';
wrapped_line = 1;
}
}
l = l->next;
}
return wrapped_line;
}

/* ===================================================== */


/*
**
** Toggles the quote status of the current line.
**
*/

static void toggle_quote(void)
{
if (current == NULL)
return;

if (current->quote)
current->quote = 0;
else
current->quote = 1;

EdPutLine(current, y);
}


/*
**
** Checks to see that the current X position is still
** on the line (ie x is not pase EOL...).
**
*/

void CheckXvalid(void)
{
SetLineBuf();
if (current->text == NULL || strlen(current->text) < x)
go_eol();
}


/*
**
** Finds the start of the current word at the current
** X position, and then returns the difference between
** that position and the current X position.
**
*/

int WordStart(void)
{
char *s, *b;

if (strlen(line_buf) == 0)
return 0;

s = line_buf + x - 1;
b = s;

if (iswhspace(*s))
return 0;

while (s > line_buf && !iswhspace(*s)) s--;
return (int)(b - s);
}


/*
**
** Inserts a char at the current position.
**
*/

static void insert_char(char ch)
{
int slen;
int wlen;

if (insert == 0 && line_buf[x - 1] != '\n')
line_buf[x - 1] = ch;
else
{
memmove(line_buf + x, line_buf + x - 1, strlen(line_buf + x - 1) + 1);
line_buf[x - 1] = ch;
}

UnmarkLineBuf();

current->templt = 0;
wlen = WordStart();
slen = strlen(current->text);

if (wrap(current, 0, 0, SW->rm) == 1)
{
SetLineBuf();
RedrawPage(current, y);
if (strlen(current->text) < x)
{
if (wlen)
{
x = wlen;
if (current->quote)
{
char *s;

s = FindQuoteEnd(current->text);
if (s && s > current->text)
x += (int)(s - current->text);
}
if (x > strlen(current->next->text))
x = strlen(current->next->text) - 1;
}
else
x = slen - strlen(current->text) - 1;

go_down();
}
}
else
EdPutLine(current, y);

x++;
SetLineBuf();
}


/*
**
** Deletes the character at the current X position.
**
*/

static void delete_character(void)
{
LINE *nl;

current->templt = 0;

if (strlen(line_buf) == 0 || line_buf[0] == '\n')
{
/*
** Current line is blank, so we delete it.
*/

if (current->next == NULL)
return;

current->next->prev = current->prev;
if (current->prev)
current->prev->next = current->next;

if (msgtop == current)
msgtop = current->next;

if (pagetop == current)
msgtop = current->next;

nl = current;
current = nl->next;

release(nl->text);
release(nl);
RedrawPage(current, y);
}
else
{
/*
** Else we just want to kill the char at x.
*/

memmove(line_buf + x - 1, line_buf + x, strlen(line_buf + x) + 1);

UnmarkLineBuf();

if (wrap(current, 0, 0, SW->rm) == 1)
RedrawPage(current, y);
else
EdPutLine(current, y);
}
SetLineBuf();
}


/*
**
** Deletes the char behind the current X pos and moves
** the cursor back one char.
**
*/

static void backspace(void)
{
if (x == 1)
{
if (current->prev == NULL)
return;

UnmarkLineBuf();
go_up();
go_eol();
delete_character();
}
else
{
x--;
delete_character();
}
EdPutLine(current, y);
}


static void delword(void)
{
char *s = line_buf + x - 1;

while ((*s) && !isspace(*s)) s++;
while ((*s) && isspace(*s)) s++;

strcpy(line_buf + x - 1, s);

UnmarkLineBuf();

wrap(current, x, y, SW->rm);
RedrawPage(current, y);

SetLineBuf();
}


static void go_left(void)
{
if (x == 1)
{
if (current->prev)
{
go_up();
go_eol();
}
}
else
x--;
}


static void go_right(void)
{
if (line_buf[x - 1] == '\0' || line_buf[x - 1] == '\n')
{
if (current->next)
{
go_down();
go_bol();
}
}
else
x++;
}


static void go_up(void)
{
UnmarkLineBuf();
if (current->prev)
{
current = current->prev;
if (y == ed_miny)
{
pagetop = current;
ScrollDown(1, ed_maxy);
EdPutLine(current, y);
}
else
y--;
}
CheckXvalid();
}


static void go_down(void)
{
UnmarkLineBuf();
if (current->next)
{
current = current->next;
if (y == ed_maxy)
{
ScrollUp(1, ed_maxy);
EdPutLine(current, y);
}
else
y++;
}
CheckXvalid();
}


static void go_bol(void)
{
x = 1;
}


static void go_eol(void)
{
x = strlen(line_buf);

if (line_buf[x - 1] != '\n')
x++;

x = min(max(1, x), SW->rm);
}


static void go_word_right(void)
{
int l = strlen(line_buf);

if (*(line_buf + x - 1) == '\0' || *(line_buf + x - 1) == '\n')
{
if (current->next != NULL)
{
go_down();
go_bol();
}
return;
}

while (isspace(*(line_buf + x - 1)) && x <= l)
x++;
while (!isspace(*(line_buf + x - 1)) && x <= l)
x++;
while (isspace(*(line_buf + x - 1)) && x <= l)
x++;

if (*(line_buf + x - 2) == '\n')
x--;
}


static void go_word_left(void)
{
if (x == 1)
{
if (current->prev != NULL)
{
go_up();
go_eol();
}
return;
}
while (isspace(*(line_buf + x - 1)) && x > 1)
x--;
while (!isspace(*(line_buf + x - 1)) && x > 1)
x--;
while (isspace(*(line_buf + x - 1)) && x > 1)
x--;
while (!isspace(*(line_buf + x - 1)) && x > 1)
x--;

if (x != 1)
x++;
}


static void go_pgup(void)
{
LINE *l = current;
int count = 1;

UnmarkLineBuf();
while (count < ed_maxy && current->prev)
{
count++;
current = current->prev;
}

/*
** If we actually moved, redraw the page.
*/

if (l != current)
{
y = 1;
RedrawPage(current, 1);
}

CheckXvalid();
}


static void go_pgdown(void)
{
LINE *l = current;
int count = 1;

UnmarkLineBuf();
while (count < ed_maxy && current->next)
{
count++;
current = current->next;
}

/*
** If we actually moved, redraw the page.
*/

if (l != current)
{
y = 1;
RedrawPage(current, 1);
}

CheckXvalid();
}


static void newline(void)
{
LINE *nl;

if ((nl = InsertLine(current)) == NULL)
return;

/*
** If the current line is a quote, then the break shouldn't
** cause a wrap from the previous line. This is prevented
** by a hard CR (which the user can then kill if wanted).
*/

if (current->quote && !strchr(line_buf, '\n'))
strcat(line_buf, "\n");

nl->text = strdup(line_buf + x - 1);
line_buf[x - 1] = '\0';

strcat(line_buf, "\n");

if (current->block)
nl->block = 1;

if (current->templt)
{
if (x == 1)
{
nl->templt = 1;
current->templt = 0;
}
else
{
current->templt = 0;
}
}

go_down();
go_bol();

wrap(current, 0, 0, SW->rm);
RedrawPage(current->prev, y - 1);
SetLineBuf();
}


/*
**
** Adds l to the deleted line queue.
**
*/

static void udel_add_q(LINE *l)
{
LINE *nl = udel;
int num = 0;

if (udel == NULL)
{
udel = l;
l->next = NULL;
l->prev = NULL;
return;
}

/*
** find the last line, keeping count of lines
** in the process.
*/

while (nl->next != NULL)
{
nl = nl->next;
num++;
}

/*
** If there are more than max num of lines, then
** we delete the oldest one (on the end of queue).
*/

if (num >= 30)
{
nl->prev->next = NULL;
release(nl->text);
release(nl);
}

/*
** Add the latest deleted line to the beginning of
** the queue.
*/

udel->prev = l;
l->next = udel;
l->prev = NULL;
udel = l;
}


static void delete_line(void)
{
LINE *nl;

if (current->next == NULL)
{
release(current->text);
current->text = strdup("\n");
EdPutLine(current, y);
CheckXvalid();
return;
}

current->next->prev = current->prev;
if (current->prev)
current->prev->next = current->next;

nl = current;
current = (nl->next != NULL) ? nl->next : nl->prev;

if (msgtop == nl)
msgtop = current;

/*
** Save the deleted line in a buffer.
*/

udel_add_q(nl);

/*
** Redraw the screen to reflect missing line.
*/

RedrawPage(current, y);
CheckXvalid();
}


/*
**
** Removes and returns the first line in the undelete
** buffer.
**
*/

static LINE *udel_delete_q(void)
{
LINE *nl = udel;

if (udel == NULL)
return NULL;

if (udel->next)
{
udel->next->prev = NULL;
udel = udel->next;
}
else
udel = NULL;

return nl;
}


/*
**
** If there is a line to undelete, undeletes the last
** line deleted and inserts it before the current line.
**
*/

static void undelete(void)
{
LINE *nl;

/*
** Get last line deleted.
*/

nl = udel_delete_q();

if (nl == NULL)
return;

/*
** Make sure we don't split it (the current block) in half ๐Ÿ™‚
*/

nl->templt = 0;

if (blocking && current->block)
nl->block = 1;
else
{
if (current->block == 0)
nl->block = 0;
}

/*
** Insert it ABOVE current line.
*/

nl->prev = current->prev;
current->prev = nl;
nl->next = current;
if (nl->prev)
nl->prev->next = nl;

/*
** Make it the current line && redraw page to reflect new line.
*/

UnmarkLineBuf();
current = nl;
RedrawPage(current, y);
CheckXvalid();
}


/*
**
** Clears all blocked lines in the message.
**
*/

static void ClearBlocks(void)
{
LINE *nl = msgtop;

while (nl != NULL)
{
if (nl->block)
nl->block = 0;

nl = nl->next;
}
blocking = 0;
}


/*
**
** Provides QEdit style blocking. Called everytime
** anchor is called (a new anchor has been laid).
**
*/

static void CalculateBlocks(void)
{
LINE *nl = msgtop;
int bl = 0; /* hit a block yet? */
int cp = 0; /* gone past current line? */

while (nl != NULL)
{
/*
** If we've passed the current line and hit the block
** and come out the other side, we want to stop.
*/

if (cp && bl && !nl->block)
break;

/*
** If bl = FALSE and we get blocked line, turn ON.
*/

if (!bl && nl->block)
bl = 1;

/*
** If we hit current line.
*/

if (nl == current)
{
/*
** If anchor is hit in the middle of a block,
** then we want to recreate the block on that line.
*/

if (nl->block)
{
ClearBlocks();
bl = 0;
}

nl->block = 1;
if (bl)
{
/*
** If we're already blocking, then we want to
** stop at the current line.
*/
break;
}
else
{
if (blocking == 0)
{
/*
** If we aren't blocking and global blocking hasn't
** been set, then we want to stop, else start blocking.
*/
break;
}
}
cp = 1;
}

/*
** If we've passed the current line and haven't hit
** a block yet, then we want to block all lines between.
*/

if (cp && !bl)
nl->block = 1;

/*
** If we haven't hit the current line, but have
** hit the block, we want to mark stuff in between.
*/

if (!cp && bl)
nl->block = 1;

nl = nl->next;
}
blocking = 1;
}


/*
**
** Kills the current block.
**
*/

static void unblock(void)
{
LINE *nl = current;
int y2 = y;

ClearBlocks();

/*
** Find the top of the page and redraw it.
*/

while (y2 != ed_miny)
{
nl = nl->prev;
y2--;
}
RedrawPage(nl, ed_miny);
}


/*
**
** Lays a block anchor at the current position.
**
*/

static void anchor(void)
{
LINE *nl = current;
int y2 = y;

/*
** Calculate the new block configuration.
*/

CalculateBlocks();

/*
** Find the top of the page and redraw it.
*/

while (y2 != ed_miny)
{
nl = nl->prev;
y2--;
}
RedrawPage(nl, ed_miny);
}


/*
**
** Cuts the current block from the message and saves it.
**
*/

static void cut(void)
{
LINE *nl, *begin, *end;
int y1;

if (!blocking)
return;

UnmarkLineBuf();

if (clip != NULL)
{
/*
** Discard whatever was in there before.
*/

clip = clearbuffer(clip);
}

nl = msgtop;
begin = NULL;
end = NULL;

/*
** Find the begin and end of the block.
*/

while (nl)
{
/*
** If we haven't hit a block yet, then this must be it.
*/

if (nl->block && !begin)
begin = nl;

/*
** If we've hit a block & come out the other side, break.
*/

if (begin && !nl->block && !end)
{
end = nl;
break;
}

nl = nl->next;
}

/*
** Shit, could get messy here... ๐Ÿ™
*/

/* y = 1; */

if (!begin->prev)
{
if (!end)
{
/*
** Whole message has been selected - create a line
** to put the cursor on.
*/

if ((nl = calloc(1, sizeof(LINE))) == NULL)
{
/*
** If we run out of memory here we may as well die.
*/

outamemory();
}
nl->text = strdup("\n");
msgtop = nl;
current = nl;
}
else
{
/*
** There is some message left.
*/

msgtop = end;
current = end;
if (end->prev)
end->prev->next = NULL;

end->prev = NULL;
}
}
else
{
/*
** Join up the gap where the cut will be.
*/

if (end)
{
begin->prev->next = end;
end->prev->next = NULL;
end->prev = begin->prev;
}
else
begin->prev->next = NULL;

current = begin->prev;
begin->prev = NULL;
}

/*
** Save the cut text and redraw the page.
*/

blocking = 0;
clip = begin;

/*
** Find beginning of screen & corresponding line.
*/

y1 = y;
nl = current;
while (y1 > ed_miny && nl->prev != NULL)
{
nl = nl->prev;
y1--;
}

/*
** Handle case where lines have to be moved up on screen.
*/

if (y1 != ed_miny)
{
y -= (y1 - ed_miny);
}

RedrawPage(nl, 1);
CheckXvalid();
}


/*
**
** Pastes the block on the clipboard into the page at the
** current cursor position.
**
*/

static void paste(void)
{
LINE *nl = current;
LINE *t = clip;
LINE *t1;

if (t == NULL)
return;

/*
** If a block was there, kill it.
*/

ClearBlocks();

/*
** Copy from the clipboard to AFTER the current position.
*/

while (t != NULL)
{
t1 = InsertLine(nl);
t1->quote = t->quote;
t1->text = strdup(t->text);
nl = t1;
t = t->next;
}

#if 0
// clip->prev = current;
// current->next = clip;
//
// /*
// ** Find the last line of clipboard.
// */
//
// while (clip->next != NULL)
// {
// clip = clip->next;
// }
//
// /*
// ** Assign it.
// */
//
// clip->next = nl;
// if (nl)
// nl->prev = clip;
//
// clip = NULL;
#endif

/*
** Redraw the page.
*/

RedrawPage(current, y);
}


static void tabit(void)
{
if (!(x % SW->tabsize))
insert_char((char) ' ');

while (x % SW->tabsize)
insert_char((char) ' ');

insert_char((char) ' ');
}


static void go_tos(void)
{
UnmarkLineBuf();
while (y > ed_miny && current->prev != NULL)
{
current = current->prev;
y--;
}
CheckXvalid();
}


static void go_bos(void)
{
UnmarkLineBuf();
while (y < ed_maxy && current->next != NULL)
{
current = current->next;
y++;
}
CheckXvalid();
}


static void go_tom()
{
if (current == msgtop)
return;

UnmarkLineBuf();

current = msgtop;
y = 1;

CheckXvalid();
RedrawPage(current, y);
}


static void go_bom(void)
{
if (current->next == NULL)
return;

UnmarkLineBuf();
while (current->next)
current = current->next;


y = 1;

CheckXvalid();
RedrawPage(current, y);
}


static void killeol(void)
{
memset(line_buf + x - 1, 0, strlen(line_buf + x - 1));
UnmarkLineBuf();
EdPutLine(current, y);
}


static void imptxt(void)
{
UnmarkLineBuf();
import(current);
RedrawPage(current, y);
SetLineBuf();
}

static void ExportBlock(void)
{
LINE *l, *nl;

if (!blocking)
return;

l = msgtop;
while (l->next && !l->block)
{
l = l->next;
}

if (!l->block)
return;

nl = l;
while (nl->next && nl->block)
{
nl = nl->next;
}
if (!nl->block)
{
if (nl->prev)
nl->prev->next = NULL;
}
export(l);
if (!nl->block)
{
if (nl->prev)
nl->prev->next = nl;
}
}


static void outtext(void)
{
char title[] = " Export ";
char msgtxt[] = "Export what?";
int res;

if (clip && blocking == 0)
{
res = ChoiceBox(title, msgtxt, "Clipbrd", "Message", NULL);
cursor(1);
switch (res)
{
case ID_ONE:
export(clip);
break;
case ID_TWO:
export(msgtop);
default:
break;
}
return;
}
else if (clip == NULL && blocking)
{
res = ChoiceBox(title, msgtxt, "Block", "Message", NULL);
cursor(1);
switch (res)
{
case ID_ONE:
ExportBlock();
break;
case ID_TWO:
export(msgtop);
default:
break;
}
return;
}
else if (clip && blocking)
{
res = ChoiceBox(title, msgtxt, "Clipbrd", "Block", "Message");
cursor(1);
switch (res)
{
case ID_ONE:
export(clip);
break;
case ID_TWO:
ExportBlock();
break;
case ID_THREE:
export(msgtop);
break;
default:
break;
}
return;
}
export(msgtop);
cursor(1);
}


static void quit(void)
{
release(current->text);

if ((current->text = strdup(line_buf)) == NULL)
WWriteStr(0, 0, cm[CM_WTXT], "Cronic Memory Shortage! Attempting to save...");

done = SAVE;
}


static void die(void)
{
if (confirm())
done = ABORT;

cursor(1);
}


static void bytecount(void)
{
LINE *ff = msgtop;
long count = 0;
char text[40];

while (ff)
{
if (ff->text)
count += strlen(ff->text);

ff = ff->next;
}
sprintf(text, "Message size is %ld bytes", count);
ChoiceBox(" Message Size ", text, "Ok", NULL, NULL);
cursor(1);
}


static void toggle_ins(void)
{
insert = !insert;
if (insert)
{
WWriteStr(maxx - 5, 5, cm[CM_DTXT], "ins");
}
else
{
WWriteStr(maxx - 5, 5, cm[CM_DTXT], "ร„ร„ร„");
}
}


static void shellos(void)
{
LINE *curr;
int y2;
char tmp[PATHLEN];

mygetcwd(tmp, PATHLEN);
setcwd(ST->home);

cursor(TRUE);
WClose(hMnScr);
KillHotSpots();
TTgotoxy(term.NRow - 1, 0);
TTclose();

fputs("Type EXIT to return to Msgedsq.",stderr);
shell_to_dos();

/*
** Redraw the screen.
*/

InitScreen();
BuildHotSpots();
DrawHeader();
ShowNewArea();
ShowMsgHeader(messg);

/*
** Redraw the text.
*/

y2 = y;
curr = current;
while (y2 > ed_miny && curr->prev)
{
curr = curr->prev;
y2--;
}
RedrawPage(curr, y2);
setcwd(tmp);
cursor(1);
}


static void doscmd(void)
{
WND *hCurr, *hWnd;
char tmp[PATHLEN];
char cmd[64];
int ret;

mygetcwd(tmp,PATHLEN);
memset(cmd,0,sizeof cmd);

if (!GetString(" Dos Command ", "Enter DOS command to execute:", cmd, 64))
return;

hCurr = Wtop();
if ((hWnd = WndOpen(0, 0, maxx-1, maxy-1, NBDR, 0, cm[CM_NTXT])) == NULL)
return;

ret = system(cmd);

sprintf(tmp, "DOS command returned %d", ret);
ChoiceBox(" Info ", tmp, "Ok", NULL, NULL);

WClose(hWnd);
WCurr(hCurr);
setcwd(tmp);
cursor(1);
}


/*
**
** Lets the user edit the header.
**
*/

static void editheader(void)
{
msg *save;
int q;

q = 0;
save = duplicatemsg(messg);
while (!q)
{
if (EditHeader(save) == Key_Esc)
{
if (confirm())
{
dispose(save);
cursor(1);
return;
}
}
else
q = 1;
}

/*
** We want to save the changes: release all allocated memory
** and make *messg = *save..
*/

release(messg->isfrom);
release(messg->isto);
release(messg->subj);
release(messg->msgid);
release(messg->reply);
release(messg->to.domain);
release(messg->from.domain);

*messg = *save;

cursor(1);
}


/*
**
** Calls the setup dialog box & allows user to play with switches.
**
*/

static void setup(void)
{
LINE *nl = current;
int y2 = y;

set_switch();
while (y2 != ed_miny && nl->prev != NULL)
{
nl = nl->prev;
y2--;
}
RedrawPage(nl, ed_miny);
cursor(1);
}

static void do_help(void)
{
if (ST->helpfile)
DoHelp(1);
}


static void UpdateMem(void)
{
#if defined(MSDOS)
long mem;
long oldmem = 0;
char line[15];

mem = corerem();
if (mem != oldmem)
{
oldmem = mem;
sprintf(line, " %ld ", mem);
WWriteStr(67, 5, cm[CM_DTXT], line);
}
#endif
}


int editmsg(msg *m, int quote)
{
EVT event;
int editcrstate;
unsigned int ch;

x = 1;
y = 1;
edminy = 5;
edmaxy = maxy;
ed_miny = 1;
ed_maxy = edmaxy - edminy - 1;
messg = m;
current = messg->text;
msgtop = messg->text;

if (insert)
WWriteStr(maxx - 5, 5, cm[CM_DTXT], "ins");

if (msgtop == NULL)
{
if ((current = msgtop = calloc(1, sizeof(LINE))) == NULL)
{
WWriteStr(0, 0, cm[CM_WTXT], "Cronic Memory Shortage! Aborting...");
return ABORT;
}
msgtop->text = strdup("\n");
msgtop->prev = NULL;
}

if (SW->editcronly)
{
editcrstate = SW->showcr;
SW->showcr = 1;
}

SetLineBuf();
RedrawPage(current, y);

done = FALSE;
cursor(1);
GotoXY(x, y);

while (!done)
{
UpdateMem();
GotoXY(x, y);
ch = MnuGetMsg(&event, hMnScr->wid);
switch (event.msgtype)
{
case WM_CHAR:
if (ch & 0xff)
{
if (editckeys[(ch & 0xff)] == NULL)
{
insert_char((char) DOROT13((char) (ch & 0xff)));
}
else
editckeys[(ch & 0xff)]();
}
else if (editakeys[(ch >> 8)] != NULL)
editakeys[(ch >> 8)]();
break;

default:
break;
}
}

messg->text = msgtop;

if (SW->chopquote && quote)
{
LINE *ff, *lowest;

ff = lowest = msgtop;

/* find the lowest line of text that *isn't* */
/* a template line */

while (ff->next)
{
if (!ff->quote && strlen(ff->text) != 0 && *(ff->text) != '\n' && !ff->templt)
lowest = ff;

ff = ff->next;
}

if (lowest && lowest != msgtop && lowest->next)
{
ff = lowest;

/* ok, we got a lowest line, now we find the template */
/* line that is next underneath it */

while (ff)
{
if (ff->templt)
break;

ff = ff->next;
}

if (ff == NULL) /* didn't find one */
lowest->next = clearbuffer(lowest->next);
else
{
LINE *d;

/* we found one, so delete all lines of text */
/* between the lowest and the template line */

ff = lowest->next;

while (!ff->templt)
{
d = ff;
ff = ff->next;

if (d->prev)
d->prev->next = ff;

if (d->next)
d->next->prev = d->prev;

release(d->text);
free(d);
}
}
}
}

/*
**
** Clean up everything.
**
*/

if (insert)
WWriteStr(maxx - 5, 5, cm[CM_DTXT], "ร„ร„ร„");

if (SW->editcronly)
{
SW->showcr = editcrstate;
}

blocking = 0;
cursor(0);
return done;
}

int ed_error(char *fc, char *fmt, ...)
{
va_list params;
char line[255];

va_start(params, fmt);
vsprintf(line, fmt, params);
fprintf(stderr, "\nError! function %s: %s", fc, line);
exit(-1);
return (0);
}


/* end of file */


  3 Responses to “Category : Recently Uploaded Files
Archive   : MSQ320.ZIP
Filename : WRAP.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! ๐Ÿ˜€ I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/