From 89847b43c2fcffefb6ec655857bf21cd0e354769 Mon Sep 17 00:00:00 2001 From: Beoran Date: Fri, 17 Jun 2016 06:05:09 +0200 Subject: [PATCH] Change the tree structure so it is compatible with the standard layout of golang projects. --- {src/woe/monolog => monolog}/monolog.go | 0 raku/raku.go | 152 ++++ {src/woe/server => server}/action.go | 0 server/ask.go | 516 ++++++++++++++ server/client.go | 236 +++++++ server/dialog.go | 279 ++++++++ server/server.go | 345 +++++++++ {src/woe/server => server}/setuptelnet.go | 41 -- {src/woe/sitef => sitef}/marshal.go | 0 {src/woe/sitef => sitef}/sitef.go | 0 src/woe/server/ask.go | 811 ---------------------- src/woe/server/client.go | 222 ------ src/woe/server/server.go | 355 ---------- src/woe/woe.go | 111 --- {src/woe/telnet => telnet}/codes.go | 0 {src/woe/telnet => telnet}/rfc1143.go | 0 {src/woe/telnet => telnet}/telnet.go | 0 woe.go | 112 +++ {src/woe/world => world}/account.go | 16 +- {src/woe/world => world}/art.go | 0 {src/woe/world => world}/being.go | 1 - {src/woe/world => world}/character.go | 0 {src/woe/world => world}/entity.go | 0 {src/woe/world => world}/inventory.go | 0 {src/woe/world => world}/item.go | 0 {src/woe/world => world}/mobile.go | 0 {src/woe/world => world}/room.go | 0 world/security.go | 36 + {src/woe/world => world}/skill.go | 0 {src/woe/world => world}/technique.go | 0 {src/woe/world => world}/world.go | 0 {src/woe/world => world}/zone.go | 0 32 files changed, 1689 insertions(+), 1544 deletions(-) rename {src/woe/monolog => monolog}/monolog.go (100%) create mode 100644 raku/raku.go rename {src/woe/server => server}/action.go (100%) create mode 100644 server/ask.go create mode 100644 server/client.go create mode 100644 server/dialog.go create mode 100644 server/server.go rename {src/woe/server => server}/setuptelnet.go (82%) rename {src/woe/sitef => sitef}/marshal.go (100%) rename {src/woe/sitef => sitef}/sitef.go (100%) delete mode 100644 src/woe/server/ask.go delete mode 100644 src/woe/server/client.go delete mode 100644 src/woe/server/server.go delete mode 100644 src/woe/woe.go rename {src/woe/telnet => telnet}/codes.go (100%) rename {src/woe/telnet => telnet}/rfc1143.go (100%) rename {src/woe/telnet => telnet}/telnet.go (100%) create mode 100644 woe.go rename {src/woe/world => world}/account.go (90%) rename {src/woe/world => world}/art.go (100%) rename {src/woe/world => world}/being.go (99%) rename {src/woe/world => world}/character.go (100%) rename {src/woe/world => world}/entity.go (100%) rename {src/woe/world => world}/inventory.go (100%) rename {src/woe/world => world}/item.go (100%) rename {src/woe/world => world}/mobile.go (100%) rename {src/woe/world => world}/room.go (100%) create mode 100644 world/security.go rename {src/woe/world => world}/skill.go (100%) rename {src/woe/world => world}/technique.go (100%) rename {src/woe/world => world}/world.go (100%) rename {src/woe/world => world}/zone.go (100%) diff --git a/src/woe/monolog/monolog.go b/monolog/monolog.go similarity index 100% rename from src/woe/monolog/monolog.go rename to monolog/monolog.go diff --git a/raku/raku.go b/raku/raku.go new file mode 100644 index 0000000..fb90a2f --- /dev/null +++ b/raku/raku.go @@ -0,0 +1,152 @@ +// raku + +/* Raku is an easy to use scripting language that can also be used easily interactively + +Syntax (verified LL(1) ) + +PROGRAM -> STATEMENTS . +STATEMENTS -> STATEMENT STATEMENTS | . +STATEMENT -> EXPRESSION | BLOCK | EMPTY_LINE | comment . +EXPRESSION -> VALUE PARAMETERS NL. +PARAMETERS_NONEMPTY -> PARAMETER PARAMETERS. +PARAMETERS-> PARAMETERS_NONEMPTY | . +PARAMETER -> BLOCK | VALUE . +EMPTY_LINE -> NL . +BLOCK -> ob STATEMENTS cb | op STATEMENTS cp | oa STATEMENTS ca. +NL -> nl | semicolon . +VALUE -> string | float | integer | symbol . + +Lexer: + + +*/ +package raku + +import ( + "fmt" + "io" +) + +type Value string +type TokenType int + +type Position struct { + Index int + Row int + Column int +} + +const ( + TokenError TokenType = iota + TokenEOF +) + +type Token struct { + TokenType + Value + Position +} + +func (me Token) String() string { + return fmt.Sprintf("Token: %d >%s< %d %d %d.", me.TokenType, string(me.Value), me.Index, me.Row, me.Column) +} + +type TokenChannel chan Token + +type Lexer struct { + Reader io.Reader + Current Position + Last Position + Token Token + rule LexerRule + Output TokenChannel + buffer []byte +} + +type LexerRule func(lexer *Lexer) LexerRule + +func (lexer *Lexer) Emit(t TokenType, v Value) { + tok := Token{t, v, lexer.Current} + lexer.Output <- tok +} + +func (lexer *Lexer) Error(message string, args ...interface{}) { + value := fmt.Sprintf(message, args...) + lexer.Emit(TokenError, Value(value)) +} + +func LexError(lexer *Lexer) LexerRule { + lexer.Error("Error") + return nil +} + +func LexNormal(lexer *Lexer) LexerRule { + return LexError +} + +func OpenLexer(reader io.Reader) *Lexer { + lexer := &Lexer{} + lexer.Reader = reader + lexer.Output = make(TokenChannel) + // lexer.buffer = new(byte[1024]) + return lexer +} + +func (me *Lexer) ReadReader() (bool, error) { + buffer := make([]byte, 1024) + + n, err := me.Reader.Read(buffer) + if n > 0 { + me.buffer = append(me.buffer, buffer...) + } + if err == io.EOF { + me.Emit(TokenEOF, "") + return true, nil + } else if err != nil { + me.Error("Error reading from reader: %s", err) + return true, err + } + return false, nil +} + +func (me *Lexer) Start() { + more, err := me.ReadReader() + for err == nil && more { + more, err = me.ReadReader() + } + + if err != nil { + return + } + + rule := LexNormal + for rule != nil { + rule = rule(me) + } + + close(me.Output) +} + +/* +func (me *Lexer) TryLexing() { + go { + me.Start() + } + + for token := range me.Output { + fmt.Println("Token %s", token) + } +} +*/ + +type Parser struct { + Lexer +} + +type Environment struct { + Parent *Environment +} + +func main() { + fmt.Println("Hello World!") +} diff --git a/src/woe/server/action.go b/server/action.go similarity index 100% rename from src/woe/server/action.go rename to server/action.go diff --git a/server/ask.go b/server/ask.go new file mode 100644 index 0000000..5ae6388 --- /dev/null +++ b/server/ask.go @@ -0,0 +1,516 @@ +package server + +/* This file contains dialog helpers for the client. */ + +// import "github.com/beoran/woe/monolog" +import t "github.com/beoran/woe/telnet" +import "github.com/beoran/woe/telnet" +import "github.com/beoran/woe/world" + +// import "github.com/beoran/woe/monolog" +import "bytes" +import "strings" +import "regexp" + +// import "fmt" +import "strconv" + +// import "strings" + +// Switches to "password" mode. +func (me *Client) PasswordMode() telnet.Event { + // The server sends "IAC WILL ECHO", meaning "I, the server, will do any + // echoing from now on." The client should acknowledge this with an IAC DO + // ECHO, and then stop putting echoed text in the input buffer. + // It should also do whatever is appropriate for password entry to the input + // box thing - for example, it might * it out. Text entered in server-echoes + // mode should also not be placed any command history. + // don't use the Q state machne for echos + me.telnet.TelnetSendBytes(t.TELNET_IAC, t.TELNET_WILL, t.TELNET_TELOPT_ECHO) + tev, _, _ := me.TryReadEvent(100) + if tev != nil && !telnet.IsEventType(tev, t.TELNET_DO_EVENT) { + return tev + } + return nil +} + +// Switches to "normal, or non-password mode. +func (me *Client) NormalMode() telnet.Event { + // When the server wants the client to start local echoing again, it s}s + // "IAC WONT ECHO" - the client must respond to this with "IAC DONT ECHO". + // Again don't use Q state machine. + me.telnet.TelnetSendBytes(t.TELNET_IAC, t.TELNET_WONT, t.TELNET_TELOPT_ECHO) + tev, _, _ := me.TryReadEvent(100) + if tev != nil && !telnet.IsEventType(tev, t.TELNET_DONT_EVENT) { + return tev + } + return nil +} + +func (me *Client) Printf(format string, args ...interface{}) { + me.telnet.TelnetPrintf(format, args...) +} + +func (me *Client) ColorTest() { + me.Printf("\033[1mBold\033[0m\r\n") + me.Printf("\033[3mItalic\033[0m\r\n") + me.Printf("\033[4mUnderline\033[0m\r\n") + for fg := 30; fg < 38; fg++ { + me.Printf("\033[%dmForeground Color %d\033[0m\r\n", fg, fg) + me.Printf("\033[1;%dmBold Foreground Color %d\033[0m\r\n", fg, fg) + } + + for bg := 40; bg < 48; bg++ { + me.Printf("\033[%dmBackground Color %d\033[0m\r\n", bg, bg) + me.Printf("\033[1;%dmBold Background Color %d\033[0m\r\n", bg, bg) + } +} + +// Blockingly reads a single command from the client +func (me *Client) ReadCommand() (something []byte) { + something = nil + for something == nil { + something, _, _ = me.TryRead(-1) + if something != nil { + something = bytes.TrimRight(something, "\r\n") + return something + } + } + return nil +} + +func (me *Client) AskSomething(prompt string, re string, nomatch_prompt string, noecho bool) (something []byte) { + something = nil + + if noecho { + me.PasswordMode() + } + + for something == nil || len(something) == 0 { + me.Printf("%s", prompt) + something, _, _ = me.TryRead(-1) + if something != nil { + something = bytes.TrimRight(something, "\r\n") + if len(re) > 0 { + ok, _ := regexp.Match(re, something) + if !ok { + me.Printf("\n%s\n", nomatch_prompt) + something = nil + } + } + } + } + + if noecho { + me.NormalMode() + me.Printf("\n") + } + + return something +} + +func (me *Client) AskYesNo(prompt string) bool { + res := me.AskSomething(prompt+" (y/n)", "[ynYN]", "Please answer y or n.", false) + if res[0] == 'Y' || res[0] == 'y' { + return true + } else { + return false + } +} + +// Interface for an item in a list of options. +type AskOption interface { + // Name of the option, also used to compare input + AskName() string + // Short description of the option, shown after name + AskShort() string + // Long description, displayed if "help name" is requested + AskLong() string + // Accound privilege required or the option to be selectable. + AskPrivilege() world.Privilege +} + +type AskOptionList interface { + AskOptionListLen() int + AskOptionListGet(index int) AskOption +} + +type TrivialAskOption string + +func (me TrivialAskOption) AskName() string { + return string(me) +} + +func (me TrivialAskOption) AskLong() string { + return "" +} + +func (me TrivialAskOption) AskShort() string { + return "" +} + +func (me TrivialAskOption) AskPrivilege() world.Privilege { + return world.PRIVILEGE_ZERO +} + +type TrivialAskOptionList []TrivialAskOption + +func (me TrivialAskOptionList) AskOptionListLen() int { + return len(me) +} + +func (me TrivialAskOptionList) AskOptionListGet(index int) AskOption { + return me[index] +} + +type SimpleAskOption struct { + Name string + Short string + Long string + Privilege world.Privilege +} + +func (me SimpleAskOption) AskName() string { + return me.Name +} + +func (me SimpleAskOption) AskShort() string { + return me.Short +} + +func (me SimpleAskOption) AskLong() string { + return me.Long +} + +func (me SimpleAskOption) AskPrivilege() world.Privilege { + return me.Privilege +} + +type SimpleAskOptionList []SimpleAskOption + +func (me SimpleAskOptionList) AskOptionListLen() int { + return len(me) +} + +func (me SimpleAskOptionList) AskOptionListGet(index int) AskOption { + return me[index] +} + +type JobListAsker []world.Job + +func (me JobListAsker) AskOptionListLen() int { + return len(me) +} + +func (me JobListAsker) AskOptionListGet(index int) AskOption { + return me[index] +} + +type KinListAsker []world.Kin + +func (me KinListAsker) AskOptionListLen() int { + return len(me) +} + +func (me KinListAsker) AskOptionListGet(index int) AskOption { + return me[index] +} + +type GenderListAsker []world.Gender + +func (me GenderListAsker) AskOptionListLen() int { + return len(me) +} + +func (me GenderListAsker) AskOptionListGet(index int) AskOption { + return me[index] +} + +type AskOptionSlice []AskOption +type AskOptionFilterFunc func(AskOption) AskOption + +func (me AskOptionSlice) AskOptionListLen() int { + return len(me) +} + +func (me AskOptionSlice) AskOptionListGet(index int) AskOption { + return me[index] +} + +func AskOptionListEach(me AskOptionList, cb AskOptionFilterFunc) AskOption { + for i := 0; i < me.AskOptionListLen(); i++ { + res := cb(me.AskOptionListGet(i)) + if res != nil { + return res + } + } + return nil +} + +func AskOptionListFilter(me AskOptionList, cb AskOptionFilterFunc) AskOptionList { + result := make(AskOptionSlice, 0) + for i := 0; i < me.AskOptionListLen(); i++ { + res := cb(me.AskOptionListGet(i)) + if res != nil { + result = append(result, res) + } + } + return result +} + +/* Finds the name irrespecful of the case */ +func AskOptionListFindName(me AskOptionList, name string) AskOption { + return AskOptionListEach(me, func(e AskOption) AskOption { + if strings.ToLower(e.AskName()) == strings.ToLower(name) { + return e + } else { + return nil + } + }) +} + +/* Filters the list by privilege level (only those allowed by the level are retained) */ +func AskOptionListFilterPrivilege(me AskOptionList, privilege world.Privilege) AskOptionList { + return AskOptionListFilter(me, func(e AskOption) AskOption { + if e.AskPrivilege() <= privilege { + return e + } else { + return nil + } + }) +} + +type MergedAskOptionList struct { + head AskOptionList + tail AskOptionList +} + +func (me *MergedAskOptionList) AskOptionListLen() int { + return me.head.AskOptionListLen() + me.tail.AskOptionListLen() +} + +func (me *MergedAskOptionList) AskOptionListGet(index int) AskOption { + headlen := me.head.AskOptionListLen() + if index < headlen { + return me.head.AskOptionListGet(index) + } + return me.tail.AskOptionListGet(index - headlen) +} + +/* Merges two AskOptionLists without copying using the MergedAskOptionList rtype */ +func AskOptionListMerge(me AskOptionList, you AskOptionList) AskOptionList { + return &MergedAskOptionList{me, you} +} + +func (me AskOptionSlice) Each(cb AskOptionFilterFunc) AskOption { + for i := 0; i < len(me); i++ { + res := cb(me[i]) + if res != nil { + return res + } + } + return nil +} + +func (me AskOptionSlice) Filter(cb AskOptionFilterFunc) AskOptionSlice { + result := make(AskOptionSlice, 0) + for i := 0; i < len(me); i++ { + res := cb(me[i]) + if res != nil { + result = append(result, res) + } + } + return result +} + +/* Finds the name irrespecful of the case */ +func (me AskOptionSlice) FindName(name string) AskOption { + return me.Each(func(e AskOption) AskOption { + if strings.ToLower(e.AskName()) == strings.ToLower(name) { + return e + } else { + return nil + } + }) +} + +/* Filters the list by privilege level (only those allowed by the level are retained) */ +func (me AskOptionSlice) FilterPrivilege(privilege world.Privilege) AskOptionSlice { + return me.Filter(func(e AskOption) AskOption { + if e.AskPrivilege() <= privilege { + return e + } else { + return nil + } + }) +} + +func (me *Client) AskOptionListHelp(alist AskOptionList, input []byte) { + re := regexp.MustCompile("[^ \t,]+") + argv := re.FindAll(input, -1) + if len(argv) < 2 { + me.Printf("Help usage: help .\n") + return + } + e := AskOptionListFindName(alist, string(argv[1])) + if e == nil { + me.Printf("Cannot find topic %s in list. No help available.\n", string(argv[1])) + } else { + al := e.AskLong() + if al == "" { + me.Printf("Topic %s found, but help is unavailable.\n", string(argv[1])) + } else { + me.Printf("Help on %s:\n%s\n", string(argv[1]), e.AskLong()) + } + } +} + +func (me *Client) AskOptionListOnce(heading string, prompt string, noecho bool, alist AskOptionList) (result AskOption) { + list := AskOptionListFilterPrivilege(alist, me.account.Privilege) + me.Printf("\n%s\n\n", heading) + for i := 0; i < list.AskOptionListLen(); i++ { + v := list.AskOptionListGet(i) + sh := v.AskShort() + if sh == "" { + me.Printf("[%d] %s\n", i+1, v.AskName()) + } else { + me.Printf("[%d] %s: %s\n", i+1, v.AskName(), sh) + } + } + me.Printf("\n") + aid := me.AskSomething(prompt, "", "", false) + iresp, err := strconv.Atoi(string(aid)) + if err != nil { /* Try by name if not a number. */ + e := AskOptionListFindName(alist, string(aid)) + if e != nil { + return e + } else if ok, _ := regexp.Match("help", bytes.ToLower(aid)); ok { + me.AskOptionListHelp(list, aid) + } else { + me.Printf("Name not found in list. Please choose a number or name from the list above. Or type help