/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * Ack 2.2 improvements copyright (C) 1994 by Stephen Dooley * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * _/ _/_/_/ _/ _/ _/ ACK! MUD is modified * * _/_/ _/ _/ _/ _/ Merc2.0/2.1/2.2 code * * _/ _/ _/ _/_/ _/ (c)Stephen Zepp 1998 * * _/_/_/_/ _/ _/ _/ Version #: 4.3 * * _/ _/ _/_/_/ _/ _/ _/ * * * * http://ackmud.nuc.net/ * * zenithar@ackmud.nuc.net * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "globals.h" /* This file deals with multi-line editing, and writing. */ typedef void RET_FUN( void *, char **, CHAR_DATA *, bool ); struct buf_data_struct { bool is_free; /* Ramias:for run-time checks of LINK/UNLINK */ BUF_DATA_STRUCT *next; BUF_DATA_STRUCT *prev; CHAR_DATA *ch; char **dest; char *buf; int pos; RET_FUN *returnfunc; void *returnparm; int old_char_pos; }; extern char str_empty[1]; /* A str function in build.c, used to duplicate strings into perm. mem. */ char *build_simpstrdup( char * ); void write_start( char **dest, void *retfunc, void *retparm, CHAR_DATA * ch ) { BUF_DATA_STRUCT *buf_data; char *buf; /* * Check that *dest != &str_empty[0] when calling this func. */ /* * If it is, it's because we've run out of memory. */ buf = getmem( MAX_STRING_LENGTH ); if( buf == NULL ) { bug( "Not enough memory for string editing.", 0 ); *dest = &str_empty[0]; send_to_char( "WARNING: No memory left. Things will start to go wrong.\n\r", ch ); return; } /* * Alloc mem. for a new buffer. */ GET_FREE( buf_data, buf_free ); LINK( buf_data, first_buf, last_buf, next, prev ); buf_data->ch = ch; buf_data->dest = dest; buf_data->buf = buf; buf_data->pos = 0; buf_data->returnfunc = retfunc; buf_data->returnparm = retparm; *buf = '\0'; buf_data->old_char_pos = ch->position; ch->position = POS_WRITING; *dest = buf; return; } void write_interpret args( ( CHAR_DATA * ch, char *argument ) ) { BUF_DATA_STRUCT *buf_data; char *buf; int curlen; for( buf_data = first_buf; buf_data != NULL; buf_data = buf_data->next ) { if( buf_data->ch == ch ) break; } if( buf_data == NULL ) { bugf( "Call to write_interpret when not writing (char=%s)\n\r", ch->name ); ch->position = POS_STANDING; return; } buf = buf_data->buf; /* * Check to see if text was a command or simply addition */ if( argument[0] != '.' ) { curlen = strlen( buf ); if( curlen > MAX_STRING_LENGTH - 240 ) { send_to_char( "String to long, cannot add new line.\n\r", ch ); return; } for( buf = buf + curlen; *argument != '\0'; ) *( buf++ ) = *( argument++ ); *( buf++ ) = '\n'; *( buf++ ) = '\r'; *buf = '\0'; return; } /* * We have a command. */ /* * Commands are .help .save .preview .- .clear .lines */ argument++; if( argument[0] == '\0' || UPPER( argument[0] == 'S' || UPPER( argument[0] ) == 'Q' ) ) { bool save; char **dest; CHAR_DATA *ch; if( UPPER( argument[0] ) == 'Q' ) save = 0; else save = 1; dest = buf_data->dest; ch = buf_data->ch; /* * Save routine. */ if( save ) { /* * Check that dest still points to buf (to check for corruption) */ if( *dest != buf ) { bug( "write_interpret: Original destination has been overwritten.", 0 ); send_to_char( "Cannot save, string pointer been modified.\n\r", ch ); } else { *dest = str_dup( buf ); if( ( buf_data->returnfunc ) != NULL ) ( *buf_data->returnfunc ) ( buf_data->returnparm, dest, ch, TRUE ); } } else { *dest = &str_empty[0]; if( ( buf_data->returnfunc ) != NULL ) ( *buf_data->returnfunc ) ( buf_data->returnparm, dest, ch, FALSE ); } /* * Re-use memory. */ dispose( buf_data->buf, MAX_STRING_LENGTH ); UNLINK( buf_data, first_buf, last_buf, next, prev ); /* * Re-set char */ ch->position = buf_data->old_char_pos; PUT_FREE( buf_data, buf_free ); return; } if( UPPER( argument[0] ) == 'H' ) { /* * Help */ CHAR_DATA *ch; ch = buf_data->ch; send_to_char( "Normal type will be appended to the string, line by line.\n\r", ch ); send_to_char( ".help or .h : displays this help.\n\r", ch ); send_to_char( ".save or . : saves and exits the editor.\n\r", ch ); send_to_char( ".preview or .p : display a preview of the text.\n\r", ch ); send_to_char( ".-[num] or .- : deletes [num] lines from the end, or just one line\n\r", ch ); send_to_char( ".clear : deletes whole text.\n\r", ch ); send_to_char( ".quit or .q : quits without saving.\n\r", ch ); send_to_char( ".format or .f : formats text for 80 chars.\n\r", ch ); send_to_char( ".replace or .r : replaces word with string.\n\r", ch ); send_to_char( " (usage) : .r <word> <string>. If no string, arg1 deleted.\n\r", ch ); return; } if( UPPER( argument[0] ) == 'R' ) { /* * Mag: I bet you take one look at this, and change it :) -S- */ char arg1[MAX_STRING_LENGTH]; char arg2[MAX_STRING_LENGTH]; char word[MAX_STRING_LENGTH]; char new_buf[MAX_STRING_LENGTH]; char pBuf; int pos; int npos; int wpos; int buf_length; int foo; int i; char *src; argument = one_argument( argument + 1, arg1 ); /* Skip the R */ strcpy( arg2, argument ); if( arg1[0] == '\0' ) { send_to_char( "No arg1 supplied for replace command.\n\r", ch ); return; } new_buf[0] = '\0'; buf_length = strlen( buf ); pos = 0; npos = 0; wpos = 0; word[0] = '\0'; for( ;; ) { pBuf = buf[pos]; if( pBuf == '\0' || pos > buf_length ) break; if( pBuf == ' ' ) { new_buf[npos] = ' '; pos++; npos++; continue; } if( !isgraph( pBuf ) ) { new_buf[npos] = pBuf; pos++; npos++; continue; } wpos = 0; for( ;; ) { if( !isgraph( pBuf ) ) break; word[wpos] = pBuf; pos++; wpos++; pBuf = buf[pos]; } word[wpos] = '\0'; if( !str_cmp( word, arg1 ) ) { if( arg2[0] != '\0' ) for( foo = 0; arg2[foo] != '\0'; foo++ ) { new_buf[npos] = arg2[foo]; npos++; } else { /* * Do nothing (much). */ if( npos > 0 ) npos--; send_to_char( "Arg1 deleted.\n\r", ch ); } } else { for( foo = 0; word[foo] != '\0'; foo++ ) { new_buf[npos] = word[foo]; npos++; } } } /* * -gulp- Copy new_buf into message structure... */ src = buf; for( i = 0; i < npos; i++ ) *( src++ ) = new_buf[i]; *( src ) = '\0'; return; } if( UPPER( argument[0] ) == 'P' ) { send_to_char( buf, ch ); return; } if( argument[0] == '-' ) { int num; int a; argument++; if( argument[0] == '\0' ) num = 2; else num = atoi( argument ) + 1; if( num <= 0 ) return; for( a = strlen( buf ); a >= 0; a-- ) { if( buf[a] == '\n' ) { num--; if( num == 0 ) break; } } if( a == 0 ) { send_to_char( "Tried to delete too many lines.\n\r", buf_data->ch ); return; } a++; if( buf[a] == '\r' ) a++; send_to_char( "Deleted:\n\r", buf_data->ch ); send_to_char( buf + a, buf_data->ch ); buf[a] = '\0'; return; } if( argument[0] == 'f' ) { char *src; char dest[MAX_STRING_LENGTH]; int col; char *srcspc; int destspc; char c; int n, i; int lastcol; /* * Format text */ /* * Go through line by line, doing word wrapping */ lastcol = 79; col = 0; n = 0; srcspc = NULL; destspc = 0; for( src = buf; *src != '\0'; ) { c = *( src++ ); switch ( c ) { case '\n': /* Convert /n/r into one space */ if( ( *src == '\r' ) && ( *( src + 1 ) == '\n' ) && ( *( src + 2 ) == '\r' ) ) { /* * Do not convert paragraph endings. */ dest[n++] = c; /* \n */ dest[n++] = *( src++ ); /* \r */ dest[n++] = *( src++ ); /* \n */ dest[n++] = *( src++ ); /* \r */ col = 0; srcspc = NULL; destspc = 0; break; } /* * Also if there is a space on the next line, don't merge. */ if( ( *src == '\r' ) && ( *( src + 1 ) == ' ' ) ) { dest[n++] = c; /* \n */ dest[n++] = *( src++ ); /* \r */ col = 0; srcspc = NULL; destspc = 0; break; } /* * Otherwise convert to a space */ /* * Get rid of spaces at end of a line. */ if( n > 0 ) { while( dest[--n] == ' ' ); n++; } dest[n++] = ' '; col++; srcspc = src - 1; destspc = n - 1; break; case '\r': break; case '\t': /* Tab */ col += 7; case '.': /* Punctuation */ case ' ': case ',': case ';': case '?': case '!': case ')': srcspc = src - 1; destspc = n - 1; case '-': if( srcspc == NULL ) { srcspc = src - 1; /* Only use a dash if necessary */ destspc = n - 1; } default: dest[n++] = c; col++; break; } if( col >= lastcol ) { /* * Need to do a line break */ if( srcspc == NULL ) { /* * there were no breakable characters on the line. */ dest[n++] = '\n'; dest[n++] = '\r'; } else { n = destspc; /* n now points to a breakable char. */ src = srcspc; while( dest[n] == ' ' || dest[n] == '\n' ) { n--; } src++; n++; if( *src == '\r' ) src++; while( *src == ' ' ) src++; /* * src now points to the new line to be put in dest. */ dest[n++] = '\n'; dest[n++] = '\r'; col = 0; srcspc = NULL; destspc = 0; } } } /* * Get rid of spaces at end, and add a newline. */ while( dest[--n] == ' ' ); n++; dest[n++] = '\n'; dest[n++] = '\r'; /* * Copy from dest back into buffer */ src = buf; for( i = 0; i < n; i++ ) *( src++ ) = dest[i]; *( src ) = '\0'; return; } if( !str_cmp( argument, "clear" ) ) { buf[0] = '\0'; send_to_char( "Done.\n\r", buf_data->ch ); return; } send_to_char( "Command not known, type .help for help.\n\r", buf_data->ch ); return; }