readmxtfile

function readmxtfile( filepath ) --> tab, err

Description

Reads and parses a mxt file.

Parameters

filepath

Path to the file that should be read.

Return Values

tab

Map table that represents the content of the mxt file.

err

A meessage if an error occurse, otherwise nil.

Code

--ZFUNC-readfile-v1
local function readfile( filename ) --> str, err
   local f, err = io.open( filename, "r" )
   if err then return nil, err end

   local str, err = f:read( "*a" )
   if err then return nil, err end

   local res, err = f:close()
   if err then return nil, err end

   return str
end

--ZFUNC-trim-v1
local function trim( str ) --> nstr
   local n = str:find( "%S" )
   return n and str:match( ".*%S", n ) or ""
end

--ZFUNC-findbyte-v1
local function findbyte( str, byte, init ) --> idx
   if not init then init = 1 end

   for idx = init, #str do
      if str:byte(idx) == byte then
         return idx
      end
   end

   return nil
end

local function readmxtheader( str, idx ) --> name, pat, idx
   local startBeg, startEnd = str:find( "//%-*%w*%-*", idx )
   if not startBeg then return nil, nil, "no start line" end

   local arrowBeg, arrowEnd = str:find( "-->", startEnd+1, true )
   if not arrowBeg then return nil, nil, nil end

   local patBeg = arrowEnd + 1
   local endlIdx = findbyte( str, string.byte( '\n' ), patBeg )

   local nameBeg, nameEnd = str:find( "%S+", startEnd+1 )
   if not nameBeg or nameBeg > arrowBeg then
      return nil, nil, nil
   end

   local name = str:sub( nameBeg, nameEnd )
   local pat = str:sub( patBeg, endlIdx )
   return name, trim( pat ), endlIdx+1
end

local function startmarker( pat ) --> mrk
   local snip = "//"
   if pat == "" then
      return "//"
   else
      return "//-"..pat.."-"
   end
end

--ZFUNC-readmxtfile-v1
local function readmxtfile( filepath ) --> tab, err
   local str, err = readfile( filepath )
   if err then return nil, err end

   local tab = {}

   local idx = 1
   while idx < str:len() do
      local name, pat, cntBeg = readmxtheader( str, idx )
      if not name then return nil, "invalid header" end

      local cntEnd = str:find( startmarker( pat ), cntBeg, true )
      if cntEnd then
         local content = str:sub( cntBeg, cntEnd-2 )
         tab[ name ] = content
         idx = cntEnd
      else
         local content = str:sub( cntBeg )
         tab[ name ] = content
         idx = str:len()
      end

   end

   return tab
end

return readmxtfile

Example

local t = require( "taptest" )
local countlen = require( "countlen" )
local readmxtfile = require( "readmxtfile" )
local trim = require( "trim" )
local writefile = require( "writefile" )

---------------------------------------- prebuild ------------------------------

t( writefile( "readmxtfile.mxt", trim( [[
//---------------------------------------------------------------- user.json -->
{
   "user": "alucard",
   "password": "C:SotN1997"
}
//--------------------------------------------------------------- connection.ini
// comment line that is not part of the ini file,
// comment lines will be joined with a space character
//
// empty comment lines will generate a newline character in the comment
//----------------------------------------------------------------------------->
request: GET

[url]
schema=http
host=localhost
port=8080
path=/db/add
// user.pgp --> XYZ
-----BEGIN PGP MESSAGE-----

hQEMA8p144+Gi+YpAQf/VeFG9Zb+8w9aldWll8n2g3jqpE613LKg2XAJgwXQmSQL
R4O+TlQakJ+Mz5vM4IxxubPgYCyt6cyL7qM3oJIuk7vsqMbl5t7c/dOfXjj7goIC
IskIX+9e5qrr8jRG/KZYSdBJtFEI9oNtZTLlnv3yeV3OWNTbUnjdTWrk/h1kavJE
5psOaTgH+Yg0utcF9Y0AqTo/o6EmiAn+uQlE5l9GTSzq51jRNiMoZRaXfUeznneF
SDn/eFve7VlLV60j8LcXSrXgiIXEYi9ZgvWHHV+h9yorQXu24fgrEd0AhE/adiJm
dzEHVCb+Q0i0p14hE2QQYdDE0zLxZN+FZJy/MiWwHtLA0QFZ+Zh47Zmiq14WyMPp
4ASQ/wNpwmZmpsiKDweUTlng3MTjifopmTeglPmRKsIOvUbTnA3yetznViugSYrA
jPuSltUZpdLTrOPrOrbPorxKmurKmswZje1hoXIrpPN2KzTnA0UNH6GKOnMjLtRH
uXMlS3q/GkIcXYDJIVFsEU3dGWMJFOtF4HPlyHmB8Gko8cDep6ugPbgJt8LBu3+p
zE00pkAd4Kf7yodSUR6mRJm5qK+vqp7dnkZd/WhTNRihMoqRY2oKiH2rHjFSa76s
D8nD4suo6ckVzYGJpknGSIAwaCFlW0aqR/3SWO4wi6ibbfub8LA73V90Ll3/S/Ph
xU15HYmdCATnVX1sp1PWmyz972bMvl8txyIKMUueVw+w0C19ZTfWXjuFSguF7zt7
RY+I3to2lbyVJbcI9Dyz04GOJZ2vIhG9eq65FxeweAKDa7L+iH1NA5L2lYd9DEr1
ro/CU6vIqkOSNRUrNYDwqz1g3Z3eAQB/8t9Y4WsV4KL0M229rsFrtl26i7+quYfg
uuTd
=WxK9
-----END PGP MESSAGE-----
//-XYZ- hello-world.h -->
//---------------------------------------------------------- hello-world.c --> X
// this is part of hello-world.c
#include<stdio.h>

int main(void) {
    printf("Hello World\n");
    return 0;
}]] ) ), true )

---------------------------------------- test ----------------------------------

tab, err = readmxtfile( "readmxtfile.mxt" )

t( countlen( tab ), 5 )

t( tab[ "user.json" ], [[{
   "user": "alucard",
   "password": "C:SotN1997"
}]] )

t( tab[ "connection.ini" ], [[request: GET

[url]
schema=http
host=localhost
port=8080
path=/db/add]] )

t( tab[ "user.pgp" ], [[-----BEGIN PGP MESSAGE-----

hQEMA8p144+Gi+YpAQf/VeFG9Zb+8w9aldWll8n2g3jqpE613LKg2XAJgwXQmSQL
R4O+TlQakJ+Mz5vM4IxxubPgYCyt6cyL7qM3oJIuk7vsqMbl5t7c/dOfXjj7goIC
IskIX+9e5qrr8jRG/KZYSdBJtFEI9oNtZTLlnv3yeV3OWNTbUnjdTWrk/h1kavJE
5psOaTgH+Yg0utcF9Y0AqTo/o6EmiAn+uQlE5l9GTSzq51jRNiMoZRaXfUeznneF
SDn/eFve7VlLV60j8LcXSrXgiIXEYi9ZgvWHHV+h9yorQXu24fgrEd0AhE/adiJm
dzEHVCb+Q0i0p14hE2QQYdDE0zLxZN+FZJy/MiWwHtLA0QFZ+Zh47Zmiq14WyMPp
4ASQ/wNpwmZmpsiKDweUTlng3MTjifopmTeglPmRKsIOvUbTnA3yetznViugSYrA
jPuSltUZpdLTrOPrOrbPorxKmurKmswZje1hoXIrpPN2KzTnA0UNH6GKOnMjLtRH
uXMlS3q/GkIcXYDJIVFsEU3dGWMJFOtF4HPlyHmB8Gko8cDep6ugPbgJt8LBu3+p
zE00pkAd4Kf7yodSUR6mRJm5qK+vqp7dnkZd/WhTNRihMoqRY2oKiH2rHjFSa76s
D8nD4suo6ckVzYGJpknGSIAwaCFlW0aqR/3SWO4wi6ibbfub8LA73V90Ll3/S/Ph
xU15HYmdCATnVX1sp1PWmyz972bMvl8txyIKMUueVw+w0C19ZTfWXjuFSguF7zt7
RY+I3to2lbyVJbcI9Dyz04GOJZ2vIhG9eq65FxeweAKDa7L+iH1NA5L2lYd9DEr1
ro/CU6vIqkOSNRUrNYDwqz1g3Z3eAQB/8t9Y4WsV4KL0M229rsFrtl26i7+quYfg
uuTd
=WxK9
-----END PGP MESSAGE-----]] )

t( tab[ "hello-world.h" ], "" )

t( tab[ "hello-world.c" ], [[// this is part of hello-world.c
#include<stdio.h>

int main(void) {
    printf("Hello World\n");
    return 0;
}]] )

---------------------------------------- cleanup -------------------------------
os.remove( "readmxtfile.mxt" )

t()

Inspired by