summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/core-con.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/core-con.lua')
-rw-r--r--tex/context/base/mkiv/core-con.lua402
1 files changed, 305 insertions, 97 deletions
diff --git a/tex/context/base/mkiv/core-con.lua b/tex/context/base/mkiv/core-con.lua
index 9617849d0..276561ad4 100644
--- a/tex/context/base/mkiv/core-con.lua
+++ b/tex/context/base/mkiv/core-con.lua
@@ -24,6 +24,7 @@ local utfchar, utfbyte = utf.char, utf.byte
local tonumber, tostring, type, rawset = tonumber, tostring, type, rawset
local P, S, R, Cc, Cf, Cg, Ct, Cs, C, V, Carg = lpeg.P, lpeg.S, lpeg.R, lpeg.Cc, lpeg.Cf, lpeg.Cg, lpeg.Ct, lpeg.Cs, lpeg.C, lpeg.V, lpeg.Carg
local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
+local div, mod = math.div, math.mod
local context = context
local commands = commands
@@ -793,115 +794,303 @@ implement {
arguments = { "string", "integer" }
}
--- Well, since the one asking for this didn't test it the following code is not
--- enabled.
---
--- -- This Lua version is based on a Javascript by Behdad Esfahbod which in turn
--- -- is based on GPL'd code by Roozbeh Pournader of the The FarsiWeb Project
--- -- Group: http://www.farsiweb.info/jalali/jalali.js.
--- --
--- -- We start tables at one, I kept it zero based in order to stay close to
--- -- the original.
--- --
--- -- Conversion by Hans Hagen
-
-local g_days_in_month = { [0] = 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
-local j_days_in_month = { [0] = 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 }
-
-local div = math.div
-local mod = math.mod
-
-function gregorian_to_jalali(gy,gm,gd)
- local jy, jm, jd, g_day_no, j_day_no, j_np, i
- gy, gm, gd = gy - 1600, gm - 1, gd - 1
- g_day_no = 365*gy + div((gy+3),4) - div((gy+99),100) + div((gy+399),400)
- i = 0
- while i < gm do
- g_day_no = g_day_no + g_days_in_month[i]
- i = i + 1
+-- hebrew data conversion
+
+local gregorian_to_hebrew do
+
+ -- The next code is based on the c code at https://github.com/hebcal/hebcal
+ --
+ -- Hebcal : A Jewish Calendar Generator
+ -- Copyright : 1994 - 2004 Danny Sadinoff, 2002 Michael J. Radwin
+ -- License : GPL
+ --
+ -- Because we only need simple dates, we use part of the code. There is more
+ -- at that github place.
+ --
+ -- The number of days elapsed between the Gregorian date 12/31/1 BC and DATE.
+ -- The Gregorian date Sunday, December 31, 1 BC is imaginary.
+ --
+ -- The code is luafied and a little different because we have no assignments
+ -- in loops and such. We could speed up the code but then we divert from the
+ -- original. This is not that critical anyway.
+
+ local NISAN = 1
+ local IYYAR = 2
+ local SIVAN = 3
+ local TAMUZ = 4
+ local AV = 5
+ local ELUL = 6
+ local TISHREI = 7
+ local CHESHVAN = 8
+ local KISLEV = 9
+ local TEVET = 10
+ local SHVAT = 11
+ local ADAR_I = 12
+ local ADAR_II = 13
+
+ local mmap = {
+ KISLEV,
+ TEVET,
+ SHVAT,
+ ADAR_I,
+ NISAN,
+ IYYAR,
+ SIVAN,
+ TAMUZ,
+ TISHREI,
+ TISHREI,
+ TISHREI,
+ CHESHVAN
+ }
+
+ local function greg2abs(year,month,day)
+ local y = year - 1
+ return y * 365 + div(y,4)- div(y,100) + div(y,400) + os.nofdays(year,month,day)
end
- if (gm>1 and ((gy%4==0 and gy%100~=0) or (gy%400==0))) then
- g_day_no = g_day_no + 1
+
+ local function abs2greg(abs)
+
+ local d0 = abs - 1
+
+ local n400 = div(d0, 146097)
+ local d1 = mod(d0, 146097)
+ local n100 = div(d1, 36524)
+ local d2 = mod(d1, 36524)
+ local n4 = div(d2, 1461)
+ local d3 = mod(d2, 1461)
+ local n1 = div(d3, 365)
+
+ local day = mod(d3, 365) + 1
+ local year = 400 * n400 + 100 * n100 + 4 * n4 + n1
+
+ if n100 == 4 or n1 == 4 then
+ return year, 12, 31
+ else
+ year = year + 1
+ month = 1
+ while true do
+ local mlen = os.nofdays(year,month)
+ if mlen < day then
+ day = day - mlen
+ month = month + 1
+ else
+ break
+ end
+ end
+ return year, month, day
+ end
end
- g_day_no = g_day_no + gd
- j_day_no = g_day_no - 79
- j_np = div(j_day_no,12053)
- j_day_no = mod(j_day_no,12053)
- jy = 979 + 33*j_np + 4*div(j_day_no,1461)
- j_day_no = mod(j_day_no,1461)
- if j_day_no >= 366 then
- jy = jy + div((j_day_no-1),365)
- j_day_no = mod((j_day_no-1),365)
+
+ local function hebrew_leapyear(year)
+ return mod(1 + year * 7, 19) < 7
end
- i = 0
- while i < 11 and j_day_no >= j_days_in_month[i] do
- j_day_no = j_day_no - j_days_in_month[i]
- i = i + 1
+
+ local function hebrew_months_in_year(year)
+ return hebrew_leapyear(year) and 13 or 12
+ end
+
+ local function hebrew_elapsed_days(year)
+ local y = year - 1
+ local m_elapsed = 235 * div(y,19) + 12 * mod(y,19) + div(((mod(y,19) * 7) + 1),19)
+ local p_elapsed = 204 + 793 * mod(m_elapsed,1080)
+ local h_elapsed = 5 + 12 * m_elapsed + 793 * div(m_elapsed,1080) + div(p_elapsed,1080)
+ local parts = mod(p_elapsed,1080) + 1080 * mod(h_elapsed,24)
+ local day = 1 + 29 * m_elapsed + div(h_elapsed,24)
+ local d = mod(day,7)
+ local alt_day = day
+ if parts >= 19440
+ or (parts >= 9924 and d == 2 and not (hebrew_leapyear(year)))
+ or (parts >= 16789 and d == 1 and hebrew_leapyear(y )) then
+ alt_day = alt_day + 1
+ end
+ d = mod(alt_day,7)
+ if d == 0 or d == 3 or d == 5 then
+ alt_day = alt_day + 1
+ end
+ return alt_day
end
- jm = i + 1
- jd = j_day_no + 1
- return jy, jm, jd
-end
-function jalali_to_gregorian(jy,jm,jd)
- local gy, gm, gd, g_day_no, j_day_no, leap, i
- jy, jm, jd = jy - 979, jm - 1, jd - 1
- j_day_no = 365*jy + div(jy,33)*8 + div((mod(jy,33)+3),4)
- for i=0,jm-1,1 do
- j_day_no = j_day_no + j_days_in_month[i]
+ local function days_in_hebrew_year(year)
+ return hebrew_elapsed_days(year + 1) - hebrew_elapsed_days(year)
end
- j_day_no = j_day_no + jd
- g_day_no = j_day_no + 79
- gy = 1600 + 400*div(g_day_no,146097)
- g_day_no = mod(g_day_no, 146097)
- leap = 1
- if g_day_no >= 36525 then
- g_day_no = g_day_no - 1
- gy = gy + 100*div(g_day_no,36524)
- g_day_no = mod(g_day_no, 36524)
- if g_day_no >= 365 then
- g_day_no = g_day_no + 1
+
+ local function long_cheshvan(year)
+ return mod(days_in_hebrew_year(year),10) == 5
+ end
+
+ local function short_kislev(year)
+ return mod(days_in_hebrew_year(year),10) == 3
+ end
+
+ local function max_days_in_heb_month(month,year)
+ if month == IYYAR or month == TAMUZ or month == ELUL or month == TEVET or month == ADAR_II or
+ (month == ADAR_I and not hebrew_leapyear(year)) or
+ (month == CHESHVAN and not long_cheshvan(year)) or
+ (month == KISLEV and short_kislev (year)) then
+ return 29
else
- leap = 0
+ return 30
end
end
- gy = gy + 4*div(g_day_no,1461)
- g_day_no = mod(g_day_no, 1461)
- if g_day_no >= 366 then
- leap = 0
- g_day_no = g_day_no - 1
- gy = gy + div(g_day_no, 365)
- g_day_no = mod(g_day_no, 365)
- end
- i = 0
- while true do
- local d = g_days_in_month[i] + ((i == 1 and leap) or 0)
- if g_day_no >= d then
- g_day_no = g_day_no - d
- i = i + 1
+
+ local function hebrew2abs(year,month,day)
+ if month < TISHREI then
+ for m=TISHREI, hebrew_months_in_year(year), 1 do
+ day = day + max_days_in_heb_month(m,year)
+ end
+ for m=NISAN, month - 1, 1 do
+ day = day + max_days_in_heb_month(m,year)
+ end
else
- break
+ for m=TISHREI, month - 1, 1 do
+ day = day + max_days_in_heb_month(m,year)
+ end
+ end
+ return hebrew_elapsed_days(year) - 1373429 + day
+ end
+
+ local function abs2hebrew(abs)
+ local yy, mm, dd = abs2greg(abs)
+ local day = 1
+ local month = TISHREI
+ local year = 3760 + yy
+ while abs >= hebrew2abs(year+1,month,day) do
+ year = year + 1
+ end
+ if year >= 4635 and year < 10666 then
+ month = mmap[mm]
+ end
+ while abs > hebrew2abs(year,month,max_days_in_heb_month(month,year)) do
+ month = mod(month,hebrew_months_in_year(year)) + 1
end
+ day = abs - hebrew2abs(year,month,1) + 1
+ return year, month, day
+ end
+
+ -- months = { "ניסן" "אייר" "סיון" "תמוז" "אב" "אלול" "תשרי" "חשון" "כסלו" "טבת" "שבט" }
+
+ gregorian_to_hebrew = function(y,m,d)
+ return abs2hebrew(greg2abs(y,m,d))
end
- gm = i + 1
- gd = g_day_no + 1
- return gy, gm, gd
+
+ converters.gregorian_to_hebrew = gregorian_to_hebrew
+
end
--- local function test(yg,mg,dg,yj,mj,dj)
--- local y1, m1, d1 = jalali_to_gregorian(yj,mj,dj)
--- local y2, m2, d2 = gregorian_to_jalali(yg,mg,dg)
--- print(y1 == yg and m1 == mg and d1 == dg, yg,mg,dg, y1,m1,d1)
--- print(y2 == yj and m2 == mj and d2 == dj, yj,mj,dj, y2,m2,d2)
--- end
+local gregorian_to_jalali, jalali_to_gregorian do
+
+ -- Well, since the one asking for this didn't test it the following code is not
+ -- enabled.
+ --
+ -- -- This Lua version is based on a Javascript by Behdad Esfahbod which in turn
+ -- -- is based on GPL'd code by Roozbeh Pournader of the The FarsiWeb Project
+ -- -- Group: http://www.farsiweb.info/jalali/jalali.js.
+ -- --
+ -- -- We start tables at one, I kept it zero based in order to stay close to
+ -- -- the original.
+ -- --
+ -- -- Conversion by Hans Hagen
+
+ local g_days_in_month = { [0] = 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+ local j_days_in_month = { [0] = 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 }
+
+
+ gregorian_to_jalali = function(gy,gm,gd)
+ local jy, jm, jd, g_day_no, j_day_no, j_np, i
+ gy, gm, gd = gy - 1600, gm - 1, gd - 1
+ g_day_no = 365*gy + div((gy+3),4) - div((gy+99),100) + div((gy+399),400)
+ i = 0
+ while i < gm do
+ g_day_no = g_day_no + g_days_in_month[i]
+ i = i + 1
+ end
+ if (gm>1 and ((gy%4==0 and gy%100~=0) or (gy%400==0))) then
+ g_day_no = g_day_no + 1
+ end
+ g_day_no = g_day_no + gd
+ j_day_no = g_day_no - 79
+ j_np = div(j_day_no,12053)
+ j_day_no = mod(j_day_no,12053)
+ jy = 979 + 33*j_np + 4*div(j_day_no,1461)
+ j_day_no = mod(j_day_no,1461)
+ if j_day_no >= 366 then
+ jy = jy + div((j_day_no-1),365)
+ j_day_no = mod((j_day_no-1),365)
+ end
+ i = 0
+ while i < 11 and j_day_no >= j_days_in_month[i] do
+ j_day_no = j_day_no - j_days_in_month[i]
+ i = i + 1
+ end
+ jm = i + 1
+ jd = j_day_no + 1
+ return jy, jm, jd
+ end
+
+ jalali_to_gregorian = function(jy,jm,jd)
+ local gy, gm, gd, g_day_no, j_day_no, leap, i
+ jy, jm, jd = jy - 979, jm - 1, jd - 1
+ j_day_no = 365*jy + div(jy,33)*8 + div((mod(jy,33)+3),4)
+ for i=0,jm-1,1 do
+ j_day_no = j_day_no + j_days_in_month[i]
+ end
+ j_day_no = j_day_no + jd
+ g_day_no = j_day_no + 79
+ gy = 1600 + 400*div(g_day_no,146097)
+ g_day_no = mod(g_day_no, 146097)
+ leap = 1
+ if g_day_no >= 36525 then
+ g_day_no = g_day_no - 1
+ gy = gy + 100*div(g_day_no,36524)
+ g_day_no = mod(g_day_no, 36524)
+ if g_day_no >= 365 then
+ g_day_no = g_day_no + 1
+ else
+ leap = 0
+ end
+ end
+ gy = gy + 4*div(g_day_no,1461)
+ g_day_no = mod(g_day_no, 1461)
+ if g_day_no >= 366 then
+ leap = 0
+ g_day_no = g_day_no - 1
+ gy = gy + div(g_day_no, 365)
+ g_day_no = mod(g_day_no, 365)
+ end
+ i = 0
+ while true do
+ local d = g_days_in_month[i] + ((i == 1 and leap) or 0)
+ if g_day_no >= d then
+ g_day_no = g_day_no - d
+ i = i + 1
+ else
+ break
+ end
+ end
+ gm = i + 1
+ gd = g_day_no + 1
+ return gy, gm, gd
+ end
+
+ -- local function test(yg,mg,dg,yj,mj,dj)
+ -- local y1, m1, d1 = jalali_to_gregorian(yj,mj,dj)
+ -- local y2, m2, d2 = gregorian_to_jalali(yg,mg,dg)
+ -- print(y1 == yg and m1 == mg and d1 == dg, yg,mg,dg, y1,m1,d1)
+ -- print(y2 == yj and m2 == mj and d2 == dj, yj,mj,dj, y2,m2,d2)
+ -- end
--- test(1953,08,19, 1332,05,28)
--- test(1979,02,11, 1357,11,22)
--- test(2000,02,28, 1378,12,09)
--- test(2000,03,01, 1378,12,11)
--- test(2009,02,24, 1387,12,06)
--- test(2015,03,21, 1394,01,01)
--- test(2016,03,20, 1395,01,01)
+ -- test(1953,08,19, 1332,05,28)
+ -- test(1979,02,11, 1357,11,22)
+ -- test(2000,02,28, 1378,12,09)
+ -- test(2000,03,01, 1378,12,11)
+ -- test(2009,02,24, 1387,12,06)
+ -- test(2015,03,21, 1394,01,01)
+ -- test(2016,03,20, 1395,01,01)
+
+ converters.gregorian_to_jalali = gregorian_to_jalali
+ converters.jalali_to_gregorian = jalali_to_gregorian
+
+end
-- -- more efficient but needs testing
@@ -1472,6 +1661,7 @@ local spaced = {
}
local dateconverters = {
+ ["hebrew:to"] = gregorian_to_hebrew,
["jalali:to"] = gregorian_to_jalali,
["jalali:from"] = jalali_to_gregorian,
}
@@ -1481,6 +1671,10 @@ local variants = {
month = monthmnems,
day = daymnems,
},
+ hebrew = {
+ month = setmetatableindex(function(t,k) return months[k] .. ":hebrew" end),
+ day = setmetatableindex(function(t,k) return days [k] .. ":hebrew" end),
+ },
jalali = {
month = setmetatableindex(function(t,k) return months[k] .. ":jalali" end),
day = setmetatableindex(function(t,k) return days [k] .. ":jalali" end),
@@ -1522,7 +1716,16 @@ do
end
auto = false
if tag == v_year or tag == "y" or tag == "Y" then
- context(year)
+ if plus then
+ plus = converters[plus]
+ end
+ if plus then
+ context(plus(year))
+ elseif currentlanguage == false then
+ context(year)
+ else
+ ctx_convertnumber(v_year,year)
+ end
elseif tag == "yy" or tag == "YY" then
context("%02i",year % 100)
elseif tag == v_month or tag == "m" then
@@ -1556,10 +1759,15 @@ do
elseif tag == "M" then
context(month)
elseif tag == v_day or tag == "d" then
- if currentlanguage == false then
+ if plus then
+ plus = converters[plus]
+ end
+ if plus then
+ context(plus(day))
+ elseif currentlanguage == false then
context(day)
else
- ctx_convertnumber(v_day,day) -- why not direct
+ ctx_convertnumber(v_day,day)
end
whatordinal = day
elseif tag == "dd" then