#ifdef HAVE_PWD_H
#include <pwd.h>
+#include <grp.h>
#endif
#include <unistd.h>
static Lisp_Object Qboundary;
+/* The startup value of the TZ environment variable so it can be
+ restored if the user calls set-time-zone-rule with a nil
+ argument. If null, the TZ environment variable was unset. */
+static char const *initial_tz;
+
+/* True if the static variable tzvalbuf (defined in
+ set_time_zone_rule) is part of 'environ'. */
+static bool tzvalbuf_in_environ;
+
void
init_editfns (void)
return;
#endif /* not CANNOT_DUMP */
+ initial_tz = getenv ("TZ");
+ tzvalbuf_in_environ = 0;
+
pw = getpwuid (getuid ());
#ifdef MSDOS
/* We let the real user name default to "root" because that's quite
return make_fixnum_or_float (uid);
}
+DEFUN ("group-gid", Fgroup_gid, Sgroup_gid, 0, 0, 0,
+ doc: /* Return the effective gid of Emacs.
+Value is an integer or a float, depending on the value. */)
+ (void)
+{
+ gid_t egid = getegid ();
+ return make_fixnum_or_float (egid);
+}
+
+DEFUN ("group-real-gid", Fgroup_real_gid, Sgroup_real_gid, 0, 0, 0,
+ doc: /* Return the real gid of Emacs.
+Value is an integer or a float, depending on the value. */)
+ (void)
+{
+ gid_t gid = getgid ();
+ return make_fixnum_or_float (gid);
+}
+
DEFUN ("user-full-name", Fuser_full_name, Suser_full_name, 0, 1, 0,
doc: /* Return the full name of the user logged in, as a string.
If the full name corresponding to Emacs's userid is not known,
}
else
{
- char tzbuf[100];
+ static char const tzbuf_format[] = "XXX%s%"pI"d:%02d:%02d";
+ char tzbuf[sizeof tzbuf_format + INT_STRLEN_BOUND (EMACS_INT)];
+ char *old_tzstring;
const char *tzstring;
- char **oldenv = environ, **newenv;
+ USE_SAFE_ALLOCA;
if (EQ (zone, Qt))
tzstring = "UTC0";
EMACS_INT zone_hr = abszone / (60*60);
int zone_min = (abszone/60) % 60;
int zone_sec = abszone % 60;
- sprintf (tzbuf, "XXX%s%"pI"d:%02d:%02d", "-" + (XINT (zone) < 0),
+ sprintf (tzbuf, tzbuf_format, "-" + (XINT (zone) < 0),
zone_hr, zone_min, zone_sec);
tzstring = tzbuf;
}
else
error ("Invalid time zone specification");
+ old_tzstring = getenv ("TZ");
+ if (old_tzstring)
+ {
+ char *buf = SAFE_ALLOCA (strlen (old_tzstring) + 1);
+ old_tzstring = strcpy (buf, old_tzstring);
+ }
+
block_input ();
/* Set TZ before calling mktime; merely adjusting mktime's returned
value = mktime (&tm);
- /* Restore TZ to previous value. */
- newenv = environ;
- environ = oldenv;
+ set_time_zone_rule (old_tzstring);
#ifdef LOCALTIME_CACHE
tzset ();
#endif
unblock_input ();
-
- xfree (newenv);
+ SAFE_FREE ();
}
if (value == (time_t) -1)
return list2 (zone_offset, zone_name);
}
-/* This holds the value of `environ' produced by the previous
- call to Fset_time_zone_rule, or 0 if Fset_time_zone_rule
- has never been called. */
-static char **environbuf;
-
-/* This holds the startup value of the TZ environment variable so it
- can be restored if the user calls set-time-zone-rule with a nil
- argument. */
-static char *initial_tz;
-
DEFUN ("set-time-zone-rule", Fset_time_zone_rule, Sset_time_zone_rule, 1, 1, 0,
doc: /* Set the local time zone using TZ, a string specifying a time zone rule.
If TZ is nil, use implementation-defined default time zone information.
(Lisp_Object tz)
{
const char *tzstring;
- char **old_environbuf;
if (! (NILP (tz) || EQ (tz, Qt)))
CHECK_STRING (tz);
- block_input ();
-
- /* When called for the first time, save the original TZ. */
- old_environbuf = environbuf;
- if (!old_environbuf)
- initial_tz = (char *) getenv ("TZ");
-
if (NILP (tz))
tzstring = initial_tz;
else if (EQ (tz, Qt))
else
tzstring = SSDATA (tz);
+ block_input ();
set_time_zone_rule (tzstring);
- environbuf = environ;
-
unblock_input ();
- xfree (old_environbuf);
return Qnil;
}
-#ifdef LOCALTIME_CACHE
-
-/* These two values are known to load tz files in buggy implementations,
- i.e. Solaris 1 executables running under either Solaris 1 or Solaris 2.
- Their values shouldn't matter in non-buggy implementations.
- We don't use string literals for these strings,
- since if a string in the environment is in readonly
- storage, it runs afoul of bugs in SVR4 and Solaris 2.3.
- See Sun bugs 1113095 and 1114114, ``Timezone routines
- improperly modify environment''. */
-
-static char set_time_zone_rule_tz1[] = "TZ=GMT+0";
-static char set_time_zone_rule_tz2[] = "TZ=GMT+1";
-
-#endif
-
/* Set the local time zone rule to TZSTRING.
- This allocates memory into `environ', which it is the caller's
- responsibility to free. */
+
+ This function is not thread-safe, partly because putenv, unsetenv
+ and tzset are not, and partly because of the static storage it
+ updates. Other threads that invoke localtime etc. may be adversely
+ affected while this function is executing. */
void
set_time_zone_rule (const char *tzstring)
{
- ptrdiff_t envptrs;
- char **from, **to, **newenv;
+ /* A buffer holding a string of the form "TZ=value", intended
+ to be part of the environment. */
+ static char *tzvalbuf;
+ static ptrdiff_t tzvalbufsize;
- /* Make the ENVIRON vector longer with room for TZSTRING. */
- for (from = environ; *from; from++)
- continue;
- envptrs = from - environ + 2;
- newenv = to = xmalloc (envptrs * sizeof *newenv
- + (tzstring ? strlen (tzstring) + 4 : 0));
+ int tzeqlen = sizeof "TZ=" - 1;
+
+#ifdef LOCALTIME_CACHE
+ /* These two values are known to load tz files in buggy implementations,
+ i.e., Solaris 1 executables running under either Solaris 1 or Solaris 2.
+ Their values shouldn't matter in non-buggy implementations.
+ We don't use string literals for these strings,
+ since if a string in the environment is in readonly
+ storage, it runs afoul of bugs in SVR4 and Solaris 2.3.
+ See Sun bugs 1113095 and 1114114, ``Timezone routines
+ improperly modify environment''. */
+
+ static char set_time_zone_rule_tz[][sizeof "TZ=GMT+0"]
+ = { "TZ=GMT+0", "TZ=GMT+1" };
+
+ /* In SunOS 4.1.3_U1 and 4.1.4, if TZ has a value like
+ "US/Pacific" that loads a tz file, then changes to a value like
+ "XXX0" that does not load a tz file, and then changes back to
+ its original value, the last change is (incorrectly) ignored.
+ Also, if TZ changes twice in succession to values that do
+ not load a tz file, tzset can dump core (see Sun bug#1225179).
+ The following code works around these bugs. */
- /* Add TZSTRING to the end of environ, as a value for TZ. */
if (tzstring)
{
- char *t = (char *) (to + envptrs);
- strcpy (t, "TZ=");
- strcat (t, tzstring);
- *to++ = t;
+ /* Temporarily set TZ to a value that loads a tz file
+ and that differs from tzstring. */
+ bool eq0 = strcmp (tzstring, set_time_zone_rule_tz[0] + tzeqlen) == 0;
+ xputenv (set_time_zone_rule_tz[eq0]);
}
+ else
+ {
+ /* The implied tzstring is unknown, so temporarily set TZ to
+ two different values that each load a tz file. */
+ xputenv (set_time_zone_rule_tz[0]);
+ tzset ();
+ xputenv (set_time_zone_rule_tz[1]);
+ }
+ tzset ();
+#endif
- /* Copy the old environ vector elements into NEWENV,
- but don't copy the TZ variable.
- So we have only one definition of TZ, which came from TZSTRING. */
- for (from = environ; *from; from++)
- if (strncmp (*from, "TZ=", 3) != 0)
- *to++ = *from;
- *to = 0;
-
- environ = newenv;
+ if (!tzstring)
+ {
+ unsetenv ("TZ");
+ tzvalbuf_in_environ = 0;
+ }
+ else
+ {
+ ptrdiff_t tzstringlen = strlen (tzstring);
- /* If we do have a TZSTRING, NEWENV points to the vector slot where
- the TZ variable is stored. If we do not have a TZSTRING,
- TO points to the vector slot which has the terminating null. */
+ if (tzvalbufsize <= tzeqlen + tzstringlen)
+ {
+ unsetenv ("TZ");
+ tzvalbuf_in_environ = 0;
+ tzvalbuf = xpalloc (tzvalbuf, &tzvalbufsize,
+ tzeqlen + tzstringlen - tzvalbufsize + 1, -1, 1);
+ memcpy (tzvalbuf, "TZ=", tzeqlen);
+ }
-#ifdef LOCALTIME_CACHE
- {
- /* In SunOS 4.1.3_U1 and 4.1.4, if TZ has a value like
- "US/Pacific" that loads a tz file, then changes to a value like
- "XXX0" that does not load a tz file, and then changes back to
- its original value, the last change is (incorrectly) ignored.
- Also, if TZ changes twice in succession to values that do
- not load a tz file, tzset can dump core (see Sun bug#1225179).
- The following code works around these bugs. */
-
- if (tzstring)
- {
- /* Temporarily set TZ to a value that loads a tz file
- and that differs from tzstring. */
- char *tz = *newenv;
- *newenv = (strcmp (tzstring, set_time_zone_rule_tz1 + 3) == 0
- ? set_time_zone_rule_tz2 : set_time_zone_rule_tz1);
- tzset ();
- *newenv = tz;
- }
- else
- {
- /* The implied tzstring is unknown, so temporarily set TZ to
- two different values that each load a tz file. */
- *to = set_time_zone_rule_tz1;
- to[1] = 0;
- tzset ();
- *to = set_time_zone_rule_tz2;
- tzset ();
- *to = 0;
- }
+ strcpy (tzvalbuf + tzeqlen, tzstring);
- /* Now TZ has the desired value, and tzset can be invoked safely. */
- }
+ if (!tzvalbuf_in_environ)
+ {
+ xputenv (tzvalbuf);
+ tzvalbuf_in_environ = 1;
+ }
+ }
+#ifdef LOCALTIME_CACHE
tzset ();
#endif
}
}
\f
DEFUN ("insert-char", Finsert_char, Sinsert_char, 1, 3,
- "(list (or (read-char-by-name \"Insert character (Unicode name or hex): \")\
- (error \"You did not specify a valid character\"))\
- (prefix-numeric-value current-prefix-arg)\
- t))",
+ "(list (read-char-by-name \"Insert character (Unicode name or hex): \")\
+ (prefix-numeric-value current-prefix-arg)\
+ t))",
doc: /* Insert COUNT copies of CHARACTER.
Interactively, prompt for CHARACTER. You can specify CHARACTER in one
of these ways:
Lisp_Object result, tem, tem1;
if (start < GPT && GPT < end)
- move_gap (start);
+ move_gap_both (start, start_byte);
if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
result = make_uninit_multibyte_string (end - start, end_byte - start_byte);
of the buffer. */)
(void)
{
- return make_buffer_string (BEGV, ZV, 1);
+ return make_buffer_string_both (BEGV, BEGV_BYTE, ZV, ZV_BYTE, 1);
}
DEFUN ("insert-buffer-substring", Finsert_buffer_substring, Sinsert_buffer_substring,
DEFUN ("compare-buffer-substrings", Fcompare_buffer_substrings, Scompare_buffer_substrings,
6, 6, 0,
doc: /* Compare two substrings of two buffers; return result as number.
-the value is -N if first string is less after N-1 chars,
-+N if first string is greater after N-1 chars, or 0 if strings match.
-Each substring is represented as three arguments: BUFFER, START and END.
-That makes six args in all, three for each substring.
+Return -N if first string is less after N-1 chars, +N if first string is
+greater after N-1 chars, or 0 if strings match. Each substring is
+represented as three arguments: BUFFER, START and END. That makes six
+args in all, three for each substring.
The value of `case-fold-search' in the current buffer
determines whether case is significant or ignored. */)
void
syms_of_editfns (void)
{
- environbuf = 0;
- initial_tz = 0;
-
DEFSYM (Qbuffer_access_fontify_functions, "buffer-access-fontify-functions");
DEFVAR_LISP ("inhibit-field-text-motion", Vinhibit_field_text_motion,
defsubr (&Suser_real_login_name);
defsubr (&Suser_uid);
defsubr (&Suser_real_uid);
+ defsubr (&Sgroup_gid);
+ defsubr (&Sgroup_real_gid);
defsubr (&Suser_full_name);
defsubr (&Semacs_pid);
defsubr (&Scurrent_time);