OCaml: Read a specific line in a file - ocaml

my problem is simple, i want to read the third line in a file. This is my code, I think it should work.
But it doesn't ... Can someone please explain for me why??
open Printf
let filename = "T:\\Soton Uni\\ok.txt"
let () =
let ic = open_in filename in
let line_counter = 0 in
try
while true; do
line_counter = line_counter + 1;
let line = input_line ic in
if line_counter = 3 then
print_endline line;
done;
flush stdout;
close_in ic
with e ->
close_in_noerr ic;;

Variables in OCaml are never mutable — they can refer to mutable data, but what the variable points to can't be changed.
Therefore, the imperative style variable initialize and update can be written like this:
let line_counter = ref 0 in
while true; do
line_counter := !line_counter + 1
if !line_counter = 3 then
print .....
done;
To initialize a variable using a reference:
let var_name = ref value;
To dereference the value being refereed to by a variable:
!var_name
To update the value being refereed to by a variable:
var_name := !var_name + value

Related

Rust regexes live long enough for match but not find

I'm trying to understand why behavior for the match regex is different from the behavior for find, from documentation here.
I have the following for match:
use regex::Regex;
{
let meow = String::from("This is a long string that I am testing regexes on in rust.");
let re = Regex::new("I").unwrap();
let x = re.is_match(&meow);
dbg!(x)
}
And get:
[src/lib.rs:142] x = true
Great, now let's identify the location of the match:
{
let meow = String::from("This is a long string that I am testing regexes on in rust.");
let re = Regex::new("I").unwrap();
let x = re.find(&meow).unwrap();
dbg!(x)
}
And I get:
let x = re.find(&meow).unwrap();
^^^^^ borrowed value does not live long enough
}
^ `meow` dropped here while still borrowed
`meow` does not live long enough
I think I'm following the documentation. Why does the string meow live long enough for a match but not long enough for find?
Writing a value without ; at the end of a { } scope effectively returns that value out of the scope. For example:
fn main() {
let x = {
let y = 10;
y + 1
};
dbg!(x);
}
[src/main.rs:7] x = 11
Here, because we don't write a ; after the y + 1, it gets returned from the inner scope and written to x.
If you write a ; after it, you will get something different:
fn main() {
let x = {
let y = 10;
y + 1;
};
dbg!(x);
}
[src/main.rs:7] x = ()
Here you can see that the ; now prevents the value from being returned. Because no value gets returned from the inner scope, it implicitly gets the empty return type (), which gets stored in x.
The same happens in your code:
use regex::Regex;
fn main() {
let z = {
let meow = String::from("This is a long string that I am testing regexes on in rust.");
let re = Regex::new("I").unwrap();
let x = re.is_match(&meow);
dbg!(x)
};
dbg!(z);
}
[src/main.rs:9] x = true
[src/main.rs:12] z = true
Because you don't write a ; after the dbg!() statement, its return value gets returned from the inner scope. The dbg!() statement simply returns the value that gets passed to it, so the return value of the inner scope is x. And because x is just a bool, it gets returned without a problem.
Now let's look at your second example:
use regex::Regex;
fn main() {
let z = {
let meow = String::from("This is a long string that I am testing regexes on in rust.");
let re = Regex::new("I").unwrap();
let x = re.find(&meow).unwrap();
dbg!(x)
};
dbg!(z);
}
error[E0597]: `meow` does not live long enough
--> src/main.rs:8:25
|
4 | let z = {
| - borrow later stored here
...
8 | let x = re.find(&meow).unwrap();
| ^^^^^ borrowed value does not live long enough
9 | dbg!(x)
10 | };
| - `meow` dropped here while still borrowed
And now it should be more obvious what's happening: It's basically the same as the previous example, just that the returned x is now a type that internally borrows meow. And because meow gets destroyed at the end of the scope, x cannot be returned, as it would outlive meow.
The reason why x borrows from meow is because regular expression Matches don't actually copy the data they matched, they just store a reference to it.
So if you add a ;, you prevent the value from being returned from the scope, changing the scope return value to ():
use regex::Regex;
fn main() {
let z = {
let meow = String::from("This is a long string that I am testing regexes on in rust.");
let re = Regex::new("I").unwrap();
let x = re.find(&meow).unwrap();
dbg!(x);
};
dbg!(z);
}
[src/main.rs:9] x = Match {
text: "This is a long string that I am testing regexes on in rust.",
start: 27,
end: 28,
}
[src/main.rs:12] z = ()

Define a closure variable in buckle script

I'm trying to convert the following ES6 script to bucklescript and I cannot for the life of me figure out how to create a "closure" in bucklescript
import {Socket, Presence} from "phoenix"
let socket = new Socket("/socket", {
params: {user_id: window.location.search.split("=")[1]}
})
let channel = socket.channel("room:lobby", {})
let presence = new Presence(channel)
function renderOnlineUsers(presence) {
let response = ""
presence.list((id, {metas: [first, ...rest]}) => {
let count = rest.length + 1
response += `<br>${id} (count: ${count})</br>`
})
document.querySelector("main[role=main]").innerHTML = response
}
socket.connect()
presence.onSync(() => renderOnlineUsers(presence))
channel.join()
the part I cant figure out specifically is let response = "" (or var in this case as bucklescript always uses vars):
function renderOnlineUsers(presence) {
let response = ""
presence.list((id, {metas: [first, ...rest]}) => {
let count = rest.length + 1
response += `<br>${id} (count: ${count})</br>`
})
document.querySelector("main[role=main]").innerHTML = response
}
the closest I've gotten so far excludes the result declaration
...
...
let onPresenceSync ev =
let result = "" in
let listFunc = [%raw begin
{|
(id, {metas: [first, ...rest]}) => {
let count = rest.length + 1
result += `${id} (count: ${count})\n`
}
|}
end
] in
let _ =
presence |. listPresence (listFunc) in
[%raw {| console.log(result) |} ]
...
...
compiles to:
function onPresenceSync(ev) {
var listFunc = (
(id, {metas: [first, ...rest]}) => {
let count = rest.length + 1
result += `${id} (count: ${count})\n`
}
);
presence.list(listFunc);
return ( console.log(result) );
}
result is removed as an optimization beacuse it is considered unused. It is generally not a good idea to use raw code that depends on code generated by BuckleScript, as there's quite a few surprises you can encounter in the generated code.
It is also not a great idea to mutate variables considered immutable by the compiler, as it will perform optimizations based on the assumption that the value will never change.
The simplest fix here is to just replace [%raw {| console.log(result) |} ] with Js.log result, but it might be enlightening to see how listFunc could be written in OCaml:
let onPresenceSync ev =
let result = ref "" in
let listFunc = fun [#bs] id item ->
let count = Js.Array.length item##meta in
result := {j|$id (count: $count)\n|j}
in
let _ = presence |. (listPresence listFunc) in
Js.log !result
Note that result is now a ref cell, which is how you specify a mutable variable in OCaml. ref cells are updated using := and the value it contains is retrieved using !. Note also the [#bs] annotation used to specify an uncurried function needed on functions passed to external higher-order functions. And the string interpolation syntax used: {j| ... |j}

Error while using Z3 module in OCaml

I am new to OCaml. I installed Z3 module as mentioned in this link
I am calling Z3 using the command:
ocamlc -custom -o ml_example.byte -I ~/Downloads/z3-unstable/build/api/ml -cclib "-L ~/Downloads/z3-unstable/build/ -lz3" nums.cma z3ml.cma $1
where $1 is replaced with file name.
type loc = int
type var = string
type exp =
| Mul of int * exp
| Add of exp * exp
| Sub of exp * exp
| Const of int
| Var of var
type formula =
| Eq of exp * exp
| Geq of exp
| Gt of exp
type stmt =
| Assign of var * exp
| Assume of formula
type transition = loc * stmt * loc
module OrdVar =
struct
type t = var
let compare = Pervasives.compare
end
module VarSets = Set.Make( OrdVar )
type vars = VarSets.t
module OrdTrans =
struct
type t = transition
let compare = Pervasives.compare
end
module TransitionSets = Set.Make( OrdTrans )
type transitionSet = TransitionSets.t
type program = vars * loc * transitionSet * loc
let ex1 () : program =
let vset = VarSets.empty in
let vset = VarSets.add "x" vset in
let vset = VarSets.add "y" vset in
let vset = VarSets.add "z" vset in
let ts = TransitionSets.empty in
(* 0 X' = X + 1 *)
let stmt1 = Assign( "x", Add( Var("x"), Const(1) ) ) in
let tr1 = (0,stmt1,1) in
let ts = TransitionSets.add tr1 ts in
(vset,0,ts,10)
In the above code I am defining some types. Now if I include the command "open Z3", I am getting "Error: Unbound module Set.Make".
I could run test code which uses Z3 module with out any difficulty, but unable to run with the above code.
The error message in this case is a little bit confusing. The problem is that Z3 also provides a module called Set, which doesn't have a make function. This can be overcome simply by not importing everything from Z3, as there are a number of modulse that might clash with others. For example,
open Z3.Expr
open Z3.Boolean
will work fine and opens only the Z3.Expr and Z3.Boolean modules, but not the Z3.Set module. so that we can write an example function:
let myfun (ctx:Z3.context) (args:expr list) =
mk_and ctx args
If Z3.Boolean is not opened, we would have to write Z3.Boolean.mk_and instead, and similarly we can still access Z3's Set module functions by prefixing them with Z3.Set.

Ocaml: FIFO's reads incorrectly

Ok, so I am working with FIFO's and I was trying to build a small library to use in future programs.
It should be able to create a named pipe, read it and write in it.
I was able to do all these functions, but it isn't reading correctly. The problem is the following:
If I say it should be reading buffers of size 10 characters, it will only print correctly if I write more than 10 characters, ex:
write = "0123456789" -> reads = ""
write = "012345678910111213" -> reads = "","10111213"
I tried the code a bit more and place a small debug on the exception "with".
This exception exists in case the read fails... what it does is: dismiss, wait, restart, and in the end return 0 (nothing)
Then I have an if that will only right if the number of characters is only bigger than 0, if not it will print "empty"
So, what happened was:
write = "0123456789" -> reads = "empty"
write = "012345678910111213" -> reads = "empty","10111213"
So on the first 10 characters he says the read failed, but he removes them from the FIFO. Why?
Sorry if it was a bit confusing. Here is the code:
Program to Read:
let fifo_name = "la_fila";;
(*define the length of the buffer*)
let buflen = 2;;
let main () =
Printf.printf "Hello! Any readers? ...\n";
flush stdout;
while true do
print_string ("I've read \"" ^ bufferRead fifo_name buflen ^ "\" from the fifo!\n");
flush stdout
done;;
(* run it *)
bufferCreate fifo_name;;
let _ = main ();;
and here is the BufferLibrary:
(* Buffer Functions *)
let bufferCreate name =
try Unix.mkfifo name 0o664 with
Unix.Unix_error(n,f,arg) -> Printf.printf "%s(%s) : %s\n" f arg
(Unix.error_message n);;
let bufferRead name size =
let frd = Unix.openfile name [Unix.O_RDONLY;Unix.O_NONBLOCK] 0o644 in
let rec aux () =
let nothing = flush_all ()
in
let buffer = String.create size in
let n = try (Unix.read frd buffer 0 size) with
Unix.Unix_error(n,f,arg) -> begin (); aux (); 0; end
in
if n > 0 then String.sub buffer 0 n else "empty"
in
aux ();;
(*(String.sub buffer 0 n)*)
let bufferWrite name str =
let length = String.length str in
let fwr = Unix.openfile name [Unix.O_WRONLY] 0o644 in
Unix.write fwr str 0 length;;
Edit
open Buffers;;
let fifo_name = "la_fila";;
let main () =
Printf.printf "CUCKOO! any consumer down there? ...\n";
flush stdout;
Printf.printf "cuckoo! Here comes a consumer! \n";
let rec reget () =
Printf.printf "-type something for it\n";
flush stdout;
let str = read_line() (*here it blocks*) in
bufferWrite fifo_name str;
reget () in
reget ();;
(* run it *)
bufferCreate fifo_name;;
main ();;
I would love some light, its killing me...
Thank you
I don't think you want non-blocking IO, at least not for your initial tests. You actually want your reader to block until somebody is ready to write. But then you also probably don't want to reopen the pipe for each read, as that will wait for a writer each time. If you do want to reopen the pipe for each read, then you should also close it. In my tests of your code, the program runs until it uses up all the available file descriptors.
Edit: If you ask for non-blocking I/O your test program is basically polling (burning up CPU cycles) waiting for input to show up. You'll see some arbitrary number of 0-length reads before you start seeing any data. That seems to be what you're reporting. If you open and close the pipe all the time you might lose data if there's a period where no reader or writer has the pipe open.
What you really want to do for an initial test (I'm pretty sure) is open the pipe once for normal (blocking) IO and leave it open forever in the reader (until the end of the test). That should make sure you see all the data. You can try variations after that works.
As a side comment, I think many people eventually decide that the semantics of named pipes are just too finicky. They end up using Unix domain stream sockets instead.

Lua - Reflection - Get list of functions/fields on an object?

I'm new to Lua and dealing with Lua as a scripting language in an alpha release of a program. The developer is unresponsive and I need to get a list of functions provided by some C++ objects which are accessible from the Lua code.
Is there any easy way to see what fields and functions these objects expose?
In Lua, to view the members of a object, you can use:
for key,value in pairs(o) do
print("found member " .. key);
end
Unfortunately I don't know if this will work for objects imported from C++.
If allowed in the environment, looking at the metatable of the exported C++ object can help:
for key,value in pairs(getmetatable(o)) do
print(key, value)
end
Print all the globals:
-- globals.lua
-- show all global variables
local seen={}
function dump(t,i)
seen[t]=true
local s={}
local n=0
for k in pairs(t) do
n=n+1 s[n]=k
end
table.sort(s)
for k,v in ipairs(s) do
print(i,v)
v=t[v]
if type(v)=="table" and not seen[v] then
dump(v,i.."\t")
end
end
end
dump(_G,"")
source: http://www.lua.org/cgi-bin/demo
Output:
_G
_VERSION
assert
bit32
arshift
band
bnot
bor
btest
bxor
extract
lrotate
lshift
replace
rrotate
rshift
collectgarbage
coroutine
create
isyieldable
resume
running
status
wrap
yield
debug
gethook
getinfo
getlocal
getmetatable
getupvalue
getuservalue
sethook
setlocal
setmetatable
setupvalue
setuservalue
traceback
upvalueid
upvaluejoin
dump
error
getmetatable
io
write
ipairs
load
math
abs
acos
asin
atan
atan2
ceil
cos
cosh
deg
exp
floor
fmod
frexp
huge
ldexp
log
log10
max
maxinteger
min
mininteger
modf
pi
pow
rad
random
randomseed
sin
sinh
sqrt
tan
tanh
tointeger
type
ult
next
os
clock
date
difftime
exit
setlocale
time
pairs
pcall
print
rawequal
rawget
rawlen
rawset
select
setmetatable
string
byte
char
dump
find
format
gmatch
gsub
len
lower
match
pack
packsize
rep
reverse
sub
unpack
upper
table
concat
insert
move
pack
remove
sort
unpack
tonumber
tostring
type
utf8
char
charpattern
codepoint
codes
len
offset
xpcall
Something along the same vein as the answer Mr Stinky gave but a whole lot more information.
I made the below code originally for a running from a web server but have added the capability to run on lua for windows
on a web server options are passed in query string ?loadmodules=no&module=_G
in program form options are passed on command line functs loadmodules no module _G
if run with no arguments all modules in pkgpath are loaded and parsed
#!/usr/bin/lua
--------------------------------------------------------------------
--|Functs.lua load available modules parse tables give write to HTML|
--|Table Of Contents, modules, available functions, strings etc.. |
--------------------------------------------------------------------
-- CONFIGURE----------------------------------------------------------------------------------------
local sPkgPath = "/usr/lib/lua" --look here for modules to load in addition to the intrinsic ones
local sWpkgPath = "C:\\Program Files (x86)\\Lua\\5.1\\lua\\" --package path for windows
local sURLsearch = "http://pgl.yoyo.org/luai/i/" --for lua standard functions search this site
local iMaxStr = 1024 -- maximum characters in a string printed to HTML table
local sFileOut = "functs.html"
----------------------------------------------------------------------------------------------------
local tQuery = {} --key,val pairs of arguments
local sQuery = "" --string of arguments ex:'?modload=no&module=_G.math...'
local sResults = "" --Results of each step through
local sEnv = "web" --running on a web server?
----------------------------------------------------------------------------------------------------
----------------------------FUNCTIONS START----------------------------------------------
local function a2m_m2a(addr_member)
--turns members into addresses; addresses back into members
return addr_member
end
local function PrRes(sVal)
--cats results strings
sResults = sResults .. sVal
end
local function errorHandler( err )
PrRes(" ERROR:" .. err .. " ")
--print(debug.traceback())
end
local function putOutput(tData, iCt)
--keys are integer indices, values to iCt written, if iCt = nil whole table written
for k, v in ipairs(tData) do
if iCt == nil or k <= iCt then
io.write (v) --write to std out could be changed here, or as below we change stdout file
end
end
end
local function parse_url(s)
--http://www.flashair-developers.com/en/support/forum/#/discussion/880/getting-query-string-parameters-from-an-http-request-in-lua/
--splits on '=' and '&' puts argument string into named keys with value [Key1] = (val1)&[Key2] = (val2)
--ex: Key1=va1&Key2=val2
local ans = {[0]=""}
----FUNCTIONS for parse_url -----------------------------------------------------
local function decode(s)
s = s:gsub('+', ' ')
s = s:gsub('%%(%x%x)', function(h) return string.char(tonumber(h, 16)) end)
return s
end
----END FUNCTIONS for parse_url --------------------------------------------------
if s == nil then return ans end
--s = s:match('%s+(.+)')
for k,v in s:gmatch('([^&=]+)=([^&=]*)&?' ) do
--2 capture groups all chars (not '&' or '=') '=' all chars (not '&' or '=') followed by '' or '&' or '?'
ans[ k ] = decode(v)
end
return ans
end
local function tableByName(tName)
--find the longest match possible to an actual table
--Name comes in as (table) tName.var so we can pass back out the name found PITA
--returns the table found (key and value)
local ld = {}
local sMatch = ""
local kMatch = nil
local vMatch = nil
----FUNCTIONS for tableByName -----------------------------------------------------
local function search4Str(n, k, v)
local sKey = tostring(k)
if string.find (n, sKey,1,true) then
if sKey:len() > sMatch:len() then sMatch = sKey kMatch = k vMatch = v end
--find the longest match we can
end
end
----END FUNCTIONS for tableByName -------------------------------------------------
if tName.val ~= nil and tName.val ~= "" then
for k, v in pairs(_G) do --_G check both since some tables are only in _G or package.loaded
search4Str(tName.val, k, v)
end
for k, v in pairs(package.loaded) do --package.loaded
search4Str(tName.val, k, v)
end
if not string.find (sMatch, "_G",1,true) then sMatch = "_G." .. sMatch end -- put the root _G in if not exist
if kMatch and vMatch then ld[kMatch] = vMatch tName.val = sMatch return ld end
end
tName.val = "_G"
return package.loaded --Not Found return default
end
local function get_common_branches(t, tRet)
--load t 'names(values)' into keys
--strip off long paths then iterate value if it exists
--local tRet={}
local sBranch = ""
local tName
for k in pairs(t) do
tName={["val"]=k}
tableByName(tName)
sBranch = tName.val
if tRet[sBranch] == nil then
tRet[sBranch] = 1 --first instance of this branch
else
tRet[sBranch] = tRet[sBranch] + 1
end
end
end
local function pairsByPairs (t, tkSorted)
--tkSorted should be an already sorted (i)table with t[keys] in the values
--https://www.lua.org/pil/19.3.html
--!!Note: table sort default function does not like numbers as [KEY]!!
--see *sortbyKeys*cmp_alphanum*
--for n in pairs(t) do table.insert(kSorted, n) end
--table.sort(kSorted, f)
local i = 0 -- iterator variable
local iter = function () -- iterator function
i = i + 1
if tkSorted[i] == nil then return nil
else return tkSorted[i], t[tkSorted[i]]
end
end
return iter
end
local function sortbyKeys(t, tkSorted)
--loads keys of (t) into values of tkSorted
--and then sorts them
--tkSorted has integer keys (see ipairs)
----FUNCTIONS for sortByKeys -------------
local cmp_alphanum = function (op1, op2)
local type1= type(op1)
local type2 = type(op2)
if type1 ~= type2 then
return type1 < type2
else
return op1 < op2
end
end
----END FUNCTIONS for sortByKeys ---------
for n in pairs(t) do table.insert(tkSorted, n) end
table.sort(tkSorted, cmp_alphanum)--table.sort(tkSorted)
end
local function load_modules(sPkgRoot, sWinPkgRoot)
--attempt to load all found modules
--Modules may depend on other modules
--Supresses print, os.exit, rawset
--Ignores *.luac
PrRes("Functions Suspended, ")
local orig ={osexit = _G.os.exit, print = _G.print, rawset = _G.rawset} --save original functions for later restoration
_G.rawset = function(t, i, v) --orig.print ("rawset!")
if _G[i] == v then
orig.rawset(t,i,"_G["..tostring(i).."] !DUP!") --Don't allow global table to be copied
else
orig.rawset(t,i,v)
end
end
_G.os.exit = function() error(999) end --don't exit whole program just this function
_G.print = function()end --don't print
local st = io.popen("find "..sPkgRoot.." -type f -iname '*.so' -o -type f -iname '*.lua'" .." 2> nul")
if not st:read(0) then --find didn't work try windows dir instead
st = io.popen("dir /b /s " .."\""..sWinPkgRoot.."\\*.lua\" " .. "\""..sWinPkgRoot.."\\*.so\" " ) --simple output, subdir
end
if st:read(0) then
for module in st:lines() do
if (module) then
if not string.find (module, ".luac", 1, true) then --don't load precompiled code
local ok, res = pcall(loadfile(module))--protected call
end
end
end
end
_G.os.exit = orig.osexit
_G.print = orig.print
_G.rawset = orig.rawset
PrRes("Functions Restored, ")
end
local function dtTag(sType)
--convert named type; 'number'.. to short type '[n]...'
--if '?' supplied print out datatype key; number = [n]...
local retType = "?"
local typ = {
["nil"] = "nil",
["boolean"] = "b",
["number"] = "n",
["string"] = "s",
["userdata"] = "u",
["function"] = "f",
["thread"] = "thr",
["table"] = "t"
}
if sType == "?" then retType = "Datatypes: " end
for k,v in pairs(typ) do
if sType == k then
retType = v break
elseif (sType == "?") then
retType = retType .. " [" ..v.. "] = " .. k
end
end
return " [" ..retType.. "] "
end
local function dump_Tables(tBase,sFunc, tSeen, tRet)
--Based on: http://www.lua.org/cgi-bin/demo?globals
--Recurse through tBase tables copying all found Tables
local sSep=""
local ld={}
if sFunc ~= "" then sSep = "." end
for k, v in pairs(tBase) do
k = tostring(k)
if k ~= "loaded" and type(v) == "table" and not tSeen[v] then
tSeen[v]=sFunc
tRet[sFunc..sSep .. k] = a2m_m2a(v) --place all keys into ld[i]=value
dump_Tables(v, sFunc .. sSep .. k, tSeen, tRet)
end
end
--print("tables dumped")
end
local function dump_Functions(tBase)
--Based on: http://www.lua.org/cgi-bin/demo?globals
--We already recursed through tBase copying all found tables
--we look up the table by name and then (ab)use a2m_m2a() to load the address
--after finding the table by address in tBase we will put the table address of tFuncs in its place
for k,v in pairs(tBase) do
local tTable = a2m_m2a(v)
local tFuncs = {}
--print(type(tTable))
for key, val in pairs(tTable) do
if key ~= "loaded" then
tFuncs[dtTag(type(val)) .. tostring(key) ]= val --put the name and value in our tFuncs table
end
end
tBase[k] = a2m_m2a(tFuncs) -- copy the address back to tBase
end
--print("functions dumped")
end
local function html_Table(tBase, tkSorted, sId, fHeader, sTitle, iCols, fCellCond, fCell, fFooter, fOut)
--[[Prints HTML <table>
tBase, the table of items you want in your table [key] contains the cell data
tkSorted, the key sorted values of tBase (tkSorted keys are (i) based (see: ipairs)
sID, ID of div tag
fHeader, function returning <DIV></DIV>
sTitle, title of the table
iCols, number of cells wide
fCellCond, if return (TRUE) cell is displayed, fCellCond(k, v, n, iCells, i)
fCell, function returning contents of cell
fFooter, function returning tags at the end of the </table>
fOut, function to print the table[integer]=HTML_DATA based output
--]]
local oTbl={}
local i = 1
local strName=""
local iCells = 0
local n = 0 --counts columns
oTbl[i]=fHeader(sId,sTitle)
i = i + 1 oTbl[i] = "<table><tr><th colspan='"..iCols.."'>"..sTitle.."</th></tr>\r\n"
for k, v in pairsByPairs(tBase,tkSorted ) do
strName= tostring(k)
if fCellCond(k, v, n, iCells, i) then
if n == 0 then
i = i + 1 oTbl[i] = "\t<tr>\r\n"
end
n = n + 1 i = i + 1 iCells = iCells + 1
oTbl[i] = "\t\t"..fCell(strName, v, sTitle).."\r\n"
if n >= iCols then
n = 0
i = i + 1
oTbl[i] = "\t</tr>\r\n"
end
fOut(oTbl, i)
i = 0
end
end
if n ~= 0 then
i = i + 1 oTbl[i] = "\t</tr>\r\n"
end
i = i + 1 oTbl[i] = "</table>\r\n" .. fFooter(strName)
fOut(oTbl, i)
return iCells
end
local function html_function_tables(tBase, tkSortTbase, fOut, iCols)
--print a table of functions for every module in tBase
local strName=""
local iCt = 0
local tFuncs = {}
local tkSorted = {}
----FUNCTIONS for Funct Html-----------------------------------------------------
local function fCellTrue(k)
--return tostring(k) == strName
return true
end
local function fTableCell(strName, value, sTitle)
local sHref = ""
local sType = type(value)
local sPkg = string.match (sTitle, ".+%p(%a+%P)")
local sVal = ""
--strName = tostring(strName)
if string.len(strName) > iMaxStr then
strName=string.sub(strName,1 , iMaxStr).."....." --Truncate strings longer than iMaxStr
end
if sPkg ~= nil and string.find (";debug;package;string;coroutine;io;math;os;table;", ";"..sPkg..";") then
sHref = "<a href='"..sURLsearch .. string.sub(strName,6) .. "'>?</a>" --remove [f] from beginning
end
if nil ~= string.find (";string;number;userdata;boolean;", sType, 1, true) then
sVal = tostring(value)
if string.len(sVal) > iMaxStr then
sVal=string.sub(sVal,1 , iMaxStr).."....." --Truncate strings longer than iMaxStr
end
return "</tr><td colspan='"..iCols.."'>".. sHref ..strName.." : "..sVal.."</td><tr>"
else
return "<td><a>"..strName.."</a>".. sHref .. "</td>"
end
end
local function fPageAnchor(sId, strTitle)
local sHref = ""
local sAddr = ""
local sModload = tQuery.modload
if not sModload then sModload = "" end
local sStyle = "'style='display:block;text-decoration: none"
if os.getenv("SERVER_NAME") and os.getenv("SCRIPT_NAME") then
sAddr = "http://"..os.getenv("SERVER_NAME") .."/".. os.getenv("SCRIPT_NAME") .."?modload=".. sModload
sHref="<a href='"..sAddr.."&module="..strTitle..sStyle.."'>" .."Module: " .. strTitle.. "</a>"
else
sHref = "Module: " .. strTitle
end
return "<div id='"..sId.."'style='color:#0000FF'><h3>"..sHref.."</h3></div>\r\n"
end
local function fPageFooter(strName)
return "<p><a href='#toc'>^</a></p><BR /><BR />"
end
----END FUNCTIONS for Funct Html--------------------------------------------------
for key, val in pairsByPairs(tBase, tkSortTbase) do
strName=tostring(key)
tkSorted = {}
tFuncs = a2m_m2a(val)
sortbyKeys(tFuncs, tkSorted)
iCt = iCt + html_Table(tFuncs,tkSorted, strName, fPageAnchor, strName, iCols, fCellTrue, fTableCell, fPageFooter, fOut)
end
return iCt
end
local function html_toc_tables(tBase, tkSortTbase, fOut, iCols)
local iCt = 0
----FUNCTIONS for TOC Html-----------------------------------------------------
local function fTableCell(strName)
return "<td><a href='#" .. strName .. "'style='display:block;text-decoration: none'>" .. strName.. "</a></td>"
end
local function fCellTrue()
return true
end
local function fFooter()
return "<BR /><b>" .. dtTag("?") .. "</b><BR /><BR /><BR /><BR /><BR /><BR />"
end
local function fPageAnchor(sId, strTitle)
return "<div id='"..sId.."'><p></p></div>\r\n"
end
----END FUNCTIONS for TOC Html--------------------------------------------------
iCt = html_Table(tBase, tkSortTbase, "toc", fPageAnchor, "* Modules Found * Lua Ver. ".._VERSION, iCols, fCellTrue, fTableCell, fFooter, fOut)
return iCt
end
local function main (sPackage)
local tSeen= {}
local tcBase = {}
local tkSortCbase = {}
local tMods= {}
local tkSortMods = {}
local iCtF = 0
if not sPackage then sPackage = "_G" end
putOutput( { --header for html document
[1] = "<!DOCTYPE html>\r\n<html><head>\r\n<style>\r\n",
[2] = "\ttable, th, td {border: 1px solid black;}\r\n",
[3] = "\ttable tr:nth-child(even) {background-color: #C4C4C4;}\r\n",
[4] = "\ttable tr:nth-child(odd) {background-color:#EFEFEF;}\r\n",
[5] = "</style>\r\n</head><body>\r\n"
} )
PrRes("Dump Tables: ")
xpcall( function()dump_Tables(tableByName({["val"] = sPackage}),"", tSeen, tMods) end , errorHandler )
tSeen = nil
PrRes("ok, ")
PrRes("Dump Functions: ")
xpcall( function()dump_Functions(tMods)end , errorHandler )
PrRes("ok, ")
PrRes("Common Branches: ")
get_common_branches(tMods, tcBase)
PrRes("ok, ")
PrRes("Sorting Branches: ")
sortbyKeys(tcBase, tkSortCbase)
sortbyKeys(tMods, tkSortMods)
PrRes("ok, ")
PrRes("Print TOC: ")
iCtF = html_toc_tables(tcBase, tkSortCbase, putOutput, 3)
tcBase= nil tkSortCbase= nil
PrRes(iCtF .." ok, ")
PrRes("Print Functions: ")
iCtF = html_function_tables(tMods, tkSortMods, putOutput, 6)
PrRes(iCtF .." ok, ")
end
----------------------------FUNCTIONS END--------------------------------------------------
if os.getenv("SERVER_NAME") == nil then
sEnv="other"
else --sEnv == web
--Send response header as soon as we load
io.write ("Status: 200 OK\r\nKeep-Alive: timeout=60\r\nContent-Type:text/html\r\nLast-Modified:Sun, 11 Jan 2099 01:01:99 GMT\r\n\r\n") -- end of response)
end
if sQuery == "" then --load arguments from query string if web; or arg[] if not
if sEnv == "web" then
sQuery = os.getenv("QUERY_STRING")
else --Load arguments from arg[] list arg[1]=arg[2]&arg[3]=arg[4]&..
for k,v in pairs({...}) do
sQuery = sQuery .. v
if math.fmod (k, 2) == 0 then
sQuery = sQuery .. "&"
else
sQuery = sQuery .. "="
end
end
end
end
tQuery = parse_url(sQuery)
--[[print(sQuery)
for k,v in pairs(tQuery) do
print ("[", k ,"]=", v)
end]]
if sQuery ~= "modloadno" and tQuery.modload ~= "no" then
PrRes("Load Modules: ")
xpcall( function()load_modules(sPkgPath,sWpkgPath)end, errorHandler )
--load_modules(sPkgPath)
PrRes("ok, ")
end
PrRes("Main; ")
if sEnv ~= "web" then
print("Fileout: " .. sFileOut)
io.output(sFileOut)
end
local ok, res = pcall(main,tQuery.module)
if not ok then
if sEnv ~= "web" then
print("Status: 500 Internal Server Error\r\nContent-Type: text/plain\r\n\r\n" .. res .. "\r\n")
else
print("Error: " .. res)
end
end
PrRes("DONE")
io.write("<p> Query: " .. sQuery .. ";; " .. sResults .."</p>")
Sample Output