1 /* $Header: //info.ravenbrook.com/project/jili/version/1.1/code/mnj/lua/OSLib.java#1 $
2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject
11 * to the following conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 // [C1990] "ISO Standard: Programming languages - C"; ISO 9899:1990;
30 import java
.util
.Calendar
;
31 import java
.util
.Date
;
32 import java
.util
.TimeZone
;
35 * The OS Library. Can be opened into a {@link Lua} state by invoking
36 * the {@link #open} method.
38 public final class OSLib
extends LuaJavaCallback
40 // Each function in the library corresponds to an instance of
41 // this class which is associated (the 'which' member) with an integer
42 // which is unique within this class. They are taken from the following
44 private static final int CLOCK
= 1;
45 private static final int DATE
= 2;
46 private static final int DIFFTIME
= 3;
52 private static final int SETLOCALE
= 9;
53 private static final int TIME
= 10;
56 * Which library function this object represents. This value should
57 * be one of the "enums" defined in the class.
61 /** Constructs instance, filling in the 'which' member. */
62 private OSLib(int which
)
68 * Implements all of the functions in the Lua os library (that are
69 * provided). Do not call directly.
70 * @param L the Lua state in which to execute.
71 * @return number of returned parameters, as per convention.
73 public int luaFunction(Lua L
)
92 * Opens the library into the given Lua state. This registers
93 * the symbols of the library in the table "os".
94 * @param L The Lua state into which to open.
96 public static void open(Lua L
)
100 r(L
, "clock", CLOCK
);
102 r(L
, "difftime", DIFFTIME
);
103 r(L
, "setlocale", SETLOCALE
);
107 /** Register a function. */
108 private static void r(Lua L
, String name
, int which
)
110 OSLib f
= new OSLib(which
);
111 Object lib
= L
.getGlobal("os");
112 L
.setField(lib
, name
, f
);
115 private static final long T0
= System
.currentTimeMillis();
117 /** Implements clock. Java provides no way to get CPU time, so we
118 * return the amount of wall clock time since this class was loaded.
120 private static int clock(Lua L
)
122 double d
= (double)System
.currentTimeMillis();
130 /** Implements date. */
131 private static int date(Lua L
)
134 if (L
.isNoneOrNil(2))
136 t
= System
.currentTimeMillis();
140 t
= (long)L
.checkNumber(2);
143 String s
= L
.optString(1, "%c");
144 TimeZone tz
= TimeZone
.getDefault();
145 if (s
.startsWith("!"))
147 tz
= TimeZone
.getTimeZone("GMT");
151 Calendar c
= Calendar
.getInstance(tz
);
152 c
.setTime(new Date(t
));
156 L
.push(L
.createTable(0, 8)); // 8 = number of fields
157 setfield(L
, "sec", c
.get(Calendar
.SECOND
));
158 setfield(L
, "min", c
.get(Calendar
.MINUTE
));
159 setfield(L
, "hour", c
.get(Calendar
.HOUR
));
160 setfield(L
, "day", c
.get(Calendar
.DAY_OF_MONTH
));
161 setfield(L
, "month", canonicalmonth(c
.get(Calendar
.MONTH
)));
162 setfield(L
, "year", c
.get(Calendar
.YEAR
));
163 setfield(L
, "wday", canonicalweekday(c
.get(Calendar
.DAY_OF_WEEK
)));
164 // yday is not supported because CLDC 1.1 does not provide it.
165 // setfield(L, "yday", c.get("???"));
166 if (tz
.useDaylightTime())
168 // CLDC 1.1 does not provide any way to determine isdst, so we set
169 // it to -1 (which in C means that the information is not
171 setfield(L
, "isdst", -1);
175 // On the other hand if the timezone does not do DST then it
176 // can't be in effect.
177 setfield(L
, "isdst", 0);
182 StringBuffer b
= new StringBuffer();
187 char ch
= s
.charAt(i
);
200 // Generally in order to save space, the abbreviated forms are
201 // identical to the long forms.
202 // The specifiers are from [C1990].
206 b
.append(weekdayname(c
));
209 b
.append(monthname(c
));
212 b
.append(c
.getTime().toString());
215 b
.append(format(c
.get(Calendar
.DAY_OF_MONTH
), 2));
218 b
.append(format(c
.get(Calendar
.HOUR
), 2));
222 int h
= c
.get(Calendar
.HOUR
);
223 h
= (h
+11)%12+1; // force into range 1-12
224 b
.append(format(h
, 2));
229 // Not supported because CLDC 1.1 doesn't provide it.
235 int m
= canonicalmonth(c
.get(Calendar
.MONTH
));
236 b
.append(format(m
, 2));
240 b
.append(format(c
.get(Calendar
.MINUTE
), 2));
244 int h
= c
.get(Calendar
.HOUR
);
245 b
.append(h
<12 ?
"am" : "pm");
249 b
.append(format(c
.get(Calendar
.SECOND
), 2));
252 b
.append(canonicalweekday(c
.get(Calendar
.DAY_OF_WEEK
)));
256 String u
= c
.getTime().toString();
257 // We extract fields from the result of Date.toString.
258 // The output of which is of the form:
259 // dow mon dd hh:mm:ss zzz yyyy
260 // except that zzz is optional.
261 b
.append(u
.substring(0, 11));
262 b
.append(c
.get(Calendar
.YEAR
));
267 String u
= c
.getTime().toString();
268 b
.append(u
.substring(11, u
.length()-5));
272 b
.append(format(c
.get(Calendar
.YEAR
) % 100, 2));
275 b
.append(c
.get(Calendar
.YEAR
));
278 b
.append(tz
.getID());
285 L
.pushString(b
.toString());
290 /** Implements difftime. */
291 private static int difftime(Lua L
)
293 L
.pushNumber((L
.checkNumber(1) - L
.optNumber(2, 0))/1000);
297 // Incredibly, the spec doesn't give a numeric value and range for
298 // Calendar.JANUARY through to Calendar.DECEMBER.
300 * Converts from 0-11 to required Calendar value. DO NOT MODIFY THIS
303 private static final int[] MONTH
=
319 /** Implements setlocale. */
320 private static int setlocale(Lua L
)
322 if (L
.isNoneOrNil(1))
333 /** Implements time. */
334 private static int time(Lua L
)
336 if (L
.isNoneOrNil(1)) // called without args?
338 L
.pushNumber(System
.currentTimeMillis());
341 L
.checkType(1, Lua
.TTABLE
);
342 L
.setTop(1); // make sure table is at the top
343 Calendar c
= Calendar
.getInstance();
344 c
.set(Calendar
.SECOND
, getfield(L
, "sec", 0));
345 c
.set(Calendar
.MINUTE
, getfield(L
, "min", 0));
346 c
.set(Calendar
.HOUR
, getfield(L
, "hour", 12));
347 c
.set(Calendar
.DAY_OF_MONTH
, getfield(L
, "day", -1));
348 c
.set(Calendar
.MONTH
, MONTH
[getfield(L
, "month", -1) - 1]);
349 c
.set(Calendar
.YEAR
, getfield(L
, "year", -1));
350 // ignore isdst field
351 L
.pushNumber(c
.getTime().getTime());
355 private static int getfield(Lua L
, String key
, int d
)
357 Object o
= L
.getField(L
.value(-1), key
);
359 return (int)L
.toNumber(o
);
361 return L
.error("field '" + key
+ "' missing in date table");
365 private static void setfield(Lua L
, String key
, int value
)
367 L
.setField(L
.value(-1), key
, Lua
.valueOfNumber(value
));
370 /** Format a positive integer in a 0-filled field of width
373 private static String
format(int i
, int w
)
375 StringBuffer b
= new StringBuffer();
377 while (b
.length() < w
)
384 private static String
weekdayname(Calendar c
)
386 String s
= c
.getTime().toString();
387 return s
.substring(0, 3);
390 private static String
monthname(Calendar c
)
392 String s
= c
.getTime().toString();
393 return s
.substring(4, 7);
397 * (almost) inverts the conversion provided by {@link #MONTH}. Converts
398 * from a {@link Calendar} value to a month in the range 1-12.
399 * @param m a value from the enum Calendar.JANUARY, Calendar.FEBRUARY, etc
400 * @return a month in the range 1-12, or the original value.
402 private static int canonicalmonth(int m
)
404 for (int i
=0; i
<MONTH
.length
; ++i
)
414 // DO NOT MODIFY ARRAY
415 private static final int[] WEEKDAY
=
427 * Converts from a {@link Calendar} value to a weekday in the range
428 * 0-6 where 0 is Sunday (as per the convention used in [C1990]).
429 * @param w a value from the enum Calendar.SUNDAY, Calendar.MONDAY, etc
430 * @return a weekday in the range 0-6, or the original value.
432 private static int canonicalweekday(int w
)
434 for (int i
=0; i
<WEEKDAY
.length
; ++i
)