/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // /////////////////////////////////////////////////////////////////////////////// using DirectoryService.Utils; using FileSystem.Utils; using System; using System.Collections; using System.Text; using System.Text.RegularExpressions; using System.ParseNumbers; using Microsoft.Singularity; using System.IO; using System.GC; using System.Runtime.Remoting; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Threading; using System.Diagnostics; using Microsoft.SingSharp; using Microsoft.Singularity.Directory; using DirectoryServices.Utils; using Microsoft.Singularity.V1.Services; using Microsoft.Singularity.Io; using Microsoft.Singularity.FileSystem; using Microsoft.Singularity.Channels; using Microsoft.Contracts; using Microsoft.SingSharp.Reflection; using Microsoft.Singularity.Applications; using Microsoft.Singularity.Configuration; [assembly: Transform(typeof(ApplicationResourceTransform))] namespace Microsoft.Singularity.Applications { [ConsoleCategory(HelpMessage="Stream Editor", DefaultAction=true)] internal class Parameters { [InputEndpoint("data")] public readonly TRef Stdin; [OutputEndpoint("data")] public readonly TRef Stdout; [StringParameter( "filename", Mandatory=true, Position=0, HelpMessage="Name of file.")] internal string fileName; reflective internal Parameters(); internal int AppMain() { SEditor.AppMain(this); return 0; } } public class SEditor { internal static void AppMain(Parameters! config) { // constants string EditorName = "SEditor"; int szLineCount = 0; int nIndex = 0; //FOR DEBUG // Console.WriteLine("Number of cmd line params = {0}", args.Length); // FOR DEBUG // Console.WriteLine("args[1] is {0}", args[1]); string filename = config.fileName; string szSrcLine; ArrayList szContents = new ArrayList(); if (File.Exists(filename)) { FileStream fsInput = new FileStream(filename, FileMode.Open, FileAccess.Read); StreamReader srInput = new StreamReader(fsInput); while ((szSrcLine = srInput.ReadLine()) != null) { szContents.Add(szSrcLine); // FOR DEBUG // Console.WriteLine("{0}", szSrcLine); // Console.ReadLine(); // END DEBUG } srInput.Close(); fsInput.Close(); // Display number of lines loaded szLineCount = szContents.Count; Console.WriteLine("* Number of lines read from {0} was {1}", filename, szLineCount); // FOR DEBUG ONLY: display contents of file // for (nIndex = 0; nIndex < szContents.Count; nIndex++) { // write line to console with numbering // Console.WriteLine("{0}: {1}", (nIndex + 1), szContents[nIndex]); // } } else if (System.IO.Directory.Exists(filename)) { // check that it's not a directory Console.WriteLine("Exiting: {0} is a directory.", filename); Console.WriteLine("Syntax: {0} filename", EditorName); return; } else { // not a directory, but file doesn't exist, so create it Console.WriteLine("* Creating new file."); } // Command parser - this is the main program loop Parser(szContents, nIndex, filename); } // end Main // Parse incoming commands static void Parser(ArrayList szArray, int pIndex, string InputFileName) { //FOR DEBUG // Console.WriteLine("* Parser called."); // Console.WriteLine("* Current line index is {0}," pIndex); Console.Write("* "); string ParserInput; string ParserInputFirstChar; string BackupFileName = ""; int tempIndex = 0; ArrayList tempArray = new ArrayList(); bool IsTextUpdated = false; int tempSize = 0; // build proper backup file name - look for extension if it exists, and replace it with (or add to) ".bak" if (Path.HasExtension(InputFileName) && (Path.GetExtension(InputFileName) != ".bak")) { // has an extension other than .bak BackupFileName = Path.ChangeExtension(InputFileName, ".bak"); } else if (Path.HasExtension(InputFileName) && (Path.GetExtension(InputFileName) == ".bak")) { // .bak already in use, use something else Console.WriteLine("{0} ends in .bak - using .ba2 for backup files...", InputFileName); Console.Write("* "); BackupFileName = Path.ChangeExtension(InputFileName, ".ba2"); } else { // no extension, so add one BackupFileName = InputFileName + ".bak"; } while (((ParserInput = GetConsoleInput()) != "q") && (ParserInput != "Q") && (ParserInput != null)) { if (ParserInput != "") { //FOR DEBUG //Console.WriteLine("* Input was {0}", ParserInput); //Console.Write("* "); // ParserInputFirstChar = Convert.ToString(ParserInput[0]); ParserInputFirstChar = ParserInput[0].ToString(); } else { Console.Write("* "); continue; } // Simple switch based parsing of commands switch (ParserInputFirstChar) { case "h": case "H": case "?": Console.WriteLine("* Commands available are:"); Console.WriteLine("* ?, (h | H) - prints this message"); Console.WriteLine("* [number] - start editing at line [number]"); Console.WriteLine("* (a | A) - append lines at end of file"); Console.WriteLine("* (c | C)[num1],[num2],[destnum] - copy lines from num1 to num2 to dest num"); Console.WriteLine("* (d | D); (d | D)[num]; (d | D)[num1],[num2] - delete current line, "); Console.WriteLine("* line at num, lines from num1 to num2"); Console.WriteLine("* (e | E) - exit, saving changes"); Console.WriteLine("* (i | I); (i | I)[num] - insert line above current line, or above line num"); Console.WriteLine("* (l | L); (l | L)[num]; (l | L)[num1],[num2] - list the whole file, "); Console.WriteLine("* list the line at num, list the lines from num1 to num2"); Console.WriteLine("* (m | M)[num1],[num2],[destnum] - move lines from num1 to num2 to dest num"); Console.WriteLine("* (n | N) - print current line number (location in file)"); Console.WriteLine("* (p | P) - same as l, only displays one page at a time."); Console.WriteLine("* (q | Q) - quit, saving no changes since last write"); Console.WriteLine("* (r | R)[num1],([num2] | ?),[searchstr]^[replacestr] - replace"); Console.WriteLine("* searchstr with replacestr. If ? is used as second param, sub is prompted"); Console.WriteLine("* (s | S)[num1],([num2] | ?),[searchstr] - search for searchstr. "); Console.WriteLine("* If ? is used as second param, occurrence is displayed with prompt"); Console.WriteLine("* until accepted with y, Y, or newline."); Console.WriteLine("* (t | T)[num],[filename] - insert contents of filename above line num."); Console.WriteLine("* (w | W) - write contents of memory to filename. Original contents will be"); Console.WriteLine("* backed up as for exit command."); break; case "a": case "A": // FOR DEBUG // Console.WriteLine("* Input was for AppendAtEOF()"); tempSize = szArray.Count; tempArray = AppendAtEOF(szArray); if (tempArray.Count > tempSize) { // array has grown, so assume text modified IsTextUpdated = true; } szArray = tempArray; pIndex = tempArray.Count; // move line pointer to the end of the file break; case "c": case "C": // FOR DEBUG // Console.WriteLine("* Input was for CopyLines()"); if (szArray.Count == 0) { Console.WriteLine("* No text available to copy - new empty file"); } else { tempArray = CopyLines(szArray, ParserInput, pIndex); if (szArray.Count != pIndex) { // assume the array has changed, ergo text modified IsTextUpdated = true; } szArray = tempArray; } break; case "d": case "D": // FOR DEBUG // Console.WriteLine("* Input was for DeleteLines()"); if (szArray.Count == 0) { Console.WriteLine("* No text available to delete - new empty file"); } else { tempArray = DeleteLines(szArray, ParserInput, pIndex); if (szArray.Count != pIndex) { // assume the array has changed, ergo text modified IsTextUpdated = true; } szArray = tempArray; tempIndex = szArray.Count; if (tempIndex < pIndex) { // deletion has reduced line count below pIndex - reset the pointer pIndex = tempIndex; } } break; case "e": case "E": // FOR DEBUG // Console.WriteLine("* Input was for Exit ..."); if (szArray.Count == 0) { Console.WriteLine("* No text to save, exiting without write."); return; } else { Console.WriteLine("* Exiting...."); EditorWrite(szArray, InputFileName, BackupFileName); return; } break; case "i": case "I": // FOR DEBUG // Console.WriteLine("* Input was for InsertAtLine()"); // Insert is a special case. The line pointer for the file needs to move // to the point of insertion if an argument is given, so we will parse that // here and pass the results, since we need to get the updated array back. if (szArray.Count == 0) { Console.WriteLine("* No lines to insert above - new empty file"); } else { Regex shortr = new Regex(@"^[iI](?<1>\d+)", RegexOptions.Compiled); Match shortm; shortm = shortr.Match(ParserInput); Group shortg1 = shortm.Groups[1]; if ((ParserInput == "i") || (ParserInput == "i")) { //insert above current line pointer pIndex InsertAtLine(szArray, pIndex); IsTextUpdated = true; } else if (shortm.Success) { // we have one line number //FOR DEBUG //Console.WriteLine("Line number {0}", shortm.Groups[1]); // write out line Capture shortc1 = shortg1.Captures[0]; // tempIndex = Convert.ToInt32(shortc1.Value); tempIndex = Int32.Parse(shortc1.Value); if (tempIndex >= 1 && tempIndex <= szArray.Count) { // check for line numbers in range of file pIndex = tempIndex; // update pIndex InsertAtLine(szArray, pIndex); IsTextUpdated = true; } else { Console.WriteLine("* Line number {0} out of range. File length is {1}", tempIndex, szArray.Count); } } else { Console.WriteLine("Invalid match"); } } break; case "l": case "L": // FOR DEBUG //Console.WriteLine("* Input was for ListText()"); tempIndex = ListText(szArray, ParserInput, pIndex); if (tempIndex != -1) { // update current line number if list command moved the pointer pIndex = tempIndex; } break; case "m": case "M": //FOR DEBUG //Console.WriteLine("* Input was for MoveLines()"); if (szArray.Count == 0) { Console.WriteLine("* No text available to move - new empty file"); } else { tempArray = MoveLines(szArray, ParserInput, pIndex); szArray = tempArray; IsTextUpdated = true; } break; case "n": case "N": //FOR DEBUG // Console.WriteLine("* Input was for PrintLineNumber()"); Console.WriteLine("* {0}", pIndex); break; case "p": case "P": // FOR DEBUG // Console.WriteLine("* Input was for PageText()"); tempIndex = PageText(szArray, ParserInput, pIndex); if (tempIndex != -1) { // update current line number if list command moved the pointer pIndex = tempIndex; } break; case "r": case "R": //FOR DEBUG // Console.WriteLine("* Input was for ReplaceText()"); if (szArray.Count == 0) { Console.WriteLine("* No text available to replace"); } else { tempArray = ReplaceText(szArray, ParserInput, pIndex); szArray = tempArray; IsTextUpdated = true; } break; case "s": case "S": //FOR DEBUG // Console.WriteLine("* Input was for SearchForText()"); if (szArray.Count == 0) { Console.WriteLine("* No text available to search"); } else { tempIndex = SearchForText(szArray, ParserInput, pIndex); if (tempIndex != -1) { // update current line number if list command moved the pointer pIndex = tempIndex; } } break; case "t": case "T": // FOR DEBUG // Console.WriteLine("* Input was for TransferText()"); tempArray = TransferText(szArray, ParserInput); if (szArray.Count != pIndex) { // assume the array has changed, ergo text modified IsTextUpdated = true; } szArray = tempArray; break; case "w": case "W": // FOR DEBUG // Console.WriteLine("* Input was for WriteTextToFile()"); if (szArray.Count == 0) { Console.WriteLine("* No text to save."); } else { EditorWrite(szArray, InputFileName, BackupFileName); IsTextUpdated = false; } break; case "": break; default: int LineNumber = 0; if (szArray.Count == 0) { Console.WriteLine("* No lines to edit at - new empty file"); break; } else { try { // LineNumber = Convert.ToInt32(ParserInput); LineNumber = Int32.Parse(ParserInput); } catch (System.ArgumentNullException) { Console.WriteLine("String is null."); break; } catch (System.FormatException) { Console.WriteLine("* Unrecognized command"); break; } catch (System.OverflowException) { Console.WriteLine("* Overflow in string to int conversion."); break; } } //FOR DEBUG // Console.WriteLine("* Input was for EditAtLine() - line {0}", LineNumber); // update line pointer to LineNumber pIndex = LineNumber; tempArray = EditAtLine(szArray, pIndex); szArray = tempArray; IsTextUpdated = true; break; } Console.Write("* "); } if (IsTextUpdated == true) { // ask them if they really wanted to quit without writing text out Console.WriteLine("* WARNING: modified text not saved."); Console.Write("* Save? (Y/N) "); string SaveReply = GetConsoleInput(); // string SaveReplyFirstChar = Convert.ToString(SaveReply[0]); if (SaveReply != "") { string SaveReplyFirstChar = SaveReply[0].ToString(); switch (SaveReplyFirstChar) { case "y": case "Y": Console.WriteLine("* Exiting...."); EditorWrite(szArray, InputFileName, BackupFileName); break; default: Console.WriteLine("* Exiting without save."); break; } } else { Console.WriteLine("* Exiting without save."); } } } // end of Parser // ListText - returns updated list pointer as int static int ListText(ArrayList szArray, string ParserInput, int nIndex) { Regex fullr = new Regex(@"^[lL](?<1>\d+),(?<2>\d+)", RegexOptions.Compiled); Regex shortr = new Regex(@"^[lL](?<1>\d+)", RegexOptions.Compiled); Match fullm; Match shortm; int listSuccess = 0; int PAGEWIDTH = 72; // allow for line numbers in printouts - up to 99,999. // TODO: adjust line number range dynamically for large files int tempwidth = 0; string workstring = ""; string tempstring = ""; int remainder = 0; int division = 0; int linesinline = 0; int leftinstring = 0; int lowLine = 0; int hiLine = 0; //FOR DEBUGGING //Console.WriteLine("Current line number is {0}", nIndex); fullm = fullr.Match(ParserInput); shortm = shortr.Match(ParserInput); Group fullg1 = fullm.Groups[1]; Group fullg2 = fullm.Groups[2]; Group shortg1 = shortm.Groups[1]; if (fullm.Success) { // we think we have two line numbers, set lowLine and hiLine accordingly //FOR DEBUG //Console.WriteLine("First line number {0}, last line number {1}", fullm.Groups[1], fullm.Groups[2]); Capture fullc1 = fullg1.Captures[0]; Capture fullc2 = fullg2.Captures[0]; // int lowLine = Convert.ToInt32(fullc1.Value); lowLine = Int32.Parse(fullc1.Value) - 1; // offset by one to allow for difference in starting point... // int hiLine = Convert.ToInt32(fullc2.Value); hiLine = Int32.Parse(fullc2.Value); // but leave this one alone, due to the loop // test for numbers out of range or out of order if ((lowLine <= hiLine) && (lowLine >= 0 && lowLine <= szArray.Count) && (hiLine >= 0 && hiLine <= szArray.Count)) { // continue on to listing... } else { // bad arguments Console.WriteLine("* Malformed arguments to list, or line out of range."); Console.WriteLine("* lnum1,num2 where num1 <= num2 and num2 <= length of file."); Console.WriteLine("* File length is {0}.", szArray.Count); listSuccess = -1; return listSuccess; } } else if (shortm.Success) { // we have one line number //FOR DEBUG //Console.WriteLine("Line number {0}", shortm.Groups[1]); // write out line Capture shortc1 = shortg1.Captures[0]; // nIndex = Convert.ToInt32(shortc1.Value); nIndex = Int32.Parse(shortc1.Value); if (nIndex >= 1 && nIndex <= szArray.Count) { // check for line numbers in range of file lowLine = nIndex - 1; hiLine = nIndex; // proceed to listing } else { Console.WriteLine("* Line number {0} out of range. File length is {1}", nIndex, szArray.Count); listSuccess = -1; return listSuccess; } } else if ((ParserInput == "l") || (ParserInput == "L")) { // set lowLine = 0, hiLine = szArray.Count lowLine = 0; hiLine = szArray.Count; } else { Console.WriteLine("Invalid match"); listSuccess = -1; return listSuccess; } // print out buffer contents between lowLine and hiLine for (nIndex = lowLine; nIndex < hiLine; nIndex++) { workstring = szArray[nIndex].ToString(); tempwidth = workstring.Length; if (tempwidth > PAGEWIDTH) { //FOR DEBUG //Console.WriteLine(" need to break up line length"); while (division != 1) { linesinline++; division = tempwidth / PAGEWIDTH; remainder = tempwidth % PAGEWIDTH; tempwidth = tempwidth - PAGEWIDTH; //FOR DEBUG //Console.WriteLine("remainder = {0}, division = {1}, tempwidth = {2}, linesinline = {3}", remainder, division, tempwidth, linesinline); //Console.ReadLine(); } if (remainder != 0) { linesinline++; //FOR DEBUG //Console.WriteLine("remainder = {0}, division = {1}, tempwidth = {2}, linesinline = {3}", remainder, division, tempwidth, linesinline); //Console.ReadLine(); } leftinstring = workstring.Length; while (linesinline > 0) { if (leftinstring >= PAGEWIDTH) { tempstring = workstring.Substring(workstring.Length - leftinstring, PAGEWIDTH); } else { tempstring = workstring.Substring(workstring.Length - leftinstring, remainder); } Console.WriteLine("{0,5}: {1}", (nIndex + 1), tempstring); linesinline--; if (leftinstring > PAGEWIDTH) { leftinstring = leftinstring - PAGEWIDTH; } } // rezero worker constants remainder = 0; division = 0; linesinline = 0; leftinstring = 0; listSuccess = 1; } else { Console.WriteLine("{0,5}: {1}", (nIndex + 1), szArray[nIndex]); } listSuccess = 1; } if (listSuccess == 1) { return nIndex; // paging worked } else { // note: you should never get here return -1; // bad arguments, don't move line pointer } } // end of ListText // CopyLines() - returns updated ArrayList with copies done, or the original ArrayList static ArrayList CopyLines(ArrayList szArray, string ParserInput, int nIndex) { Queue copyQueue = new Queue(); Regex copyr = new Regex(@"^[cC](?<1>\d+),(?<2>\d+),(?<3>\d+)", RegexOptions.Compiled); Match copym; //FOR DEBUGGING //Console.WriteLine("Current line number is {0}", nIndex); copym = copyr.Match(ParserInput); Group copyg1 = copym.Groups[1]; Group copyg2 = copym.Groups[2]; Group copyg3 = copym.Groups[3]; if (copym.Success) { // we think we have two line numbers and a dest number //FOR DEBUG //Console.WriteLine("First line number {0}, last line number {1}, dest {2}", copym.Groups[1], copym.Groups[2], copym.Groups[3]); //Put array elements to be copied into copyQueue Capture copyc1 = copyg1.Captures[0]; // first line of copy Capture copyc2 = copyg2.Captures[0]; // last line of copy // int lowLine = Convert.ToInt32(copyc1.Value); int lowLine = Int32.Parse(copyc1.Value); // int hiLine = Convert.ToInt32(copyc2.Value); int hiLine = Int32.Parse(copyc2.Value); // test for numbers out of range or out of order if ((lowLine <= hiLine) && (lowLine >= 1 && lowLine <= szArray.Count) && (hiLine >= 1 && hiLine <= szArray.Count)) { for (nIndex = lowLine; nIndex <= hiLine; nIndex++) { //FOR DEBUG // Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); copyQueue.Enqueue(szArray[nIndex - 1]); } // check dest num valid Capture copyc3 = copyg3.Captures[0]; // int destLine = Convert.ToInt32(copyc3.Value); int destLine = Int32.Parse(copyc3.Value); if (destLine >= 1 && destLine <= szArray.Count) { // insert copyQueue at point dest in szArray // note that due to the indexing offset you need to decrement destLine by 1 here szArray.InsertRange(destLine - 1, copyQueue); } else if (destLine > szArray.Count) { // ask them if they want the copy at the end of the file Console.Write("* Copy past end of file - do you want block appended? (y/n) "); string appendReply = GetConsoleInput(); // string appendReplyFirstChar = Convert.ToString(appendReply[0]); if (appendReply != "") { string appendReplyFirstChar = appendReply[0].ToString(); switch (appendReplyFirstChar) { case "y": case "Y": szArray.AddRange(copyQueue); break; default: Console.WriteLine("* Aborting copy."); break; } } else { Console.WriteLine("* Aborting copy."); } } else { Console.WriteLine("* Invalid copy destination."); Console.WriteLine("* cnum1,num2,dest where num1 <= num2, num2 and dest <= length of file."); Console.WriteLine("* File length is {0}.", szArray.Count); } } else { // bad arguments Console.WriteLine("* Malformed arguments to copy, or line out of range."); Console.WriteLine("* cnum1,num2 where num1 <= num2, num2 and dest <= length of file."); Console.WriteLine("* File length is {0}.", szArray.Count); } return szArray; // c[num1,num2,dest] worked } else { Console.WriteLine("Invalid match"); return szArray; } } // end of CopyLines // DeleteLines() - returns updated ArrayList with deletes done, or the original ArrayList static ArrayList DeleteLines(ArrayList szArray, string ParserInput, int nIndex) { Regex fullr = new Regex(@"^[dD](?<1>\d+),(?<2>\d+)", RegexOptions.Compiled); Regex shortr = new Regex(@"^[dD](?<1>\d+)", RegexOptions.Compiled); Match fullm; Match shortm; //FOR DEBUGGING //Console.WriteLine("Current line number is {0}", nIndex); fullm = fullr.Match(ParserInput); shortm = shortr.Match(ParserInput); Group fullg1 = fullm.Groups[1]; Group fullg2 = fullm.Groups[2]; Group shortg1 = shortm.Groups[1]; if ((ParserInput == "d") || (ParserInput == "D")) { // delete line at current nIndex (which means subtracting 1) szArray.RemoveAt(nIndex - 1); return szArray; } else if (fullm.Success) { // we think we have two line numbers //FOR DEBUG //Console.WriteLine("First line number {0}, last line number {1}", fullm.Groups[1], fullm.Groups[2]); //delete lines between first and second numbers Capture fullc1 = fullg1.Captures[0]; Capture fullc2 = fullg2.Captures[0]; // int lowLine = Convert.ToInt32(fullc1.Value); int lowLine = Int32.Parse(fullc1.Value); // int hiLine = Convert.ToInt32(fullc2.Value); int hiLine = Int32.Parse(fullc2.Value); // test for numbers out of range or out of order if ((lowLine <= hiLine) && (lowLine >= 1 && lowLine <= szArray.Count) && (hiLine >= 1 && hiLine <= szArray.Count) && ((hiLine - lowLine) != 0)) { szArray.RemoveRange(lowLine - 1, ((hiLine - lowLine) + 1)); } else { // bad arguments Console.WriteLine("* Malformed arguments to list, or line out of range."); Console.WriteLine("* dnum1,num2 where num1 <= num2 and num2 <= length of file."); Console.WriteLine("* File length is {0}.", szArray.Count); } return szArray; // end of d[num1,num] } else if (shortm.Success) { // we have one line number //FOR DEBUG //Console.WriteLine("Line number {0}", shortm.Groups[1]); // delete line Capture shortc1 = shortg1.Captures[0]; // nIndex = Convert.ToInt32(shortc1.Value); nIndex = Int32.Parse(shortc1.Value); if (nIndex >= 1 && nIndex <= szArray.Count) { // check for line numbers in range of file szArray.RemoveAt(nIndex - 1); } else { Console.WriteLine("* Line number {0} out of range. File length is {1}", nIndex, szArray.Count); return szArray; } return szArray; } else { Console.WriteLine("Invalid match"); return szArray; } } // end of DeleteLines // EditAtLine() - edit the line at nIndex in szArray. Since we know the line number, we don't have // to parse ParserInput here. static ArrayList EditAtLine(ArrayList szArray, int nIndex) { Queue editQueue = new Queue(); if (nIndex >= 1 && nIndex <= szArray.Count) { // check that line number is in range of file Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); Console.Write("> "); string editInput = GetConsoleInput(); if (editInput == "") { return szArray; } else { editQueue.Enqueue(editInput); szArray.RemoveAt(nIndex - 1); szArray.InsertRange(nIndex - 1, editQueue); } } else { Console.WriteLine("* Line number {0} out of range. File length is {1}", nIndex, szArray.Count); } return szArray; } // end of EditAtLine // InsertAtLine() - insert line(s) above nIndex in szArray. Since we know the line number, we don't have // to parse ParserInput here. static ArrayList InsertAtLine(ArrayList szArray, int nIndex) { Queue insertQueue = new Queue(); string insertInput = null; Console.WriteLine("* Inserting text above {0}: {1}", nIndex, szArray[nIndex - 1]); Console.WriteLine("* Press ^^ to end input."); while (insertInput != "^^") { // Double carat ^^ ends input - would have used control char, but need tty to understand them.... Console.Write("> "); insertInput = GetConsoleInput(); if (insertInput != "^^") { insertQueue.Enqueue(insertInput); } } szArray.InsertRange(nIndex - 1, insertQueue); return szArray; } // end of InsertAtLine // AppendAtEOF() - append line(s) below current end of szArray. Since we are appending, we don't have // to parse ParserInput here. static ArrayList AppendAtEOF(ArrayList szArray) { Queue appendQueue = new Queue(); string appendInput = null; Console.WriteLine("* Appending text at EOF - Press ^^ to end input."); while (appendInput != "^^") { // ^^ ends input Console.Write("> "); appendInput = GetConsoleInput(); if (appendInput != "^^") { appendQueue.Enqueue(appendInput); } } szArray.AddRange(appendQueue); return szArray; } // end of AppendAtEOF() // MoveLines() - returns updated ArrayList with moves done, or the original ArrayList static ArrayList MoveLines(ArrayList szArray, string ParserInput, int nIndex) { Queue moveQueue = new Queue(); Regex mover = new Regex(@"^[mM](?<1>\d+),(?<2>\d+),(?<3>\d+)", RegexOptions.Compiled); Match movem; //FOR DEBUGGING //Console.WriteLine("Current line number is {0}", nIndex); movem = mover.Match(ParserInput); Group moveg1 = movem.Groups[1]; Group moveg2 = movem.Groups[2]; Group moveg3 = movem.Groups[3]; if (movem.Success) { // we think we have two line numbers and a dest number //FOR DEBUG // Console.WriteLine("First line number {0}, last line number {1}, dest {2}", movem.Groups[1], movem.Groups[2], movem.Groups[3]); //Put array elements to be moved into moveQueue Capture movec1 = moveg1.Captures[0]; // first line of move Capture movec2 = moveg2.Captures[0]; // last line of move // int lowLine = Convert.ToInt32(movec1.Value); int lowLine = Int32.Parse(movec1.Value); // int hiLine = Convert.ToInt32(movec2.Value); int hiLine = Int32.Parse(movec2.Value); // test for numbers out of range or out of order if ((lowLine <= hiLine) && (lowLine >= 1 && lowLine <= szArray.Count) && (hiLine >= 1 && hiLine <= szArray.Count)) { for (nIndex = lowLine; nIndex <= hiLine; nIndex++) { //FOR DEBUG // Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); moveQueue.Enqueue(szArray[nIndex - 1]); } // check dest num valid // However, you can't overlap - dest must either be before the block you're moving, or after it. Capture movec3 = moveg3.Captures[0]; // int destLine = Convert.ToInt32(movec3.Value); int destLine = Int32.Parse(movec3.Value); if ((destLine >= 1 && destLine <= szArray.Count) && ((destLine < lowLine) || (destLine) > hiLine)) { // insert moveQueue at point dest in szArray // note that due to the indexing offset you need to decrement destLine by 1 here szArray.InsertRange(destLine - 1, moveQueue); // once the insertion is complete, then you can delete the lines from the original // however, need to be careful about seeing what happened to the original lines - they // may have moved their indexes in the array depending on where you did the insertion if (destLine > hiLine) { // indexes stayed the same for the original block - delete it szArray.RemoveRange(lowLine - 1, ((hiLine - lowLine) + 1)); } else { // destLine above lowLine, need to adjust int padLine = hiLine - lowLine; szArray.RemoveRange((lowLine + padLine), ((hiLine - lowLine) + 1)); } } else if (destLine > szArray.Count) { // ask them if they want the move at the end of the file Console.Write("* Move past end of file - do you want block appended? (y/n) "); string appendReply = GetConsoleInput(); // string appendReplyFirstChar = Convert.ToString(appendReply[0]); if (appendReply != "") { string appendReplyFirstChar = appendReply[0].ToString(); switch (appendReplyFirstChar) { case "y": case "Y": szArray.AddRange(moveQueue); // we don't have to worry about the index adjustment here - we can just remove the lines // from their original location szArray.RemoveRange(lowLine - 1, ((hiLine - lowLine) + 1)); break; default: Console.WriteLine("* Aborting move."); break; } } else { Console.WriteLine("* Aborting move."); } } else { Console.WriteLine("* Invalid move destination."); Console.WriteLine("* mnum1,num2,dest where num1 <= num2, num2 and dest <= length of file,"); Console.WriteLine("* but dest not within num1 - num2 range."); Console.WriteLine("* File length is {0}.", szArray.Count); } } else { // bad arguments Console.WriteLine("* Malformed arguments to move, or line out of range."); Console.WriteLine("* mnum1,num2 where num1 <= num2, num2 and dest <= length of file,"); Console.WriteLine("* but dest not within num1 - num2 range."); Console.WriteLine("* File length is {0}.", szArray.Count); } return szArray; // m[num1,num2,dest] worked } else { Console.WriteLine("Invalid match"); return szArray; } } // end of MoveLines // SearchForText() - returns updated list pointer, since we're not modifying any text static int SearchForText(ArrayList szArray, string ParserInput, int nIndex) { Regex closedsearchr = new Regex(@"^[sS](?<1>\d+),(?<2>\d+),(?<3>.+)", RegexOptions.Compiled); Regex opensearchr = new Regex(@"^[sS](?<1>\d+),\?,(?<2>.+)", RegexOptions.Compiled); Match closedsearchm; Match opensearchm; //FOR DEBUGGING //Console.WriteLine("Current line number is {0}", nIndex); closedsearchm = closedsearchr.Match(ParserInput); opensearchm = opensearchr.Match(ParserInput); Group closedsearchg1 = closedsearchm.Groups[1]; Group closedsearchg2 = closedsearchm.Groups[2]; Group closedsearchg3 = closedsearchm.Groups[3]; Group opensearchg1 = opensearchm.Groups[1]; Group opensearchg2 = opensearchm.Groups[2]; int searchSuccess = 0; if (closedsearchm.Success) { // we think we have two line numbers and a search string //FOR DEBUG // Console.WriteLine("First line number {0}, last line number {1}, string {2}", closedsearchm.Groups[1], closedsearchm.Groups[2], closedsearchm.Groups[3]); Capture closedsearchc1 = closedsearchg1.Captures[0]; Capture closedsearchc2 = closedsearchg2.Captures[0]; Capture closedsearchc3 = closedsearchg3.Captures[0]; // int lowLine = Convert.ToInt32(closedsearchc1.Value); int lowLine = Int32.Parse(closedsearchc1.Value); // int hiLine = Convert.ToInt32(closedsearchc2.Value); int hiLine = Int32.Parse(closedsearchc2.Value); Regex searchstringr = new Regex(Regex.Escape(closedsearchc3.Value)); Match searchstringm; // test for numbers out of range or out of order if ((lowLine <= hiLine) && (lowLine >= 1 && lowLine <= szArray.Count) && (hiLine >= 1 && hiLine <= szArray.Count)) { for (nIndex = lowLine; nIndex <= hiLine; nIndex++) { //FOR DEBUG // Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); // search for the searchstring in the current line // searchstringm = searchstringr.Match(Regex.Escape(Convert.ToString(szArray[nIndex - 1]))); searchstringm = searchstringr.Match(Regex.Escape(szArray[nIndex - 1].ToString())); if (searchstringm.Success) { // found a match Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); searchSuccess = 1; break; } else { // no match found //FOR DEBUG // Console.WriteLine("* No match found"); searchSuccess = -1; } } } else { // bad arguments Console.WriteLine("* Malformed arguments to search, or line out of range."); Console.WriteLine("* snum1,[num2 | ?],string where num1 <= num2 and"); Console.WriteLine("* num2 <= length of file. File length is {0}", szArray.Count); searchSuccess = -1; } if (searchSuccess == 1) { return nIndex; } else { Console.WriteLine("* No match found"); return -1; } } else if (opensearchm.Success) { // we have a starting line number and a string //FOR DEBUG // Console.WriteLine("First line number {0}, last line number {1}, string {2}", closedsearchm.Groups[1], closedsearchm.Groups[2], closedsearchm.Groups[3]); Capture opensearchc1 = opensearchg1.Captures[0]; Capture opensearchc2 = opensearchg2.Captures[0]; // int lowLine = Convert.ToInt32(opensearchc1.Value); int lowLine = Int32.Parse(opensearchc1.Value); Regex searchstringr = new Regex(Regex.Escape(opensearchc2.Value)); Match searchstringm; // test for start number out of range if (lowLine >= 1 && lowLine <= szArray.Count) { for (nIndex = lowLine; nIndex <= szArray.Count; nIndex++) { //FOR DEBUG // Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); // search for the searchstring in the current line // searchstringm = searchstringr.Match(Regex.Escape(Convert.ToString(szArray[nIndex - 1]))); searchstringm = searchstringr.Match(Regex.Escape(szArray[nIndex - 1].ToString())); if (searchstringm.Success) { // found a match Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); Console.Write("O.K.? "); string searchReply = GetConsoleInput(); if (searchReply == "") { searchSuccess = 1; } else { // string searchReplyFirstChar = Convert.ToString(searchReply[0]); string searchReplyFirstChar = searchReply[0].ToString(); switch (searchReplyFirstChar) { case "y": case "Y": searchSuccess = 1; break; default: searchSuccess = -1; break; } } if (searchSuccess == 1) { // found a match, so stop looking (break from the for loop) break; } } else { // no match found //FOR DEBUG // Console.WriteLine("* No match found"); searchSuccess = -1; } } } else { // bad arguments Console.WriteLine("* Malformed arguments to search, or line out of range."); Console.WriteLine("* snum1,[num2 | ?],string where num1 <= num2 and"); Console.WriteLine("* num2 <= length of file. File length is {0}", szArray.Count); searchSuccess = -1; } if (searchSuccess == 1) { return nIndex; } else { Console.WriteLine("* No match found"); return -1; } } else { // bad match to initial parse of command args Console.WriteLine("* Malformed arguments to search, or line out of range."); Console.WriteLine("* snum1,[num2 | ?],string where num1 <= num2 and"); Console.WriteLine("* num2 <= length of file. File length is {0}", szArray.Count); return -1; } } // end of SearchForText // ReplaceText() - returns updated list pointer, since we're not modifying any text static ArrayList ReplaceText(ArrayList szArray, string ParserInput, int nIndex) { Regex closedreplacer = new Regex(@"^[rR](?<1>\d+),(?<2>\d+),(?<3>.+)\^(?<4>.+)", RegexOptions.Compiled); Regex openreplacer = new Regex(@"^[rR](?<1>\d+),\?,(?<2>.+)\^(?<3>.+)", RegexOptions.Compiled); Match closedreplacem; Match openreplacem; //FOR DEBUGGING //Console.WriteLine("Current line number is {0}", nIndex); closedreplacem = closedreplacer.Match(ParserInput); openreplacem = openreplacer.Match(ParserInput); Group closedreplaceg1 = closedreplacem.Groups[1]; Group closedreplaceg2 = closedreplacem.Groups[2]; Group closedreplaceg3 = closedreplacem.Groups[3]; Group closedreplaceg4 = closedreplacem.Groups[4]; Group openreplaceg1 = openreplacem.Groups[1]; Group openreplaceg2 = openreplacem.Groups[2]; Group openreplaceg3 = openreplacem.Groups[3]; if (closedreplacem.Success) { // we think we have two line numbers, a search string, and a replace string //FOR DEBUG // Console.WriteLine("First line number {0}, last line number {1}, string {2}, string {3}", closedreplacem.Groups[1], closedreplacem.Groups[2], closedreplacem.Groups[3], closedreplacem.Groups[4]); Capture closedreplacec1 = closedreplaceg1.Captures[0]; Capture closedreplacec2 = closedreplaceg2.Captures[0]; Capture closedreplacec3 = closedreplaceg3.Captures[0]; Capture closedreplacec4 = closedreplaceg4.Captures[0]; // int lowLine = Convert.ToInt32(closedreplacec1.Value); int lowLine = Int32.Parse(closedreplacec1.Value); // int hiLine = Convert.ToInt32(closedreplacec2.Value); int hiLine = Int32.Parse(closedreplacec2.Value); Regex searchstringr = new Regex(Regex.Escape(closedreplacec3.Value)); // Match searchstringm; Regex replacestringr = new Regex(Regex.Escape(closedreplacec4.Value)); string replaceresult = null; // test for numbers out of range or out of order if ((lowLine <= hiLine) && (lowLine >= 1 && lowLine <= szArray.Count) && (hiLine >= 1 && hiLine <= szArray.Count)) { for (nIndex = lowLine; nIndex <= hiLine; nIndex++) { //FOR DEBUG // Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); // search for the searchstring in the current line and replace it with the replacement string if found // replaceresult = Regex.Replace(Convert.ToString(szArray[nIndex - 1]), Convert.ToString(searchstringr), Convert.ToString(replacestringr)); replaceresult = Regex.Replace(szArray[nIndex - 1].ToString(), searchstringr.ToString(), replacestringr.ToString()); Queue replaceQueue = new Queue(); replaceQueue.Enqueue(replaceresult); szArray.InsertRange(nIndex - 1, replaceQueue); szArray.RemoveAt(nIndex); } } else { // bad arguments Console.WriteLine("* Malformed arguments to replace, or line out of range."); Console.WriteLine("* rnum1,[num2 | ?],string,string where num1 <= num2 and"); Console.WriteLine("* num2 <= length of file. File length is {0}", szArray.Count); } return szArray; } else if (openreplacem.Success) { // we have a starting line number, a search string and a replace string //FOR DEBUG // Console.WriteLine("First line number {0}, string {1}, string {2}", openreplacem.Groups[1], openreplacem.Groups[2], openreplacem.Groups[3]); Capture openreplacec1 = openreplaceg1.Captures[0]; Capture openreplacec2 = openreplaceg2.Captures[0]; Capture openreplacec3 = openreplaceg3.Captures[0]; // int lowLine = Convert.ToInt32(openreplacec1.Value); int lowLine = Int32.Parse(openreplacec1.Value); Regex searchstringr = new Regex(Regex.Escape(openreplacec2.Value)); Match searchstringm; Regex replacestringr = new Regex(Regex.Escape(openreplacec3.Value)); string replaceresult = null; // test for start number out of range if (lowLine >= 1 && lowLine <= szArray.Count) { for (nIndex = lowLine; nIndex <= szArray.Count; nIndex++) { //FOR DEBUG // Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); // search for the searchstring in the current line // searchstringm = searchstringr.Match(Regex.Escape(Convert.ToString(szArray[nIndex - 1]))); searchstringm = searchstringr.Match(Regex.Escape(szArray[nIndex - 1].ToString())); if (searchstringm.Success) { // found a match Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); Console.Write("O.K.? "); string replaceReply = GetConsoleInput(); if (replaceReply == "") { // replaceresult = Regex.Replace(Convert.ToString(szArray[nIndex - 1]), Convert.ToString(searchstringr), Convert.ToString(replacestringr)); replaceresult = Regex.Replace(szArray[nIndex - 1].ToString(), searchstringr.ToString(), replacestringr.ToString()); Queue replaceQueue = new Queue(); replaceQueue.Enqueue(replaceresult); szArray.InsertRange(nIndex - 1, replaceQueue); szArray.RemoveAt(nIndex); } else { // string replaceReplyFirstChar = Convert.ToString(replaceReply[0]); string replaceReplyFirstChar = replaceReply[0].ToString(); switch (replaceReplyFirstChar) { case "y": case "Y": // replaceresult = Regex.Replace(Convert.ToString(szArray[nIndex - 1]), Convert.ToString(searchstringr), Convert.ToString(replacestringr)); replaceresult = Regex.Replace(szArray[nIndex - 1].ToString(), searchstringr.ToString(), replacestringr.ToString()); Queue replaceQueue = new Queue(); replaceQueue.Enqueue(replaceresult); szArray.InsertRange(nIndex - 1, replaceQueue); szArray.RemoveAt(nIndex); break; default: break; } } } else { // no match found //FOR DEBUG // Console.WriteLine("* No match found"); } } } else { // bad arguments Console.WriteLine("* Malformed arguments to replace, or line out of range."); Console.WriteLine("* rnum1,[num2 | ?],string,string where num1 <= num2 and"); Console.WriteLine("* num2 <= length of file. File length is {0}", szArray.Count); } return szArray; } else { // bad match to initial parse of command args Console.WriteLine("* Malformed arguments to replace, or line out of range."); Console.WriteLine("* rnum1,[num2 | ?],string,string where num1 <= num2 and"); Console.WriteLine("* num2 <= length of file. File length is {0}", szArray.Count); return szArray; } } // end of ReplaceText static void EditorWrite(ArrayList szArray, string InputFileName, string BackupFileName) { int pIndex = 0; // check to see if file exists at all, first - if it doesn't, // we have to create it, but don't have to back it up. if (File.Exists(InputFileName)) { // it does exist, ergo we need to back it up // Test to see if the backup file exists, if it does, delete it (to clear it) if (File.Exists(BackupFileName)) { File.Delete(BackupFileName); } // Then, copy the original file to one with bak at the end File.Copy(InputFileName, BackupFileName, true); // Then delete the original file (to clear it) File.Delete(InputFileName); // Then write out the contents of the buffer to our InputFileName FileStream fsOutput = new FileStream(InputFileName, FileMode.Create, FileAccess.Write); StreamWriter srOutput = new StreamWriter(fsOutput); for (pIndex = 0; pIndex < szArray.Count; pIndex++) { //FOR DEBUG // Console.WriteLine("* pIndex = {0}, line = {1}", pIndex, szArray[pIndex]); srOutput.WriteLine(szArray[pIndex]); } srOutput.Close(); fsOutput.Close(); return; } else { // file didn't exist, so create it, and don't back it up FileStream fsOutput = new FileStream(InputFileName, FileMode.Create, FileAccess.Write); StreamWriter srOutput = new StreamWriter(fsOutput); for (pIndex = 0; pIndex < szArray.Count; pIndex++) { srOutput.WriteLine(szArray[pIndex]); } srOutput.Close(); fsOutput.Close(); return; } } // end of EditorWrite(); // PageText - returns updated list pointer as int static int PageText(ArrayList szArray, string ParserInput, int nIndex) { Regex fullr = new Regex(@"^[pP](?<1>\d+),(?<2>\d+)", RegexOptions.Compiled); Regex shortr = new Regex(@"^[pP](?<1>\d+)", RegexOptions.Compiled); Match fullm; Match shortm; int listSuccess = 0; int pageCounter = 0; string pageReply = ""; string pageReplyFirstChar = ""; int PAGELENGTH = 47; // allow for Singularity "activity" line at top of console int PAGEWIDTH = 72; // allow for line numbers in printouts - up to 99,999. // TODO: adjust line number range dynamically for large files int tempwidth = 0; string workstring = ""; string tempstring = ""; int remainder = 0; int division = 0; int linesinline = 0; int leftinstring = 0; int lowLine = 0; int hiLine = 0; //FOR DEBUGGING //Console.WriteLine("Current line number is {0}", nIndex); fullm = fullr.Match(ParserInput); shortm = shortr.Match(ParserInput); Group fullg1 = fullm.Groups[1]; Group fullg2 = fullm.Groups[2]; Group shortg1 = shortm.Groups[1]; if (fullm.Success) { // we think we have two line numbers, set lowLine and hiLine accordingly //FOR DEBUG //Console.WriteLine("First line number {0}, last line number {1}", fullm.Groups[1], fullm.Groups[2]); Capture fullc1 = fullg1.Captures[0]; Capture fullc2 = fullg2.Captures[0]; // int lowLine = Convert.ToInt32(fullc1.Value); lowLine = Int32.Parse(fullc1.Value) - 1; // offset by one to allow for difference in starting point... // int hiLine = Convert.ToInt32(fullc2.Value); hiLine = Int32.Parse(fullc2.Value); // but leave this one alone, due to the loop // test for numbers out of range or out of order if ((lowLine <= hiLine) && (lowLine >= 0 && lowLine <= szArray.Count) && (hiLine >= 0 && hiLine <= szArray.Count)) { // continue on to listing... } else { // bad arguments Console.WriteLine("* Malformed arguments to page, or line out of range."); Console.WriteLine("* pnum1,num2 where num1 <= num2 and num2 <= length of file."); Console.WriteLine("* File length is {0}.", szArray.Count); listSuccess = -1; return listSuccess; } } else if (shortm.Success) { // we have one line number //FOR DEBUG //Console.WriteLine("Line number {0}", shortm.Groups[1]); // write out line Capture shortc1 = shortg1.Captures[0]; // nIndex = Convert.ToInt32(shortc1.Value); nIndex = Int32.Parse(shortc1.Value); if (nIndex >= 1 && nIndex <= szArray.Count) { // check for line numbers in range of file lowLine = nIndex - 1; hiLine = nIndex; // proceed to listing } else { Console.WriteLine("* Line number {0} out of range. File length is {1}", nIndex, szArray.Count); listSuccess = -1; return listSuccess; } } else if ((ParserInput == "p") || (ParserInput == "P")) { // set lowLine = 0, hiLine = szArray.Count lowLine = 0; hiLine = szArray.Count; } else { Console.WriteLine("Invalid match"); listSuccess = -1; return listSuccess; } // print out buffer contents between lowLine and hiLine by pages for (nIndex = lowLine; nIndex < hiLine; nIndex++) { workstring = szArray[nIndex].ToString(); tempwidth = workstring.Length; if (tempwidth > PAGEWIDTH) { //FOR DEBUG //Console.WriteLine(" need to break up line length"); while (division != 1) { linesinline++; division = tempwidth / PAGEWIDTH; remainder = tempwidth % PAGEWIDTH; tempwidth = tempwidth - PAGEWIDTH; //FOR DEBUG //Console.WriteLine("remainder = {0}, division = {1}, tempwidth = {2}, linesinline = {3}", remainder, division, tempwidth, linesinline); //Console.ReadLine(); } if (remainder != 0) { linesinline++; //FOR DEBUG //Console.WriteLine("remainder = {0}, division = {1}, tempwidth = {2}, linesinline = {3}", remainder, division, tempwidth, linesinline); //Console.ReadLine(); } if (linesinline < (PAGELENGTH - pageCounter)) { // room to print the whole wrapped line leftinstring = workstring.Length; while (linesinline > 0) { if (leftinstring >= PAGEWIDTH) { tempstring = workstring.Substring(workstring.Length - leftinstring, PAGEWIDTH); } else { tempstring = workstring.Substring(workstring.Length - leftinstring, remainder); } Console.WriteLine("{0,5}: {1}", (nIndex + 1), tempstring); pageCounter++; linesinline--; if (leftinstring > PAGEWIDTH) { leftinstring = leftinstring - PAGEWIDTH; } } } else if (pageCounter <= PAGELENGTH) { // less than PAGELENGTH, but not enough room to print the whole wrapped line leftinstring = workstring.Length; while (linesinline > 0) { if (leftinstring >= PAGEWIDTH) { tempstring = workstring.Substring(workstring.Length - leftinstring, PAGEWIDTH); } else { tempstring = workstring.Substring(workstring.Length - leftinstring, remainder); } Console.WriteLine("{0,5}: {1}", (nIndex + 1), tempstring); pageCounter++; linesinline--; if (leftinstring > PAGEWIDTH) { leftinstring = leftinstring - PAGEWIDTH; } if (pageCounter > PAGELENGTH) { pageCounter = 0; Console.Write("-- -- "); pageReply = GetConsoleInput(); if (pageReply != "") { //pageReplyFirstChar = Convert.ToString(pageReply[0]); pageReplyFirstChar = pageReply[0].ToString(); switch (pageReplyFirstChar) { case "q": case "Q": return nIndex + 1; default: if (leftinstring >= PAGEWIDTH) { tempstring = workstring.Substring(workstring.Length - leftinstring, PAGEWIDTH); } else { tempstring = workstring.Substring(workstring.Length - leftinstring, remainder); } Console.WriteLine("{0,5}: {1}", (nIndex + 1), tempstring); pageCounter++; linesinline--; break; } } } } } // rezero worker constants remainder = 0; division = 0; linesinline = 0; leftinstring = 0; listSuccess = 1; } else { Console.WriteLine("{0,5}: {1}", (nIndex + 1), szArray[nIndex]); if (pageCounter < PAGELENGTH) { pageCounter++; } else { pageCounter = 0; Console.Write("-- -- "); pageReply = GetConsoleInput(); if (pageReply != "") { //pageReplyFirstChar = Convert.ToString(pageReply[0]); pageReplyFirstChar = pageReply[0].ToString(); switch (pageReplyFirstChar) { case "q": case "Q": return nIndex + 1; default: break; } } } listSuccess = 1; } } if (listSuccess == 1) { return nIndex; // paging worked } else { // note that you should never get here return -1; // bad arguments, don't move line pointer } } // end of PageText // TransferText() - returns updated ArrayList with content merged in from external file, or the original ArrayList static ArrayList TransferText(ArrayList szArray, string ParserInput) { Queue transferQueue = new Queue(); Regex transferr = new Regex(@"^[tT](?<1>\d+),(?<2>.+)", RegexOptions.Compiled); Match transferm; //FOR DEBUGGING //Console.WriteLine("Current line number is {0}", nIndex); transferm = transferr.Match(ParserInput); Group transferg1 = transferm.Groups[1]; Group transferg2 = transferm.Groups[2]; if (transferm.Success) { // we think we have a line number and a filename of some sort //FOR DEBUG // Console.WriteLine("First line number {0}, filename {1}", transferm.Groups[1], transferm.Groups[2]); //Put file contents to be copied into transferQueue Capture transferc1 = transferg1.Captures[0]; // insertion point // int lowLine = Convert.ToInt32(transferc1.Value); int lowLine = Int32.Parse(transferc1.Value); Capture transferc2 = transferg2.Captures[0]; // filename // string TransferFileName = Convert.ToString(transferc2.Value); string TransferFileName = transferc2.Value.ToString(); if (File.Exists(TransferFileName)) { // file exists, so read it into a buffer string TransferLine; ArrayList transferContents = new ArrayList(); FileStream fsInput = new FileStream(TransferFileName, FileMode.Open, FileAccess.Read); StreamReader srInput = new StreamReader(fsInput); while ((TransferLine = srInput.ReadLine()) != null) { transferContents.Add(TransferLine); } srInput.Close(); fsInput.Close(); for (int transferIndex = 0; transferIndex < transferContents.Count; transferIndex++) { //FOR DEBUG // Console.WriteLine("{0}: {1}", transferIndex, transferContents[transferIndex]); transferQueue.Enqueue(transferContents[transferIndex]); } } else { // file to be merged wasn't there Console.WriteLine("* File to be merged doesn't exist."); return szArray; } // test for numbers out of range or out of order if (lowLine >= 1 && lowLine <= szArray.Count) { // szArray.InsertRange(lowLine - 1, transferQueue); return szArray; } else if (lowLine > szArray.Count) { // check if number is past the end of the file and they want to append Console.Write("* Transfer past end of file - do you want file appended? (Y/N) "); string appendReply = GetConsoleInput(); // string appendReplyFirstChar = Convert.ToString(appendReply[0]); if (appendReply != "") { string appendReplyFirstChar = appendReply[0].ToString(); switch (appendReplyFirstChar) { case "y": case "Y": szArray.AddRange(transferQueue); break; default: Console.WriteLine("* Aborting transfer."); break; } } else { Console.WriteLine("* Aborting transfer."); } return szArray; } else { // something else is wrong with the insertion point Console.WriteLine("* Invalid transfer destination."); Console.WriteLine("* tnum1, filename where num1 is insertion point and filename"); Console.WriteLine("* is what is to be inserted. File length is {0}.", szArray.Count); return szArray; } } else {// bad arguments Console.WriteLine("* Malformed arguments to transfer."); Console.WriteLine("* tnum1, filename where num1 is insertion point and filename"); Console.WriteLine("* is what is to be inserted. File length is {0}.", szArray.Count); return szArray; } } // end of TransferText static string GetConsoleInput() { // filter Console.ReadLine input for backspaces string InputString = ""; string InputCheck = ""; InputString = Console.ReadLine(); if (InputString != "") { //FOR DEBUG //Console.WriteLine("* Input was {0}", InputString); //Console.Write("* "); // //for (int i = 0; i < InputString.Length; i++) { // Console.Write("{0:x}",(int)InputString[i]); //} //Console.Write("* "); // END DEBUG // Check for backspace chars and remove them if present, but also delete the character(s) they meant to delete int j = 0; string TempString = ""; for (int i = 0; i < InputString.Length; i++) { if ((int)InputString[i] != 0x08) { TempString = string.Concat(InputCheck,InputString[i].ToString()); InputCheck = TempString; j++; } else { InputCheck = InputCheck.Remove(j - 1,1); j--; } } //FOR DEBUG //Console.WriteLine("* Check was {0}", InputCheck); //Console.Write("* "); // //for (int i = 0; i < InputCheck.Length; i++) { // Console.Write("{0:x}",(int)InputCheck[i]); //} //END DEBUG } return InputCheck; } // end of GetConsoleInput() } }