summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/diadia/diadia.lua
blob: 81d668499e7d635739c3163aaf533d40f38abe37 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
#!/usr/bin/env texlua
--
-- diadia [options]
--
-- loads and processes a diadia data file
--
-- License: LPPL
--
local version = "v1.0 (2015/05/15)"

local infile = ""
local outfile = ""
local mode = "*"
local startdate = ""
local enddate = ""
local columns = ""
local data = {}
function pversion()
  print("diadia.lua " .. version)
  print("(C) Josef Kleber 2015   License: LPPL")
  os.exit(0)
end
function phelp()
  print([[
diadia.lua [options]

 allows you to

 - cut a chunk out of the data file
   e.g.: -i in.dat -o out.dat -s YYYY-MM-DD -e YYYY-MM-DD

 - compose a new data file based on given columns of an
   existing data file
   e.g.: -i in.dat -o out.dat -c 1,2

 - create a new data file with date and value (1st and
   2nd column of existing file) and added value average
   columns of the last 7, 14, 30, 60 and 90 days
   e.g.: -i in.dat -o out.dat [-s YYYY-MM-DD -e YYYY-MM-DD]

 Options:

 -m  specify the mode (cut|compose|average)

 -i  specify the input file

 -o  specify the output file

 -c  specify the columns for compose mode

 -s  specify the start date (YYYY-MM-DD) in
     cut and average mode

 -e  specify the end date

 -v  prints version information

 -h  prints help information

]])
  pversion()
end
function check_date(date)
  if string.find(date, "(%d%d%d%d)-(%d%d)-(%d%d)") == nil
  then
    io.stderr:write ("Error 21: wrong date format (YYYY-MM-DD)\n")
    os.exit(11)
  end
end
function parse_date(date)
  return string.match(date, "(%d%d%d%d)%-(%d%d)%-(%d%d)")
end
function parse_dateinline(line)
  return string.match(line, "(%d%d%d%d%-%d%d%-%d%d)")
end
function daystring(unixtime)
  return os.date("%Y-%m-%d", unixtime)
end
function unixtime(year,month,day)
  return os.time{year=year, month=month, day=day}
end
function round(number)
  return math.floor(number+0.5)
end
function ptd(value)
  local val = tostring(value)
  local slen = string.len(val)
  if slen == 3
  then
    return val
  else
    return val .. " "
  end
end
function calc_avg(data,date,days)
  local sum = 0
  local wdays = 0
  local wday
  local endday = unixtime(parse_date(date))
  local startday = endday - 60*60*24*(days-1)
  while startday <= endday
  do
    wday = daystring(startday)
    if data[wday] ~= nil
    then
      sum = sum + data[wday]
      wdays = wdays + 1
    end
    startday = startday + 60*60*24
  end
  if wdays == 0
  then
    return "nan"
  else
    return tostring(round(sum/wdays))
  end
end
function read_data(file)
  local data = {}
  local date
  local startdate
  local enddate
  local dat
  local firstline = true
  for line in io.lines(file)
  do
    if string.match(line, "date")
    then
    else
      date, dat = string.match(line, "(%d%d%d%d%-%d%d%-%d%d)%s+(%S+)")
      if firstline == true
      then
        startdate = date
        firstline = false
      end
      if dat ~= "nan" and dat ~= "{}" and dat ~= ""
      then
        data[date] = dat
      end
    end
  end
  enddate = date
  return data,startdate,enddate
end
function write_avg_file(data,file,startdate,enddate)
  local sdate
  local edate
  local wday
  sdate = unixtime(parse_date(startdate))
  edate = unixtime(parse_date(enddate))
  outfile = assert(io.open(file, "w"))
  outfile:write("date        value avg07 avg14 avg30 avg60 avg90")
  while sdate <= edate+7200
  do
    wday = daystring(sdate)
    if data[wday] ~= nil
    then
      outfile:write("\n" .. wday .. "  "
                    .. ptd(data[wday]) .. "   "
                    .. ptd(calc_avg(data,wday,7)) .. "   "
                    .. ptd(calc_avg(data,wday,14)) .. "   "
                    .. ptd(calc_avg(data,wday,30)) .. "   "
                    .. ptd(calc_avg(data,wday,60)) .. "   "
                    .. ptd(calc_avg(data,wday,90)))
    end
    sdate = sdate + 60*60*24
  end
  outfile:close()
end
do
  local newarg = {}
  local i, limit = 1, #arg
  while (i <= limit) do
    if arg[i] == "-i" then
      infile = arg[i+1]
      i = i + 1
    elseif arg[i] == "-o" then
      outfile = arg[i+1]
      i = i + 1
    elseif arg[i] == "-s" then
      startdate = arg[i+1]
      i = i + 1
    elseif arg[i] == "-e" then
      enddate = arg[i+1]
      i = i + 1
    elseif arg[i] == "-c" then
      columns = arg[i+1]
      i = i + 1
    elseif arg[i] == "-m" then
      mode = arg[i+1]
      i = i + 1
    elseif arg[i] == "-v" then
      pversion()
    elseif arg[i] == "-h" then
      phelp()
    else
      newarg[#newarg+1] = arg[i]
    end
    i = i + 1
  end
  arg = newarg
end
if mode == "average"
then
  local startd
  local endd

  print("set mode to " .. mode)
  print("reading data file " .. infile)
  data,startd,endd = read_data(infile)
  if startdate ~= ""
  then
    startd = startdate
  end
  if enddate ~= ""
  then
    endd = enddate
  end
  print("writing data file " .. outfile)
  write_avg_file(data,outfile,startd,endd)
  os.exit(0)
end
if mode == "compose"
then
  local row = 0
  local column = 0
  local ofile
  local cols

  print("set mode to " .. mode)
  print("reading data file " .. infile)
  for line in io.lines(infile)
  do
    row = row + 1
    data[row] = {}
    column = 0
    for value in string.gmatch(line, "%S+")
    do
      column = column + 1
      data[row][column] = value
    end
  end
  cols = assert(load("return table.concat({"..columns:gsub("%d+","(...)[%0]").."},'  ')"))
  ofile = assert(io.open(outfile, "w"))
  print("writing data file " .. outfile)
  for irow = 1,row
  do
    if irow == row
    then
      ofile:write(cols(data[irow]))
    else
      ofile:write(cols(data[irow]).."\n")
    end
  end
  ofile:close()
  os.exit(0)
end
if mode == "cut"
then
  local ofile
  local date
  local sdate
  local edate
  local cdate

  check_date(startdate)
  check_date(enddate)
  sdate = unixtime(parse_date(startdate))
  edate = unixtime(parse_date(enddate))
  print("set mode to " .. mode)
  print("reading data file " .. infile)
  print("writing data file " .. outfile)
  ofile = assert(io.open(outfile, "w"))
  for line in io.lines(infile)
  do
    if string.match(line, "date")
    then
      ofile:write(line)
    else
      date = parse_dateinline(line)
      cdate = unixtime(parse_date(date))
      if cdate >= sdate and cdate <= edate
      then
        ofile:write("\n" .. line)
      end
    end
  end
  ofile:close()
  os.exit(0)
end
if mode == "*"
then
  io.stderr:write ("Error 11: no mode specified!")
  os.exit(11)
else
  io.stderr:write ("Error 12: invalid mode " .. mode)
  os.exit(12)
end