Jim Tcl
Check-in [f11e879168]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:file: Add microsecond resolution for mtime: mtimeus

Note that actual support is dependent upon the underlying operating system and filesystem.

Signed-off-by: Steve Bennett <steveb@workware.net.au>

Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: f11e87916874fba3c65049c64534d528cb553e50
User & Date: steveb@workware.net.au 2018-09-21 02:57:41
Context
2018-09-21
02:58
lreplace: Implement TIP #505

More consistent behaviour of replacing past end of list

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: 54894f621d user: steveb@workware.net.au tags: trunk

02:57
file: Add microsecond resolution for mtime: mtimeus

Note that actual support is dependent upon the underlying operating system and filesystem.

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: f11e879168 user: steveb@workware.net.au tags: trunk

2018-09-03
22:00
bootstrap package support

Allow minimal command "package" to take additional arguments, but ignore them.

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: a2b3125017 user: steveb@workware.net.au tags: trunk

Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to auto.def.

125
126
127
128
129
130
131





132
133
134
135
136
137
138
}

if {[cc-check-functions sysinfo]} {
    cc-with {-includes sys/sysinfo.h} {
        cc-check-members "struct sysinfo.uptime"
    }
}






cc-with {-includes fcntl.h} {
    cc-check-types "struct flock"
}

cc-check-lfs
cc-check-functions fseeko ftello







>
>
>
>
>







125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
}

if {[cc-check-functions sysinfo]} {
    cc-with {-includes sys/sysinfo.h} {
        cc-check-members "struct sysinfo.uptime"
    }
}

cc-with {-includes {sys/types.h sys/stat.h}} {
    cc-check-members "struct stat.st_mtimespec"
    cc-check-members "struct stat.st_mtim"
}

cc-with {-includes fcntl.h} {
    cc-check-types "struct flock"
}

cc-check-lfs
cc-check-functions fseeko ftello

Changes to jim-file.c.

73
74
75
76
77
78
79







80
81
82
83
84
85
86
...
165
166
167
168
169
170
171



172
173
174
175
176
177
178
...
605
606
607
608
609
610
611






















612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643




















644
645
646
647
648
649
650
...
761
762
763
764
765
766
767









768
769
770
771
772
773
774

#if defined(__MINGW32__) || defined(__MSYS__) || defined(_MSC_VER)
#define ISWINDOWS 1
#else
#define ISWINDOWS 0
#endif








/*
 *----------------------------------------------------------------------
 *
 * JimGetFileType --
 *
 *  Given a mode word, returns a string identifying the type of a
 *  file.
................................................................................
    AppendStatElement(interp, listObj, "nlink", sb->st_nlink);
    AppendStatElement(interp, listObj, "uid", sb->st_uid);
    AppendStatElement(interp, listObj, "gid", sb->st_gid);
    AppendStatElement(interp, listObj, "size", sb->st_size);
    AppendStatElement(interp, listObj, "atime", sb->st_atime);
    AppendStatElement(interp, listObj, "mtime", sb->st_mtime);
    AppendStatElement(interp, listObj, "ctime", sb->st_ctime);



    Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
    Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1));

    /* Was a variable specified? */
    if (varName) {
        Jim_Obj *objPtr;
        objPtr = Jim_GetVariable(interp, varName, JIM_NONE);
................................................................................

    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
        return JIM_ERR;
    }
    Jim_SetResultInt(interp, sb.st_atime);
    return JIM_OK;
}























static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    struct stat sb;

    if (argc == 2) {
#ifdef HAVE_UTIMES
        jim_wide newtime;
        struct timeval times[2];

        if (Jim_GetWide(interp, argv[1], &newtime) != JIM_OK) {
            return JIM_ERR;
        }

        times[1].tv_sec = times[0].tv_sec = newtime;
        times[1].tv_usec = times[0].tv_usec = 0;

        if (utimes(Jim_String(argv[0]), times) != 0) {
            Jim_SetResultFormatted(interp, "can't set time on \"%#s\": %s", argv[0], strerror(errno));
            return JIM_ERR;
        }
#else
        Jim_SetResultString(interp, "Not implemented", -1);
        return JIM_ERR;
#endif
    }
    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
        return JIM_ERR;
    }
    Jim_SetResultInt(interp, sb.st_mtime);
    return JIM_OK;
}





















static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    return Jim_EvalPrefix(interp, "file copy", argc, argv);
}

static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
................................................................................
    {   "mtime",
        "name ?time?",
        file_cmd_mtime,
        1,
        2,
        /* Description: Get or set last modification time */
    },









    {   "copy",
        "?-force? source dest",
        file_cmd_copy,
        2,
        3,
        /* Description: Copy source file to destination file */
    },







>
>
>
>
>
>
>







 







>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






<
|
<
<
|


<
<
<
<
|
<
<
<
<
<
<
<







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
...
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649

650


651
652
653




654







655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
...
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821

#if defined(__MINGW32__) || defined(__MSYS__) || defined(_MSC_VER)
#define ISWINDOWS 1
#else
#define ISWINDOWS 0
#endif

/* extract nanosecond resolution mtime from struct stat */
#if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
    #define STAT_MTIME_US(STAT) ((STAT).st_mtimespec.tv_sec * 1000000ll + (STAT).st_mtimespec.tv_nsec / 1000)
#elif defined(HAVE_STRUCT_STAT_ST_MTIM)
    #define STAT_MTIME_US(STAT) ((STAT).st_mtim.tv_sec * 1000000ll + (STAT).st_mtim.tv_nsec / 1000)
#endif

/*
 *----------------------------------------------------------------------
 *
 * JimGetFileType --
 *
 *  Given a mode word, returns a string identifying the type of a
 *  file.
................................................................................
    AppendStatElement(interp, listObj, "nlink", sb->st_nlink);
    AppendStatElement(interp, listObj, "uid", sb->st_uid);
    AppendStatElement(interp, listObj, "gid", sb->st_gid);
    AppendStatElement(interp, listObj, "size", sb->st_size);
    AppendStatElement(interp, listObj, "atime", sb->st_atime);
    AppendStatElement(interp, listObj, "mtime", sb->st_mtime);
    AppendStatElement(interp, listObj, "ctime", sb->st_ctime);
#ifdef STAT_MTIME_US
    AppendStatElement(interp, listObj, "mtimeus", STAT_MTIME_US(*sb));
#endif
    Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
    Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1));

    /* Was a variable specified? */
    if (varName) {
        Jim_Obj *objPtr;
        objPtr = Jim_GetVariable(interp, varName, JIM_NONE);
................................................................................

    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
        return JIM_ERR;
    }
    Jim_SetResultInt(interp, sb.st_atime);
    return JIM_OK;
}

/**
 * Set file atime/mtime to the given time in microseconds since the epoch.
 */
static int JimSetFileTimes(Jim_Interp *interp, const char *filename, jim_wide us)
{
#ifdef HAVE_UTIMES
    struct timeval times[2];

    times[1].tv_sec = times[0].tv_sec = us / 1000000;
    times[1].tv_usec = times[0].tv_usec = us % 1000000;

    if (utimes(filename, times) != 0) {
        Jim_SetResultFormatted(interp, "can't set time on \"%s\": %s", filename, strerror(errno));
        return JIM_ERR;
    }
    return JIM_OK;
#else
    Jim_SetResultString(interp, "Not implemented", -1);
    return JIM_ERR;
#endif
}

static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    struct stat sb;

    if (argc == 2) {

        jim_wide secs;


        if (Jim_GetWide(interp, argv[1], &secs) != JIM_OK) {
            return JIM_ERR;
        }




        return JimSetFileTimes(interp, Jim_String(argv[0]), secs * 1000000);







    }
    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
        return JIM_ERR;
    }
    Jim_SetResultInt(interp, sb.st_mtime);
    return JIM_OK;
}

#ifdef STAT_MTIME_US
static int file_cmd_mtimeus(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    struct stat sb;

    if (argc == 2) {
        jim_wide us;
        if (Jim_GetWide(interp, argv[1], &us) != JIM_OK) {
            return JIM_ERR;
        }
        return JimSetFileTimes(interp, Jim_String(argv[0]), us);
    }
    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
        return JIM_ERR;
    }
    Jim_SetResultInt(interp, STAT_MTIME_US(sb));
    return JIM_OK;
}
#endif

static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    return Jim_EvalPrefix(interp, "file copy", argc, argv);
}

static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
................................................................................
    {   "mtime",
        "name ?time?",
        file_cmd_mtime,
        1,
        2,
        /* Description: Get or set last modification time */
    },
#ifdef STAT_MTIME_US
    {   "mtimeus",
        "name ?time?",
        file_cmd_mtimeus,
        1,
        2,
        /* Description: Get or set last modification time in microseconds */
    },
#endif
    {   "copy",
        "?-force? source dest",
        file_cmd_copy,
        2,
        3,
        /* Description: Copy source file to destination file */
    },

Changes to jim_tcl.txt.

1
2
3
4
5
6
7
8
9
10
11
12
13
..
48
49
50
51
52
53
54




55
56
57
58
59
60
61
....
2369
2370
2371
2372
2373
2374
2375






2376
2377
2378
2379
2380
2381
2382
....
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
Jim Tcl(n)
==========

NAME
----
Jim Tcl v0.78 - reference manual for the Jim Tcl scripting language

SYNOPSIS
--------

  cc <source> -ljim

or
................................................................................
13. Expression shorthand syntax: +$(...)+
14. Modular build allows many features to be omitted or built as dynamic, loadable modules
15. Highly suitable for use in an embedded environment
16. Support for UDP, IPv6, Unix-Domain sockets in addition to TCP sockets

RECENT CHANGES
--------------




Changes between 0.77 and 0.78
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Add serial/tty support with `aio tty`
2. Add support for 'jimsh -'
3. Add hidden '-commands' option to many commands
4. Add scriptable autocompletion support in interactive mode with `tcl::autocomplete`
5. Add `aio sockopt`
................................................................................
    Return a decimal string giving the time at which file +'name'+
    was last modified.  The time is measured in the standard UNIX
    fashion as seconds from a fixed starting time (often January 1, 1970).
    If the file doesn't exist or its modified time cannot be queried then an
    error is generated. If +'time'+ is given, sets the modification time
    of the file to the given value.







+*file normalize* 'name'+::
    Return the normalized path of +'name'+. See 'realpath(3)'.

+*file owned* 'name'+::
    Return '1' if file +'name'+ is owned by the current user,
    '0' otherwise.

................................................................................
    If the file doesn't exist or its size cannot be queried then an
    error is generated.

+*file stat* 'name ?varName?'+::
    Invoke the 'stat' kernel call on +'name'+, and return the result
    as a dictionary with the following keys: 'atime',
    'ctime', 'dev', 'gid', 'ino', 'mode', 'mtime',
    'nlink', 'size', 'type', 'uid'.
    Each element except 'type' is a decimal string with the value of
    the corresponding field from the 'stat' return structure; see the
    manual entry for 'stat' for details on the meanings of the values.
    The 'type' element gives the type of the file in the same form
    returned by the command `file type`.
    If +'varName'+ is specified, it is taken to be the name of an array
    variable and the values are also stored into the array.





|







 







>
>
>
>







 







>
>
>
>
>
>







 







|







1
2
3
4
5
6
7
8
9
10
11
12
13
..
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
....
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
....
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
Jim Tcl(n)
==========

NAME
----
Jim Tcl v0.78+ - reference manual for the Jim Tcl scripting language

SYNOPSIS
--------

  cc <source> -ljim

or
................................................................................
13. Expression shorthand syntax: +$(...)+
14. Modular build allows many features to be omitted or built as dynamic, loadable modules
15. Highly suitable for use in an embedded environment
16. Support for UDP, IPv6, Unix-Domain sockets in addition to TCP sockets

RECENT CHANGES
--------------
Changes since 0.78
~~~~~~~~~~~~~~~~~~
1. Add `file mtimeus` for high resolution file timestamps

Changes between 0.77 and 0.78
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Add serial/tty support with `aio tty`
2. Add support for 'jimsh -'
3. Add hidden '-commands' option to many commands
4. Add scriptable autocompletion support in interactive mode with `tcl::autocomplete`
5. Add `aio sockopt`
................................................................................
    Return a decimal string giving the time at which file +'name'+
    was last modified.  The time is measured in the standard UNIX
    fashion as seconds from a fixed starting time (often January 1, 1970).
    If the file doesn't exist or its modified time cannot be queried then an
    error is generated. If +'time'+ is given, sets the modification time
    of the file to the given value.

+*file mtimeus* 'name ?time_us?'+::
    As for `file mtime` except the time value is in microseconds
	since the epoch (see also `clock microseconds`).
	Note that some platforms and some filesystems don't support high
	resolution timestamps for files.

+*file normalize* 'name'+::
    Return the normalized path of +'name'+. See 'realpath(3)'.

+*file owned* 'name'+::
    Return '1' if file +'name'+ is owned by the current user,
    '0' otherwise.

................................................................................
    If the file doesn't exist or its size cannot be queried then an
    error is generated.

+*file stat* 'name ?varName?'+::
    Invoke the 'stat' kernel call on +'name'+, and return the result
    as a dictionary with the following keys: 'atime',
    'ctime', 'dev', 'gid', 'ino', 'mode', 'mtime',
    'nlink', 'size', 'type', 'uid', 'mtimeus' (if supported - see `file mtimeus`)
    Each element except 'type' is a decimal string with the value of
    the corresponding field from the 'stat' return structure; see the
    manual entry for 'stat' for details on the meanings of the values.
    The 'type' element gives the type of the file in the same form
    returned by the command `file type`.
    If +'varName'+ is specified, it is taken to be the name of an array
    variable and the values are also stored into the array.