diff --git a/clite/commands.js b/clite/commands.js index 0f7c984..3927f00 100644 --- a/clite/commands.js +++ b/clite/commands.js @@ -37,8 +37,10 @@ clite.commands.load('ls',function(args,env,io) { var dirs = []; var long = false; var all = false; + var access = false; var stdlib = io.include('stdlib'); var stdio = io.include('stdio'); + var time = io.include('time'); var clite = io.include('clite'); function help() { stdio.printf(` @@ -48,27 +50,42 @@ Usage: ls [OPTION] [FILE] Options: -? Print this help information -l Display data in long format +-u Display access time in long format -a Do not ignore entries starting with . `); } function writeNodeData(st,fd) { if (long) { - var pw = stdlib.getpwuid(st.uid); - var gr = stdlib.getgrgid(st.gid); - var uname = st.uid.toString(); - var gname = st.gid.toString(); + var pw = stdlib.getpwuid(st.st_uid); + var gr = stdlib.getgrgid(st.st_gid); + var uname = st.st_uid.toString(); + var gname = st.st_gid.toString(); if (pw) uname = pw.pw_name; if (gr) gname = gr.gr_name; - if (st.type == stdio.types.FT_LINK) { - var d = stdio.readAll(fd); - if (!d) - d = '?'; - stdio.printf('%s%16s%16s%16s -> %s\n',st.perms,uname,gname,st.name,d); + var tm; + var t = time.time(); + var tmn = time.localtime(t); + if (access) { + tm = time.localtime(st.st_atim.tv_sec); }else{ - stdio.printf('%s%16s%16s%16s\n',st.perms,uname,gname,st.name); + tm = time.localtime(st.st_mtim.tv_sec); + } + var d = ''; + if (tm.tm_year != tmn.tm_year) { + d = time.strftime('%b %d %Y',tm); + }else{ + d = time.strftime('%b %d %H:%M',tm); + } + if (st.type == stdio.types.FT_LINK) { + var lp = stdio.readAll(fd); + if (!lp) + lp = '?'; + stdio.printf('%s%16s%16s%14s%16s -> %s\n',st.perms,uname,gname,d,st.name,lp); + }else{ + stdio.printf('%s%16s%16s%14s%16s\n',st.perms,uname,gname,d,st.name); } }else{ stdio.printf(st.name); @@ -86,6 +103,9 @@ Options: case 'l': long = true; break; + case 'u': + access = true; + break; case 'a': all = true; break; @@ -1216,140 +1236,6 @@ Options: //tm_wday:0, // day of week (0-6, sunday = 0) //tm_yday:0, // day of year (0-365) //tm_isdst:0 // 1 if daylight savings - function getDT(fmt,tm) { - var parts = fmt.split('%'); - var out = ''; - var skip = false; - var data = { - d_s:['Sun','Mon','Tue','Wed','Thu','Fri','Sat'], - m_s:['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'], - d_l:['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'], - m_l:['January','February','March','April','May','June','July','August','September','October','November','December'], - } - parts.forEach(function(part,i) { - if (part == '') { - if (i != 0) { - out += '%'; - skip = true; - } - return; - } - if (skip || i == 0) { - out += part; - skip = false; - return; - } - var o = part.substring(0,1); - var e = part.substring(1); - switch (o) { - case 'a': //Locale's abbreviated weekday name. - out += data.d_s[tm.tm_wday]; - break; - case 'A': //Locale's full weekday name. - out += data.d_l[tm.tm_wday]; - break; - case 'h': - case 'b': //Locale's abbreviated month name. - out += data.m_s[tm.tm_mon]; - break; - case 'B': //Locale's full month name. - out += data.m_l[tm.tm_mon]; - break; - case 'c': //Locale's appropriate date and time representation. - out += getDT('%a %d %b %Y %H:%M:%S',tm); - break; - case 'C': //Century (a year divided by 100 and truncated to an integer) as a decimal number [00,99]. - var y = tm.tm_year+1900; - out += (y/100).toFixed(0); - break; - case 'd': //Day of the month as a decimal number [01,31]. - out += (tm.tm_mday+1).toFixed(0).padStart(2,'0'); - break; - case 'D': //Date in the format mm/dd/yy. - out += getDT('%M/%D/%y',tm); - break; - case 'e': //Day of the month as a decimal number [1,31] in a two-digit field with leading character fill. - out += (tm.tm_mday+1).toFixed(0).padStart(2,' '); - break; - case 'H': //Hour (24-hour clock) as a decimal number [00,23]. - out += (tm.tm_hour).toFixed(0).padStart(2,'0'); - break; - case 'I': //Hour (12-hour clock) as a decimal number [01,12]. - out += (tm.tm_hour%12).toFixed(0).padStart(2,'0'); - break; - case 'j': //Day of the year as a decimal number [001,366]. - out += (tm.tm_yday).toFixed(0).padStart(3,'0'); - break; - case 'm': //Month as a decimal number [01,12]. - out += (tm.tm_mon+1).toFixed(0).padStart(2,'0'); - break; - case 'M': //Minute as a decimal number [00,59]. - out += (tm.tm_min).toFixed(0).padStart(2,'0'); - break; - case 'n': //A . - out += '\n'; - break; - case 'p': //Locale's equivalent of either AM or PM. - if (tm.tm_hour >11) { - out += 'PM'; - }else{ - out += 'AM'; - } - break; - case 'r': //12-hour clock time [01,12] using the AM/PM notation; in the POSIX locale, this shall be equivalent to %I : %M : %S %p. - out += getDT('%I:%M:%S%p',tm); - break; - case 's': - out += time.mktime(tm).toFixed(0); - break; - case 'S': //Seconds as a decimal number [00,60]. - out += tm.tm_sec.toFixed(0).padStart(2,'0'); - break; - case 't': //A . - out += '\t'; - break; - case 'T': //24-hour clock time [00,23] in the format HH:MM:SS. - out += getDT('%H:%M:%S',tm); - break; - case 'u': //Weekday as a decimal number [1,7] (1=Monday). - if (tm.tm_wday < 1) { - out += '7'; - }else{ - out += tm.tm_wday.toFixed(0); - } - break; - case 'U': //Week of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday shall be considered to be in week 0. - // TODO: this - break; - case 'V': //Week of the year (Monday as the first day of the week) as a decimal number [01,53]. If the week containing January 1 has four or more days in the new year, then it shall be considered week 1; otherwise, it shall be the last week of the previous year, and the next week shall be week 1. - // TODO: this - break; - case 'w': //Weekday as a decimal number [0,6] (0=Sunday). - out += tm.tm_wday.toFixed(0); - break; - case 'W': //Week of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday shall be considered to be in week 0. - // TODO: this - break; - case 'x': //Locale's appropriate date representation. - out += getDT('%d/%m/%Y',tm); - break; - case 'X': //Locale's appropriate time representation. - out += getDT('%H:%M:%S',tm); - break; - case 'y': //Year within century [00,99]. - out += (tm.tm_year+1900).toFixed(0).substring(2); - break; - case 'Y': //Year with century as a decimal number. - out += (tm.tm_year+1900).toFixed(0); - break; - case 'Z': //Timezone name, or no characters if no timezone is determinable. - break; - default:; - } - out += e; - }); - return out; - } function main(args) { var utc = false; @@ -1388,7 +1274,7 @@ Options: if (!t) return 1; - var out = getDT(format,tm); + var out = time.strftime(format,tm); if (!out) return 1; @@ -1410,6 +1296,7 @@ clite.commands.load('test',function(args,env,io) { stdio.printf('time is: %d\n',t); var tm = time.gmtime(t); stdio.printf('gmtime gives: %d %d %d %d %d %d %d %d %d\n',tm.tm_sec,tm.tm_min,tm.tm_hour,tm.tm_mday,tm.tm_mon,tm.tm_year,tm.tm_wday,tm.tm_yday,tm.tm_isdst); + stdio.printf('%s\n',time.ctime(t)); stdio.printf('Hello world\n'); stdio.printf('uid:%d\n',stdlib.getuid()); stdio.printf('%#15x:%15o:%15.5f:%0$15.5f:%%:\n',10,12,8.123456789); diff --git a/clite/core.js b/clite/core.js index 7388929..fa38b8d 100644 --- a/clite/core.js +++ b/clite/core.js @@ -10,6 +10,17 @@ var clite = { // a list of library files to load libs:['libclite.js','libcurses.js','libstd.js','libstdio.js','libterm.js','libtime.js'] }, + time:{ + sec:function() { + return parseInt(Date.now()/1000.0,10); + }, + msec:function() { + return Date.now(); + }, + nsec:function() { + return parseInt(Date.now()*1000,10); + } + }, core:{ execSafe:function(f) { try{ @@ -275,7 +286,7 @@ var clite = { } n.data.content = { read:function() { - return Date.now().toString(); + return clite.time.msec().toString(); }, write:null }; @@ -1295,6 +1306,7 @@ clite.io = { return false; if (fd.node.data.isdev) { if (typeof fd.node.data.content != 'string') { + fd.node.time.modify = clite.time.sec(); try{ return fd.node.data.content.write(data); } catch(err) { @@ -1315,6 +1327,7 @@ clite.io = { fd.node.data.content = b+data+e; fd.pos += data.length; } + fd.node.time.modify = clite.time.sec(); return true; } clite.io.ftruncate = function(pid,fd,len) { @@ -1325,6 +1338,7 @@ clite.io = { fd.data.content = fd.data.content.substring(0,len); if (fd.pos > len) fd.pos = len; + fd.node.time.modify = clite.time.sec(); return true; } clite.io.truncate = function(pid,path,len) { @@ -1379,14 +1393,30 @@ clite.io = { var stat = Object.create({ name:fd.node.name, type:clite.lib.getFileType(fd), - uid:fd.node.uid, - gid:fd.node.gid, - size:0, + st_dev:0, + st_ino:0, + st_mode:0, + st_nlink:0, + st_uid:fd.node.uid, + st_gid:fd.node.gid, + st_size:0, + st_atim:{ + tv_sec:fd.node.time.access, + tv_nsec:0 + }, + st_mtim:{ + tv_sec:fd.node.time.modify, + tv_nsec:0 + }, + st_ctim:{ + tv_sec:fd.node.time.change, + tv_nsec:0 + }, perms:fd.node.perms }); - if (stat.type == 1 || stat.type == 7) - stat.size = fd.node.data.content.length; + if (stat.type == clite.io.types.FT_TEXT || stat.type == clite.io.types.FT_SCRIPT) + stat.st_size = fd.node.data.content.length; return stat; }, @@ -1411,6 +1441,7 @@ clite.io = { }else{ fd.node.perms = '-'+mode.substring(0); } + fd.node.time.change = clite.time.sec(); return true; } clite.io.chmod = function(pid,path,mode) { @@ -1899,6 +1930,11 @@ clite.vfs = { uid: 0, gid: 0, perms:'-rw-r--r--', + time:{ + access:clite.time.sec(), + modify:clite.time.sec(), + change:clite.time.sec() + }, data:{ remote:null, isdir:false, @@ -1945,6 +1981,7 @@ clite.vfs = { } if (!checkCanOpen(uid,n)) return null; + n.time.access = clite.time.sec(); return n; } vfsdata.api.getFile = function(uid,path) { @@ -1977,6 +2014,7 @@ clite.vfs = { n.uid = uid; n.gid = clite.user.getGID(uid); parent.data.content.push(n); + parent.time.modify = clite.time.sec(); return true; } vfsdata.api.mkFile = function(uid,path) { @@ -2000,6 +2038,7 @@ clite.vfs = { n.uid = uid; n.gid = clite.user.getGID(uid); parent.data.content.push(n); + parent.time.modify = clite.time.sec(); return true; } vfsdata.api.mkLink = function(uid,path,target) { @@ -2024,6 +2063,7 @@ clite.vfs = { n.uid = uid; n.gid = clite.user.getGID(uid); parent.data.content.push(n); + parent.time.modify = clite.time.sec(); return true; } vfsdata.api.mkPath = function(uid,path) { diff --git a/clite/libtime.js b/clite/libtime.js index 45df3ff..acb5b97 100644 --- a/clite/libtime.js +++ b/clite/libtime.js @@ -4,6 +4,8 @@ clite.libs.load('libtime','time',function(io,env) { var data = { days:['Sun','Mon','Tue','Wed','Thu','Fri','Sat'], months:['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'], + days_l:['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'], + months_l:['January','February','March','April','May','June','July','August','September','October','November','December'], mdays:[31,28,31,30,31,30,31,31,30,31,30,31] } function getyDay(mon,mday,year) { @@ -58,13 +60,145 @@ clite.libs.load('libtime','time',function(io,env) { return tm; } + function getDTStr(fmt,tm) { + var parts = fmt.split('%'); + var out = ''; + var skip = false; + parts.forEach(function(part,i) { + if (part == '') { + if (i != 0) { + out += '%'; + skip = true; + } + return; + } + if (skip || i == 0) { + out += part; + skip = false; + return; + } + var o = part.substring(0,1); + var e = part.substring(1); + switch (o) { + case 'a': //Locale's abbreviated weekday name. + out += data.days[tm.tm_wday]; + break; + case 'A': //Locale's full weekday name. + out += data.days_l[tm.tm_wday]; + break; + case 'h': + case 'b': //Locale's abbreviated month name. + out += data.months[tm.tm_mon]; + break; + case 'B': //Locale's full month name. + out += data.months_l[tm.tm_mon]; + break; + case 'c': //Locale's appropriate date and time representation. + out += getDTStr('%a %d %b %Y %H:%M:%S',tm); + break; + case 'C': //Century (a year divided by 100 and truncated to an integer) as a decimal number [00,99]. + var y = tm.tm_year+1900; + out += (y/100).toFixed(0); + break; + case 'd': //Day of the month as a decimal number [01,31]. + out += (tm.tm_mday+1).toFixed(0).padStart(2,'0'); + break; + case 'D': //Date in the format mm/dd/yy. + out += getDTStr('%M/%D/%y',tm); + break; + case 'e': //Day of the month as a decimal number [1,31] in a two-digit field with leading character fill. + out += (tm.tm_mday+1).toFixed(0).padStart(2,' '); + break; + case 'H': //Hour (24-hour clock) as a decimal number [00,23]. + out += (tm.tm_hour).toFixed(0).padStart(2,'0'); + break; + case 'I': //Hour (12-hour clock) as a decimal number [01,12]. + out += (tm.tm_hour%12).toFixed(0).padStart(2,'0'); + break; + case 'j': //Day of the year as a decimal number [001,366]. + out += (tm.tm_yday).toFixed(0).padStart(3,'0'); + break; + case 'm': //Month as a decimal number [01,12]. + out += (tm.tm_mon+1).toFixed(0).padStart(2,'0'); + break; + case 'M': //Minute as a decimal number [00,59]. + out += (tm.tm_min).toFixed(0).padStart(2,'0'); + break; + case 'n': //A . + out += '\n'; + break; + case 'p': //Locale's equivalent of either AM or PM. + if (tm.tm_hour >11) { + out += 'PM'; + }else{ + out += 'AM'; + } + break; + case 'r': //12-hour clock time [01,12] using the AM/PM notation; in the POSIX locale, this shall be equivalent to %I : %M : %S %p. + out += getDTStr('%I:%M:%S%p',tm); + break; + case 's': + out += time.mktime(tm).toFixed(0); + break; + case 'S': //Seconds as a decimal number [00,60]. + out += tm.tm_sec.toFixed(0).padStart(2,'0'); + break; + case 't': //A . + out += '\t'; + break; + case 'T': //24-hour clock time [00,23] in the format HH:MM:SS. + out += getDTStr('%H:%M:%S',tm); + break; + case 'u': //Weekday as a decimal number [1,7] (1=Monday). + if (tm.tm_wday < 1) { + out += '7'; + }else{ + out += tm.tm_wday.toFixed(0); + } + break; + case 'U': //Week of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday shall be considered to be in week 0. + // TODO: this + break; + case 'V': //Week of the year (Monday as the first day of the week) as a decimal number [01,53]. If the week containing January 1 has four or more days in the new year, then it shall be considered week 1; otherwise, it shall be the last week of the previous year, and the next week shall be week 1. + // TODO: this + break; + case 'w': //Weekday as a decimal number [0,6] (0=Sunday). + out += tm.tm_wday.toFixed(0); + break; + case 'W': //Week of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday shall be considered to be in week 0. + // TODO: this + break; + case 'x': //Locale's appropriate date representation. + out += getDTStr('%d/%m/%Y',tm); + break; + case 'X': //Locale's appropriate time representation. + out += getDTStr('%H:%M:%S',tm); + break; + case 'y': //Year within century [00,99]. + out += (tm.tm_year+1900).toFixed(0).substring(2); + break; + case 'Y': //Year with century as a decimal number. + out += (tm.tm_year+1900).toFixed(0); + break; + case 'Z': //Timezone name, or no characters if no timezone is determinable. + break; + default:; + } + out += e; + }); + return out; + } // return Object.create({ asctime:function(timeptr) { - return data.days[timeptr.tm_wday]+' '+data.months[timeptr.tm_mon]+' '+timeptr.tm_mday+' '+timeptr.tm_hour+':'+timeptr.tm_min+':'+timeptr.tm_sec+' '+(1900+timeptr.tm_year)+'\n'; + return getDTStr('%a %d %b %T %Y',timeptr); + }, + ctime:function(time) { + var tm = this.localtime(time); + return this.asctime(tm); }, gmtime:function(time) { return genTime(time,0); @@ -75,9 +209,12 @@ return Object.create({ return genTime(time,tz); }, mktime:function(timeptr) { - var t = data.days[timeptr.tm_wday]+' '+data.months[timeptr.tm_mon]+' '+timeptr.tm_mday+' '+timeptr.tm_hour+':'+timeptr.tm_min+':'+timeptr.tm_sec+' '+(1900+timeptr.tm_year+' UTC'); + var t = getDTStr('%a %d %b %T %Y %Z',timeptr); return parseInt(Math.floor((new Date(t)).getTime()/1000.0).toFixed(0)); }, + strftime:function(fmt,timeptr) { + return getDTStr(fmt,timeptr); + }, time:function() { var t = readTime(); return parseInt(Math.floor(t/1000.0).toFixed(0)); // convert from milliseconds to seconds