about summary refs log tree commit diff stats
path: root/adapter
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-10-13 20:39:52 +0200
committerbptato <nincsnevem662@gmail.com>2024-10-13 21:09:18 +0200
commit4fb37158efa37a01a2ecc86be024c22202a879d0 (patch)
treed8dd7032eb37ef2e0aabbedf32968b7e3c0ee971 /adapter
parentb773f053478dfae83719417b434f9e232d374b0b (diff)
downloadchawan-4fb37158efa37a01a2ecc86be024c22202a879d0.tar.gz
dirlist2html: fix heisenbug, refactor
so it turns out you *can't* just deref refcounted strings through
a ptr...

the entire algorithm was a mess anyway, so I've just re-done the sorting
with refc.
Diffstat (limited to 'adapter')
-rw-r--r--adapter/format/dirlist2html.nim146
1 files changed, 74 insertions, 72 deletions
diff --git a/adapter/format/dirlist2html.nim b/adapter/format/dirlist2html.nim
index a64eec9a..08981f20 100644
--- a/adapter/format/dirlist2html.nim
+++ b/adapter/format/dirlist2html.nim
@@ -9,9 +9,11 @@ import utils/twtstr
 type DirlistItemType = enum
   ditFile, ditLink, ditDir
 
-type DirlistItem = object
-  name: string
-  modified: string
+type DirlistItem = ref object
+  name: string # real name
+  dname: string # display name
+  width: int # display name width
+  modified: string # date last modified
   case t: DirlistItemType
   of ditLink:
     linkto: string
@@ -20,30 +22,9 @@ type DirlistItem = object
   of ditDir:
     discard
 
-type NameWidthTuple = tuple[name: string, width: int, item: ptr DirlistItem]
-
-func makeDirlist(items: seq[DirlistItem]): string =
-  var names: seq[NameWidthTuple] = @[]
-  var maxw = 20
+proc printDirlist(f: File; items: seq[DirlistItem]; maxw: int) =
+  f.writeLine("<a href=\"../\">[Upper Directory]</a>")
   for item in items:
-    var name = item.name
-    if item.t == ditLink:
-      name &= '@'
-    elif item.t == ditDir:
-      name &= '/'
-    let w = name.width()
-    maxw = max(w, maxw)
-    names.add((name, w, unsafeAddr item))
-  names.sort(proc(a, b: NameWidthTuple): int =
-    if a.item.t == ditDir and b.item.t != ditDir:
-      return -1
-    if a.item.t != ditDir and b.item.t == ditDir:
-      return 1
-    return cmp(a.name, b.name)
-  )
-  var outs = "<A HREF=\"../\">[Upper Directory]</A>\n"
-  for (name, width, itemp) in names.mitems:
-    let item = itemp[]
     var path = percentEncode(item.name, PathPercentEncodeSet)
     if item.t == ditLink:
       if item.linkto.len > 0 and item.linkto[^1] == '/':
@@ -51,7 +32,8 @@ func makeDirlist(items: seq[DirlistItem]): string =
         path &= '/'
     elif item.t == ditDir:
       path &= '/'
-    var line = "<A HREF=\"" & path & "\">" & htmlEscape(name) & "</A>"
+    var line = "<a href=\"" & path & "\">" & htmlEscape(item.dname) & "</a>"
+    var width = item.width
     while width <= maxw:
       if width mod 2 == 0:
         line &= ' '
@@ -65,45 +47,25 @@ func makeDirlist(items: seq[DirlistItem]): string =
       line &= ' ' & convertSize(item.nsize)
     elif item.t == ditLink:
       line &= " -> " & htmlEscape(item.linkto)
-    outs &= line & '\n'
-  return outs
+    f.writeLine(line)
 
 proc usage() =
   stderr.write("Usage: dirlist2html [-t title]\n")
   quit(1)
 
-proc main() =
-  # parse args
-  let H = paramCount()
-  var i = 1
-  var title = ""
-  while i <= H:
-    let s = paramStr(i)
-    if s == "":
-      inc i
-    if s[0] != '-':
-      usage()
-    for j in 1 ..< s.len:
-      case s[j]
-      of 't':
-        inc i
-        if i > H: usage()
-        title = paramStr(i).percentDecode()
-      else:
-        usage()
-    inc i
-  if title != "":
-    stdout.write("""
-<!DOCTYPE html>
-<head>
-<title>""" & title.htmlEscape() & """</title>
-</head>
-<body>
-<h1>""" & title.htmlEscape() & """</h1>
-<pre>""")
-  var items: seq[DirlistItem] = @[]
+proc addItem(items: var seq[DirlistItem]; item: DirlistItem; maxw: var int) =
+  if item.t == ditDir:
+    item.name &= '/'
+  item.dname = item.name
+  if item.t == ditLink:
+    item.dname &= '@'
+  item.width = item.dname.width()
+  maxw = max(item.width, maxw)
+  items.add(item)
+
+proc parseInput(f: File; items: var seq[DirlistItem]; maxw: var int) =
   var line: string
-  while stdin.readLine(line):
+  while f.readLine(line):
     if line.len == 0: continue
     var i = 10 # permission
     template skip_till_space =
@@ -111,15 +73,13 @@ proc main() =
         inc i
     # link count
     i = line.skipBlanks(i)
-    while i < line.len and line[i] in AsciiDigit:
-      inc i
+    skip_till_space
     # owner
     i = line.skipBlanks(i)
     skip_till_space
     # group
     i = line.skipBlanks(i)
-    while i < line.len and line[i] != ' ':
-      inc i
+    skip_till_space
     # size
     i = line.skipBlanks(i)
     var sizes = ""
@@ -141,32 +101,74 @@ proc main() =
     if line[^1] == '\r':
       dec j
     let name = line.substr(i, j - 1)
-    if name == "." or name == "..": continue
+    if name == "." or name == "..":
+      continue
     case line[0]
     of 'l': # link
       let linki = name.find(" -> ")
       let linkfrom = name.substr(0, linki - 1)
       let linkto = name.substr(linki + 4) # you?
-      items.add(DirlistItem(
+      items.addItem(DirlistItem(
         t: ditLink,
         name: linkfrom,
         modified: dates,
         linkto: linkto
-      ))
+      ), maxw)
     of 'd': # directory
-      items.add(DirlistItem(
+      items.addItem(DirlistItem(
         t: ditDir,
         name: name,
         modified: dates
-      ))
+      ), maxw)
     else: # file
-      items.add(DirlistItem(
+      items.addItem(DirlistItem(
         t: ditFile,
         name: name,
         modified: dates,
         nsize: int(nsize)
-      ))
-  stdout.write(makeDirlist(items))
+      ), maxw)
+
+proc parseArgs(title: var string) =
+  let H = paramCount()
+  var i = 1
+  while i <= H:
+    let s = paramStr(i)
+    if s == "":
+      inc i
+    if s[0] != '-':
+      usage()
+    for j in 1 ..< s.len:
+      case s[j]
+      of 't':
+        inc i
+        if i > H: usage()
+        title = paramStr(i).percentDecode()
+      else:
+        usage()
+    inc i
+
+proc main() =
+  var title = ""
+  parseArgs(title)
+  stdout.write("""
+<!DOCTYPE html>
+<head>
+<title>""" & title.htmlEscape() & """</title>
+</head>
+<body>
+<h1>""" & title.htmlEscape() & """</h1>
+<pre>""")
+  var items: seq[DirlistItem] = @[]
+  var maxw = 20
+  stdin.parseInput(items, maxw)
+  items.sort(proc(a, b: DirlistItem): int =
+    if a.t == ditDir and b.t != ditDir:
+      return -1
+    if a.t != ditDir and b.t == ditDir:
+      return 1
+    return cmp(a.dname, b.dname)
+  )
+  stdout.printDirlist(items, maxw)
   stdout.write("</pre></body>")
 
 main()