const char memprof_lua[] =
"-- A tool for parsing and visualisation of LuaJIT's memory\n"
"-- profiler output.\n"
"--\n"
"-- TODO:\n"
"-- * Think about callgraph memory profiling for complex\n"
"--   table reallocations\n"
"-- * Nicer output, probably an HTML view\n"
"-- * Demangling of C symbols\n"
"--\n"
"-- Major portions taken verbatim or adapted from the LuaVela.\n"
"-- Copyright (C) 2015-2019 IPONWEB Ltd.\n"
"\n"
"local bufread = require \"utils.bufread\"\n"
"local memprof = require \"memprof.parse\"\n"
"local symtab = require \"utils.symtab\"\n"
"local view = require \"memprof.humanize\"\n"
"\n"
"local stdout, stderr = io.stdout, io.stderr\n"
"local match, gmatch = string.match, string.gmatch\n"
"\n"
"-- Program options.\n"
"local opt_map = {}\n"
"\n"
"function opt_map.help()\n"
"  stdout:write [[\n"
"luajit-parse-memprof - parser of the memory usage profile collected\n"
"                       with LuaJIT's memprof.\n"
"\n"
"SYNOPSIS\n"
"\n"
"luajit-parse-memprof [options] memprof.bin\n"
"\n"
"Supported options are:\n"
"\n"
"  --help                            Show this help and exit\n"
"]]\n"
"  os.exit(0)\n"
"end\n"
"\n"
"-- Print error and exit with error status.\n"
"local function opterror(...)\n"
"  stderr:write(\"luajit-parse-memprof.lua: ERROR: \", ...)\n"
"  stderr:write(\"\\n\")\n"
"  os.exit(1)\n"
"end\n"
"\n"
"-- Parse single option.\n"
"local function parseopt(opt, args)\n"
"  local opt_current = #opt == 1 and \"-\"..opt or \"--\"..opt\n"
"  local f = opt_map[opt]\n"
"  if not f then\n"
"    opterror(\"unrecognized option `\", opt_current, \"'. Try `--help'.\\n\")\n"
"  end\n"
"  f(args)\n"
"end\n"
"\n"
"-- Parse arguments.\n"
"local function parseargs(args)\n"
"  -- Process all option arguments.\n"
"  args.argn = 1\n"
"  repeat\n"
"    local a = args[args.argn]\n"
"    if not a then\n"
"      break\n"
"    end\n"
"    local lopt, opt = match(a, \"^%-(%-\?)(.+)\")\n"
"    if not opt then\n"
"      break\n"
"    end\n"
"    args.argn = args.argn + 1\n"
"    if lopt == \"\" then\n"
"      -- Loop through short options.\n"
"      for o in gmatch(opt, \".\") do\n"
"        parseopt(o, args)\n"
"      end\n"
"    else\n"
"      -- Long option.\n"
"      parseopt(opt, args)\n"
"    end\n"
"  until false\n"
"\n"
"  -- Check for proper number of arguments.\n"
"  local nargs = #args - args.argn + 1\n"
"  if nargs ~= 1 then\n"
"    opt_map.help()\n"
"  end\n"
"\n"
"  -- Translate a single input file.\n"
"  -- TODO: Handle multiple files\?\n"
"  return args[args.argn]\n"
"end\n"
"\n"
"local function dump(inputfile)\n"
"  local reader = bufread.new(inputfile)\n"
"  local symbols = symtab.parse(reader)\n"
"  local events = memprof.parse(reader, symbols)\n"
"\n"
"  stdout:write(\"ALLOCATIONS\", \"\\n\")\n"
"  view.render(events.alloc, symbols)\n"
"  stdout:write(\"\\n\")\n"
"\n"
"  stdout:write(\"REALLOCATIONS\", \"\\n\")\n"
"  view.render(events.realloc, symbols)\n"
"  stdout:write(\"\\n\")\n"
"\n"
"  stdout:write(\"DEALLOCATIONS\", \"\\n\")\n"
"  view.render(events.free, symbols)\n"
"  stdout:write(\"\\n\")\n"
"\n"
"  os.exit(0)\n"
"end\n"
"\n"
"-- FIXME: this script should be application-independent.\n"
"local args = {...}\n"
"if #args == 1 and args[1] == \"memprof\" then\n"
"  return dump\n"
"else\n"
"  dump(parseargs(args))\n"
"end\n"
""
;
