| ----------------------------------------------------------------------------- |
| -- Little program to download DICT word definitions |
| -- LuaSocket sample files |
| -- Author: Diego Nehab |
| -- RCS ID: $Id: dict.lua,v 1.22 2005/11/22 08:33:29 diego Exp $ |
| ----------------------------------------------------------------------------- |
| |
| ----------------------------------------------------------------------------- |
| -- Load required modules |
| ----------------------------------------------------------------------------- |
| local base = _G |
| local string = require("string") |
| local table = require("table") |
| local socket = require("socket") |
| local url = require("socket.url") |
| local tp = require("socket.tp") |
| module("socket.dict") |
| |
| ----------------------------------------------------------------------------- |
| -- Globals |
| ----------------------------------------------------------------------------- |
| HOST = "dict.org" |
| PORT = 2628 |
| TIMEOUT = 10 |
| |
| ----------------------------------------------------------------------------- |
| -- Low-level dict API |
| ----------------------------------------------------------------------------- |
| local metat = { __index = {} } |
| |
| function open(host, port) |
| local tp = socket.try(tp.connect(host or HOST, port or PORT, TIMEOUT)) |
| return base.setmetatable({tp = tp}, metat) |
| end |
| |
| function metat.__index:greet() |
| return socket.try(self.tp:check(220)) |
| end |
| |
| function metat.__index:check(ok) |
| local code, status = socket.try(self.tp:check(ok)) |
| return code, |
| base.tonumber(socket.skip(2, string.find(status, "^%d%d%d (%d*)"))) |
| end |
| |
| function metat.__index:getdef() |
| local line = socket.try(self.tp:receive()) |
| local def = {} |
| while line ~= "." do |
| table.insert(def, line) |
| line = socket.try(self.tp:receive()) |
| end |
| return table.concat(def, "\n") |
| end |
| |
| function metat.__index:define(database, word) |
| database = database or "!" |
| socket.try(self.tp:command("DEFINE", database .. " " .. word)) |
| local code, count = self:check(150) |
| local defs = {} |
| for i = 1, count do |
| self:check(151) |
| table.insert(defs, self:getdef()) |
| end |
| self:check(250) |
| return defs |
| end |
| |
| function metat.__index:match(database, strat, word) |
| database = database or "!" |
| strat = strat or "." |
| socket.try(self.tp:command("MATCH", database .." ".. strat .." ".. word)) |
| self:check(152) |
| local mat = {} |
| local line = socket.try(self.tp:receive()) |
| while line ~= '.' do |
| database, word = socket.skip(2, string.find(line, "(%S+) (.*)")) |
| if not mat[database] then mat[database] = {} end |
| table.insert(mat[database], word) |
| line = socket.try(self.tp:receive()) |
| end |
| self:check(250) |
| return mat |
| end |
| |
| function metat.__index:quit() |
| self.tp:command("QUIT") |
| return self:check(221) |
| end |
| |
| function metat.__index:close() |
| return self.tp:close() |
| end |
| |
| ----------------------------------------------------------------------------- |
| -- High-level dict API |
| ----------------------------------------------------------------------------- |
| local default = { |
| scheme = "dict", |
| host = "dict.org" |
| } |
| |
| local function there(f) |
| if f == "" then return nil |
| else return f end |
| end |
| |
| local function parse(u) |
| local t = socket.try(url.parse(u, default)) |
| socket.try(t.scheme == "dict", "invalid scheme '" .. t.scheme .. "'") |
| socket.try(t.path, "invalid path in url") |
| local cmd, arg = socket.skip(2, string.find(t.path, "^/(.)(.*)$")) |
| socket.try(cmd == "d" or cmd == "m", "<command> should be 'm' or 'd'") |
| socket.try(arg and arg ~= "", "need at least <word> in URL") |
| t.command, t.argument = cmd, arg |
| arg = string.gsub(arg, "^:([^:]+)", function(f) t.word = f end) |
| socket.try(t.word, "need at least <word> in URL") |
| arg = string.gsub(arg, "^:([^:]*)", function(f) t.database = there(f) end) |
| if cmd == "m" then |
| arg = string.gsub(arg, "^:([^:]*)", function(f) t.strat = there(f) end) |
| end |
| string.gsub(arg, ":([^:]*)$", function(f) t.n = base.tonumber(f) end) |
| return t |
| end |
| |
| local function tget(gett) |
| local con = open(gett.host, gett.port) |
| con:greet() |
| if gett.command == "d" then |
| local def = con:define(gett.database, gett.word) |
| con:quit() |
| con:close() |
| if gett.n then return def[gett.n] |
| else return def end |
| elseif gett.command == "m" then |
| local mat = con:match(gett.database, gett.strat, gett.word) |
| con:quit() |
| con:close() |
| return mat |
| else return nil, "invalid command" end |
| end |
| |
| local function sget(u) |
| local gett = parse(u) |
| return tget(gett) |
| end |
| |
| get = socket.protect(function(gett) |
| if base.type(gett) == "string" then return sget(gett) |
| else return tget(gett) end |
| end) |
| |