#include <core> #include <string> #include <admin> #include <adminlib> #include <console> ReadLine (file[], lineNo, buffer[], maxlen); CopyToken (source[], start, token[], maxlen); #define DEFAULT_ACCESS ACCESS_SAY #define DEFAULT_WRITE_ACCESS ACCESS_SAY #define DONE -1 #define SPACE 32 #define MAX_COLUMN 60 #define MAX_EXEC_LEN 92 #define MAX_UNSAVED_WORDS 32 #define MAX_OUT_LINES 20 #define MAX_SOUNDS 256 #define MAX_SOUND_LEN 128 #define MAX_TOKEN_LEN 16 #define MAX_WORD_LEN 24 new OPTION_ADD_SOUND[] = "-addsound"; new OPTION_ADD_WORD[] = "-addword"; new OPTION_FLUSH[] = "-flush"; new OPTION_HELP[] = "-help"; new OPTION_MATCH[] = "-match"; new OPTION_RELOAD[] = "-reload"; new OPTION_SAVE_SOUNDS[] = "-savesounds"; new OPTION_SAVE_WORDS[] = "-savewords"; new OPTION_SOUNDS[] = "-sounds"; new OPTION_SET_SOUND[] = "-trysound"; new OPTION_SET_WORD[] = "-tryword"; new OPTION_UNSAVED[] = "-unsaved"; new OPTION_WORDS[] = "-words"; new OPTION_VOX[] = "-vox"; new LINES_FILE[] = "yak_lines.txt"; new MY_NAME[] = "admin_yak"; new SOUNDS_FILE[] = "yak_sounds.txt"; new WORDS_FILE[] = "yak_words.txt"; new VERSION[] = "0.2"; new VOX_WORDS_FILE[] = "vox_words.txt"; new YAK_ACCESS_VAR[] = "yak_access_level"; new YAK_WRITE_ACCESS_VAR[] = "yak_write_access_level"; new NumSounds; new SavedSounds[MAX_SOUNDS]; // 1=sound is in file, 0=not new Sounds[MAX_SOUNDS][MAX_SOUND_LEN]; // vox sounds new Tokens[MAX_SOUNDS][MAX_TOKEN_LEN]; // sound keys new UnsavedWords[MAX_UNSAVED_WORDS][MAX_WORD_LEN]; // word keys new UnsavedSounds[MAX_UNSAVED_WORDS][MAX_SOUND_LEN]; // sounds for words public plugin_init() { new i; i = getvar (YAK_ACCESS_VAR); if (i == 0) i = DEFAULT_ACCESS; plugin_registerinfo("Yak tester", "Speak & Spell for HL!.", VERSION); plugin_registercmd (MY_NAME, "HandleYak", i); plugin_registerhelp(MY_NAME, i, "admin_yak <text>: Speak & Spell for HL! (admin_yak -help for details."); ReadSounds(); for (i = 0; i < MAX_UNSAVED_WORDS; i++) { strinit (UnsavedWords[i]); strinit (UnsavedSounds[i]); } return PLUGIN_CONTINUE; } public HandleYak (HLCommand, HLData, HLUser,UserIndex) { new canWrite; new Data[MAX_DATA_LENGTH]; new command[MAX_DATA_LENGTH]; new i; convert_string(HLData, Data, MAX_DATA_LENGTH); i = SkipWS(Data); if (i == DONE) strcpy (command, OPTION_HELP, MAX_TEXT_LENGTH); else strcpy (command, Data[i], MAX_DATA_LENGTH); if (strncmp (command, "-", 1) == 0) { canWrite = 0; i = getvar(YAK_WRITE_ACCESS_VAR); if (i == 0) i = DEFAULT_WRITE_ACCESS; if (check_auth(i) != 0) { canWrite = 1; } if (canWrite && strcmp (command, OPTION_RELOAD) == 0) { selfmessage ("Reloading sounds file..."); NumSounds = 0; ReadSounds(); selfprintf ("Read %i sounds from %s", NumSounds, SOUNDS_FILE); return PLUGIN_HANDLED; } if (strcmp (command, OPTION_HELP) == 0) { selfprintf ("admin_yak must-know commands:"); selfprintf ("admin_yak <words> : speaks <words>"); selfprintf ("admin_yak %s : display this message", OPTION_HELP); selfprintf ("admin_yak %s <str> : displays any words matching <str>", OPTION_MATCH); if (canWrite) { selfmessage (""); selfprintf ("admin_yak commands for trying and adding new sounds & words:"); selfprintf ("admin_yak %s <sound> [<vox>] : tests a key/vox combination", OPTION_SET_SOUND); selfprintf ("admin_yak %s <sound> <vox> : adds a new sound to the sounds file", OPTION_ADD_SOUND); selfprintf ("admin_yak %s <word> [<sounds>] : tests a key/sound combination", OPTION_SET_WORD); selfprintf ("admin_yak %s <word> <sounds> : adds a new sound to the sounds file", OPTION_ADD_WORD); selfprintf ("admin_yak %s : saves all sounds that have been tried but not added", OPTION_SAVE_SOUNDS); selfprintf ("admin_yak %s : saves all words that have been tried but not added", OPTION_SAVE_WORDS); selfprintf ("admin_yak %s : deletes all unsaved sounds and unsaved words", OPTION_FLUSH); selfprintf ("admin_yak %s : reloads sounds file", OPTION_RELOAD); selfprintf ("admin_yak %s : dumps unsaved sound and words", OPTION_UNSAVED); if (getvar("file_access_write") == 0) { selfprintf ("Write commands are disabled! Use %s and 'condump' instead", OPTION_UNSAVED); } } selfmessage (""); selfprintf ("admin_yak commands that aren't very interesting:"); if (canWrite == 0) { selfprintf ("admin_yak %s : dumps unsaved sound and words", OPTION_UNSAVED); } selfprintf ("admin_yak %s <str> : displays all sound keys that contain <str>", OPTION_SOUNDS); selfprintf ("admin_yak %s <line> : displays known words starting at line <line>", OPTION_WORDS); selfprintf ("admin_yak %s <line> : displays built-in VOX words starting at line <line>", OPTION_VOX); return PLUGIN_HANDLED; } if (strncmp (command, OPTION_WORDS, strlen(OPTION_WORDS)) == 0) { ListWords (command[strlen(OPTION_WORDS) + 1]); return PLUGIN_HANDLED; } if (strncmp (command, OPTION_MATCH, strlen(OPTION_MATCH)) == 0) { MatchWords (command[strlen(OPTION_MATCH) + 1]); return PLUGIN_HANDLED; } if (strncmp (command, OPTION_SOUNDS, strlen (OPTION_SOUNDS)) == 0) { ListSounds (command[strlen(OPTION_SOUNDS) + 1]); return PLUGIN_HANDLED; } if (strncmp (command, OPTION_UNSAVED, strlen (OPTION_UNSAVED)) == 0) { DumpUnsaved(); return PLUGIN_HANDLED; } if (strncmp (command, OPTION_VOX, strlen (OPTION_VOX)) == 0) { ListVox (command[strlen(OPTION_VOX) + 1]); return PLUGIN_HANDLED; } if (canWrite) { if (strncmp (command, OPTION_SET_SOUND, strlen (OPTION_SET_SOUND)) == 0) { SetSound (command[strlen(OPTION_SET_SOUND) + 1], OPTION_SET_SOUND, 0, HLUser); return PLUGIN_HANDLED; } if (strncmp (command, OPTION_ADD_SOUND, strlen (OPTION_ADD_SOUND)) == 0) { WriteSound (command[strlen(OPTION_ADD_SOUND) + 1], HLUser); return PLUGIN_HANDLED; } if (strncmp (command, OPTION_SET_WORD, strlen (OPTION_SET_WORD)) == 0) { SetWord (command[strlen(OPTION_SET_WORD) + 1], HLUser); return PLUGIN_HANDLED; } if (strncmp (command, OPTION_ADD_WORD, strlen (OPTION_ADD_WORD)) == 0) { WriteWord (command[strlen(OPTION_ADD_WORD) + 1], HLUser); return PLUGIN_HANDLED; } if (strncmp (command, OPTION_SAVE_WORDS, strlen (OPTION_SAVE_WORDS)) == 0) { SaveWords(); return PLUGIN_HANDLED; } if (strncmp (command, OPTION_SAVE_SOUNDS, strlen (OPTION_SAVE_SOUNDS)) == 0) { SaveSounds(); return PLUGIN_HANDLED; } if (strncmp (command, OPTION_FLUSH, strlen (OPTION_FLUSH)) == 0) { FlushUnsaved(); return PLUGIN_HANDLED; } } } StartYakking (command); return PLUGIN_HANDLED; } public YakTimer (Timer, Repeat, HLName, HLParam) { new Data[MAX_DATA_LENGTH]; convert_string(HLParam, Data, MAX_DATA_LENGTH); StartYakking (Data); return PLUGIN_HANDLED; } StartYakking (command[]) { new i; new len; new previ; new final[MAX_TEXT_LENGTH]; new word[MAX_WORD_LEN]; new words[MAX_TEXT_LENGTH]; strinit (words); strinit (final); if (strncmp (command, "!", 1) == 0) { // asked to say a sentance.. new count; new tmp[MAX_TEXT_LENGTH]; len = strlen(command); for (count = ReadLine (LINES_FILE, 0, tmp, MAX_TEXT_LENGTH); count != DONE; count = ReadLine (LINES_FILE, count, tmp, MAX_TEXT_LENGTH)) { if (strncmp (tmp, command, len) != 0) continue; i = SkipWS (tmp, len); if (i == DONE) { selfprintf ("Bogus format on line %i of %s", count, LINES_FILE); return; } strcpy (words, tmp[len], MAX_TEXT_LENGTH); break; } if (strlen(words) == 0) strcpy (words, command, MAX_TEXT_LENGTH); } else { strcpy (words, command, MAX_TEXT_LENGTH); } previ = 0; len = 0; // for each word we've been asked to say... for (i = CopyToken (words, 0, word, MAX_WORD_LEN); i != DONE; i = CopyToken (words, i, word, MAX_WORD_LEN)) { new output[MAX_TEXT_LENGTH]; strinit (output); AddWordToStr (word, output, MAX_TEXT_LENGTH); len += strlen(output); if (len > MAX_EXEC_LEN) { selfprintf ("Setting timer at %i", previ); if (previ == 0) { selfprintf ("Sounds too long for '%s'!!", word); return; } set_timer ("YakTimer", 2, 1, words[previ]); break; } strcat (final, output, MAX_EXEC_LEN); previ = i; } SpeakAll (final); } AddWordToStr (word[], output[], maxlen) { new i; new len; new line[MAX_TEXT_LENGTH]; new lineNo; len = strlen (word); if (len == 0) return; for (i = 0; i < MAX_UNSAVED_WORDS; i++) { if (strlen(UnsavedWords[i]) == 0) continue; if (strcmp(UnsavedWords[i], word) == 0) { selfprintf ("Unsaved word: %s", word); AddSoundsToStr (UnsavedSounds[i], output, maxlen); return; } } for (lineNo = ReadLine (WORDS_FILE, 0, line, MAX_TEXT_LENGTH); lineNo != DONE; lineNo = ReadLine (WORDS_FILE, lineNo, line, MAX_TEXT_LENGTH)) { new token[MAX_WORD_LEN]; if (CopyToken (line, 0, token, MAX_WORD_LEN) == DONE) continue; if (strcmp (token, word) != 0) { continue; } i = SkipWS(line, len); if (i == DONE) { selfprintf ("Malformed syntax for '%s' in %s, line %i", word, WORDS_FILE, lineNo); return; } AddSoundsToStr (line[i], output, maxlen); return; } if (strlen(output) > 0) strcat (output, " ", maxlen); strcat (output, word, maxlen); strcat (output, " ", maxlen); } AddSoundsToStr (source[], output[], maxlen) { new i; new t[MAX_TOKEN_LEN]; if (strlen (source) == 0) return; for (i = CopyToken (source, 0, t, MAX_TOKEN_LEN); i != DONE; i = CopyToken (source, i, t, MAX_TOKEN_LEN)) { new found; new s; if (strlen (t) == 0) continue; found = 0; for (s = 0; s < NumSounds; s++) { if (strcmp (Tokens[s], t) != 0) continue; found = 1; strcat (output, Sounds[s], maxlen); strcat (output, " ", maxlen); break; } if (found == 0) { strcat (output, t, maxlen); strcat (output, " ", maxlen); } } } ReadSounds() { new i; new token[MAX_TEXT_LENGTH]; new lineNo; new line[MAX_TEXT_LENGTH]; for (i = 0; i < MAX_SOUNDS; i++) { strinit (Sounds[i]); strinit (Tokens[i]); SavedSounds[i] = 0; } NumSounds = 0; for (lineNo = ReadLine (SOUNDS_FILE, 0, line, MAX_TEXT_LENGTH); lineNo != DONE && NumSounds < MAX_SOUNDS; lineNo = ReadLine (SOUNDS_FILE, lineNo, line, MAX_TEXT_LENGTH)) { i = CopyToken (line, 0, token, MAX_TEXT_LENGTH); if (i == DONE) continue; // strip whitespace between token and sound i = SkipWS (line, i); if (i == DONE) { selfprintf ("Bogus syntax on line %i of %s", lineNo, SOUNDS_FILE); continue; } AddSound (token, line[i], 1); } } AddSound (key[], vox[], saved) { new i; for (i = 0; i < MAX_SOUNDS; i++) { if (strlen(Tokens[i]) == 0) { strcpy (Tokens[i], key, MAX_TOKEN_LEN); strcpy (Sounds[i], vox, MAX_SOUND_LEN); SavedSounds[i] = saved; NumSounds++; return; } if (strcmp (Tokens[i], key) == 0) { selfprintf ("Duplicate sound '%s' found", key); strcpy (Tokens[i], key, MAX_TOKEN_LEN); strcpy (Sounds[i], vox, MAX_SOUND_LEN); SavedSounds[i] = saved; return; } } selfmessage ("Too many sounds!"); } Speak (words[], HLUser) { new output[MAX_TEXT_LENGTH + 10]; new user[MAX_NAME_LENGTH]; convert_string(HLUser, user, MAX_NAME_LENGTH); snprintf (output, MAX_TEXT_LENGTH, "speak ^"%s^"", words); execclient (user, output); } SpeakAll (words[]) { new output[MAX_TEXT_LENGTH + 10]; snprintf (output, MAX_TEXT_LENGTH, "speak ^"%s^"", words); execclient_all (output); } SetSound (command[], name[], saved, HLUser) { new i; new needUsage; new token[MAX_TEXT_LENGTH]; needUsage = 0; if (strlen (command) > 0) { i = CopyToken (command, 0, token, MAX_TEXT_LENGTH); if (i != DONE) { i = SkipWS (command, i); if (i != DONE) { AddSound (token, command[i], saved); Speak (command[i], HLUser); } else { for (i = 0; i < NumSounds; i++) { if (strcmp (Tokens[i], command) != 0) continue; Speak (Sounds[i], HLUser); return 1; } selfmessage ("Sound not found!"); needUsage = 1; } } else needUsage = 1; } else needUsage = 1; if (needUsage) { selfprintf ("Usage: %s %s <key> <sounds>", MY_NAME, name); return 1; } return 0; } WriteSound (command[], HLUser) { if (SetSound(command, OPTION_ADD_SOUND, 1, HLUser) != 0) return; writefile (SOUNDS_FILE, command); } SetWord (command[], HLUser) { new i; new j; new output[MAX_TEXT_LENGTH]; new word[MAX_TEXT_LENGTH]; i = CopyToken (command, 0, word, MAX_TEXT_LENGTH); if (i == DONE) { selfprintf ("%s %s <word> [<sounds>]", MY_NAME, OPTION_SET_WORD); return; } i = SkipWS (command, i); if (i == DONE) { // if they just gave the word without sounds, try to speak that word AddWordToStr (word, output, MAX_TEXT_LENGTH); Speak (output, HLUser); return; } AddSoundsToStr (command[i], output, MAX_TEXT_LENGTH); Speak (output, HLUser); for (j = 0; j < MAX_UNSAVED_WORDS; j++) { if (strlen (UnsavedWords[j]) == 0 || strcmp (word, UnsavedWords[j]) == 0) { strcpy (UnsavedWords[j], word, MAX_TEXT_LENGTH); strcpy (UnsavedSounds[j], command[i], MAX_TEXT_LENGTH); return; } } selfprintf ("Too many unsaved words! This one was not saved. Use %s %s", MY_NAME, OPTION_SAVE_WORDS); } WriteWord (command[], HLUser) { SetWord (command, HLUser); writefile (WORDS_FILE, command); } SaveWords() { new i; new line[MAX_TEXT_LENGTH]; for (i = 0; i < MAX_UNSAVED_WORDS; i++) { if (strlen (UnsavedWords[i]) > 0) { snprintf (line, MAX_TEXT_LENGTH, "%s %s^n", UnsavedWords[i], UnsavedSounds[i]); writefile (WORDS_FILE, line); strinit (UnsavedWords[i]); strinit (UnsavedSounds[i]); } } selfmessage ("Done!"); } SaveSounds() { new i; new line[MAX_TEXT_LENGTH]; for (i = 0; i < NumSounds; i++) { if (SavedSounds[i] != 0) continue; snprintf (line, MAX_TEXT_LENGTH, "%s %s^n", Tokens[i], Sounds[i]); writefile (SOUNDS_FILE, line); SavedSounds[i] = 1; } selfmessage ("Done!"); } FlushUnsaved() { new i; NumSounds = 0; ReadSounds(); for (i = 0; i < MAX_UNSAVED_WORDS; i++) { strinit (UnsavedWords[i]); strinit (UnsavedSounds[i]); } selfmessage ("Done!"); } ListSounds (match[]) { new i; new output[MAX_TEXT_LENGTH]; strinit (output); for (i = 0; i < NumSounds; i++) { if (match[0] != NULL_CHAR && strcasestr (Tokens[i], match) == DONE) continue; if (SavedSounds[i] == 0) AddOutput (Tokens[i], output, 0, 1); else AddOutput (Tokens[i], output, 0, 0); } selfmessage (output); } ListWords (lineStr[]) { new count; new line[MAX_TEXT_LENGTH]; new lineNo; new output[MAX_TEXT_LENGTH]; new start; new word[MAX_TEXT_LENGTH]; strinit (output); if (lineStr[0] == NULL_CHAR) start = 1; else start = strtonum (lineStr); count = 0; for (lineNo = ReadLine (WORDS_FILE, start, line, MAX_TEXT_LENGTH); lineNo != DONE && count < MAX_OUT_LINES; lineNo = ReadLine (WORDS_FILE, lineNo, line, MAX_TEXT_LENGTH)) { if (CopyToken (line, 0, word, MAX_TEXT_LENGTH) == DONE) continue; count = AddOutput (word, output, count); } selfmessage (output); if (count >= MAX_OUT_LINES) { selfprintf ("Use %s %s %i for the next set of words", MY_NAME, OPTION_WORDS, lineNo); } } ListVox (lineStr[]) { new count; new line[MAX_TEXT_LENGTH]; new lineNo; new output[MAX_TEXT_LENGTH]; new start; strinit (output); if (lineStr[0] == NULL_CHAR) start = 1; else start = strtonum (lineStr); count = 0; for (lineNo = ReadLine (VOX_WORDS_FILE, start, line, MAX_TEXT_LENGTH); lineNo != DONE && count < MAX_OUT_LINES; lineNo = ReadLine (VOX_WORDS_FILE, lineNo, line, MAX_TEXT_LENGTH)) { count = AddOutput (line, output, count); } selfmessage (output); if (count >= MAX_OUT_LINES) { selfprintf ("Use %s %s %i for the next set of words", MY_NAME, OPTION_VOX, lineNo); } } MatchWords (match[]) { new count; new line[MAX_TEXT_LENGTH]; new lineNo; new hadHit; new output[MAX_TEXT_LENGTH]; new token[MAX_TEXT_LENGTH]; if (strlen (match) == 0) { selfprintf ("You must supply a string to match on. EG, '%s %s blue'", MY_NAME, OPTION_MATCH); selfprintf ("will display all words with 'blue' in them."); return; } hadHit = 0; count = 0; // check lines file hadHit = 0; for (lineNo = ReadLine (LINES_FILE, 0, line, MAX_TEXT_LENGTH); lineNo != DONE && count < MAX_OUT_LINES; lineNo = ReadLine (LINES_FILE, lineNo, line, MAX_TEXT_LENGTH)) { if (CopyToken (line, 0, token, MAX_TEXT_LENGTH) == DONE) continue; // the above check was just to make sure the line kinda sorta looks // right. We actually want to match on the whole line.. if (strcasestr (line, match) == -1) continue; if (hadHit == 0) { hadHit = 1; selfprintf ("Matches from %s:", LINES_FILE); count++; } selfmessage (line); if (++count > MAX_OUT_LINES) { selfmessage ("Too many matches. Stopping. Please be more specific."); return; } } if (hadHit != 0) selfmessage (""); if (count < MAX_UNSAVED_WORDS) { strinit (output); hadHit = 0; // check unsaved words.. for (lineNo = 0; lineNo < MAX_UNSAVED_WORDS; lineNo++) { if (strlen(UnsavedWords[lineNo]) == 0) continue; if (hadHit == 0) { hadHit = 1; selfmessage ("Unsaved words:"); count++; } count = AddOutput (UnsavedWords[lineNo], output, count, 1); } if (strlen (output) > 0) { selfmessage (output); strinit (output); } } // next, check for matches in the words file.. if (count < MAX_UNSAVED_WORDS) { if (hadHit != 0) selfmessage (""); hadHit = 0; strinit (output); for (lineNo = ReadLine (WORDS_FILE, 0, line, MAX_TEXT_LENGTH); lineNo != DONE && count < MAX_OUT_LINES; lineNo = ReadLine (WORDS_FILE, lineNo, line, MAX_TEXT_LENGTH)) { if (CopyToken (line, 0, token, MAX_TEXT_LENGTH) == DONE) continue; if (strcasestr (token, match) == -1) continue; if (hadHit == 0) { hadHit = 1; selfprintf ("Matches from %s:", WORDS_FILE); strinit (output); count++; } count = AddOutput (token, output, count); } if (strlen(output) > 0) { count++; if (count < MAX_OUT_LINES) selfmessage (output); } } // last, check to see if there's any built-in matches if (count < MAX_OUT_LINES) { if (hadHit != 0) selfmessage (""); hadHit = 0; strinit (output); for (lineNo = ReadLine (VOX_WORDS_FILE, 0, line, MAX_TEXT_LENGTH); lineNo != DONE && count < MAX_OUT_LINES; lineNo = ReadLine (VOX_WORDS_FILE, lineNo, line, MAX_TEXT_LENGTH)) { if (strcasestr (line, match) == DONE) continue; if (hadHit == 0) { hadHit = 1; selfprintf ("Matches from %s:", VOX_WORDS_FILE); strinit (output); count++; } count = AddOutput (line, output, count); } if (strlen(output) > 0) { count++; if (count < MAX_OUT_LINES) selfmessage (output); } } if (count >= MAX_OUT_LINES) { selfprintf ("Too many matches. Stopping. Please be more specific."); return; } } DumpUnsaved() { new count; new i; new hadHit; count = 0; hadHit = 0; for (i = 0; i < NumSounds && count < MAX_OUT_LINES; i++) { if (SavedSounds[i] != 0 || strlen(Tokens[i]) == 0) continue; if (hadHit == 0) { hadHit = 1; selfmessage ("Unsaved sounds:"); count++; } selfprintf ("^t%s^t^t%s", Tokens[i], Sounds[i]); count++; } hadHit = 0; for (i = 0; i < MAX_UNSAVED_WORDS && count < MAX_OUT_LINES; i++) { if (strlen (UnsavedWords[i]) == 0) continue; if (hadHit == 0) { hadHit = 1; selfmessage ("Unsaved words:"); count++; } selfprintf ("^t%s^t^t%s", UnsavedWords[i], UnsavedSounds[i]); count++; } if (count >= MAX_OUT_LINES) { selfmessage ("Oops: too many unsaved sounds and/or words!"); } } AddOutput (str[], line[], count, flag = 0) { if (strlen(str) + strlen(line) > MAX_COLUMN) { selfmessage (line); strinit (line); count++; } new tmp[MAX_TEXT_LENGTH]; if (flag) snprintf (tmp, MAX_TEXT_LENGTH, "^t^t*%s", str); else snprintf (tmp, MAX_TEXT_LENGTH, "^t^t %s", str); strcat (line, tmp, MAX_TEXT_LENGTH); return count; } ReadLine (file[], lineNo, buffer[], maxlen) { new done; new i; new ret; new raw[MAX_TEXT_LENGTH]; done = 0; while (!done) { ret = readfile (file, raw, lineNo, MAX_TEXT_LENGTH); if (ret == 0) { // EOF return DONE; } i = SkipWS (raw); if (i == DONE || strncmp (raw, "//", 2) == 0) lineNo++; else done = 1; } strncpy (buffer, raw[i], maxlen, MAX_TEXT_LENGTH); // return next lineNo to read return lineNo + 1; } selfprintf (origformat[], ...) { new i; new format[MAX_TEXT_LENGTH]; new output[MAX_TEXT_LENGTH]; if (numargs() == 1) { selfmessage (origformat); return; } strcpy (format, origformat, MAX_TEXT_LENGTH); for (i = 1; i < numargs(); i++) { if (getarg(i, 1) == 0) { // 2nd element is a 0 - assume it's a number snprintf (output, MAX_TEXT_LENGTH, format, getarg(i)); } else { new tmp[MAX_TEXT_LENGTH]; new p; // element 1 is not 0.. assume this is a string strinit (tmp); for (p = 0; getarg(i, p) != NULL_CHAR && p < MAX_TEXT_LENGTH; p++) { tmp[p] = getarg(i, p); } tmp[p] = NULL_CHAR; snprintf (output, MAX_TEXT_LENGTH, format, tmp); } strcpy (format, output, MAX_TEXT_LENGTH); } selfmessage (output); } CopyToken (source[], start, token[], maxlen) { new i; new j; strinit (token); i = SkipWS (source, start); if (i == DONE) return DONE; for (j = 0; source[i] > SPACE && j < maxlen - 1; i++) { token[j++] = source[i]; } token[j] = NULL_CHAR; return i; } SkipWS (source[], start = 0) { new i; if (start == DONE) return DONE; for (i = start; source[i] != NULL_CHAR; i++) { if (source[i] > SPACE) { return i; } } return DONE; }