Make #'require's NOERROR arg do its job properly.
[sxemacs] / src / fns.c
index e438f05..8cec14c 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -46,6 +46,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 #include "systime.h"
 #include "ui/insdel.h"
 #include "lstream.h"
+#include "ent/ent.h"
 /* for the categorial views */
 #include "category.h"
 #include "seq.h"
@@ -147,11 +148,11 @@ Return a pseudo-random number.
 All integers representable in Lisp are equally likely.
 On most systems, this is 31 bits' worth.
 
-With positive integer argument LIMIT, return random number 
+With positive integer argument LIMIT, return random number
 in interval [0,LIMIT). LIMIT can be a big integer, in which
 case the range of possible values is extended.
 
-With argument t, set the random number seed from the 
+With argument t, set the random number seed from the
 current time and pid.
 */
       (limit))
@@ -694,12 +695,12 @@ concat(int nargs, Lisp_Object * args,
        Lisp_Object last_tail;
        Lisp_Object prev;
        struct merge_string_extents_struct *args_mse = 0;
-       Bufbyte *string_result = 0;
-       Bufbyte *string_result_ptr = 0;
+       Bufbyte *string_result = NULL;
+       Bufbyte *string_result_ptr = NULL;
        struct gcpro gcpro1;
        int speccount = specpdl_depth();
-        Charcount total_length;
-        
+       Charcount total_length;
+
 
        /* The modus operandi in Emacs is "caller gc-protects args".
           However, concat is called many times in Emacs on freshly
@@ -716,7 +717,7 @@ concat(int nargs, Lisp_Object * args,
           the result in the returned string's `string-translatable' property. */
 #endif
        if (target_type == c_string)
-                XMALLOC_OR_ALLOCA(args_mse, nargs, struct merge_string_extents_struct);
+               XMALLOC_OR_ALLOCA(args_mse, nargs, struct merge_string_extents_struct);
 
        /* In append, the last arg isn't treated like the others */
        if (last_special && nargs > 0) {
@@ -758,7 +759,7 @@ concat(int nargs, Lisp_Object * args,
                /* Charcount is a misnomer here as we might be dealing with the
                   length of a vector or list, but emphasizes that we're not dealing
                   with Bytecounts in strings */
-                /* Charcount total_length; */
+               /* Charcount total_length; */
 
                for (argnum = 0, total_length = 0; argnum < nargs; argnum++) {
 #ifdef LOSING_BYTECODE
@@ -772,21 +773,21 @@ concat(int nargs, Lisp_Object * args,
 
                switch (target_type) {
                case c_cons:
-                        if (total_length == 0) {
+                       if (total_length == 0) {
                                /* In append, if all but last arg are nil,
                                   return last arg */
-                                XMALLOC_UNBIND(args_mse, nargs, speccount);
+                               XMALLOC_UNBIND(args_mse, nargs, speccount);
                                RETURN_UNGCPRO(last_tail);
-                        }
+                       }
                        val = Fmake_list(make_int(total_length), Qnil);
                        break;
                case c_dllist:
-                        if (total_length == 0) {
+                       if (total_length == 0) {
                                /* In append, if all but last arg are nil,
                                   return last arg */
-                                XMALLOC_UNBIND(args_mse, nargs, speccount);
+                               XMALLOC_UNBIND(args_mse, nargs, speccount);
                                RETURN_UNGCPRO(last_tail);
-                        }
+                       }
                        val = Fmake_list(make_int(total_length), Qnil);
                        break;
                case c_vector:
@@ -807,7 +808,7 @@ concat(int nargs, Lisp_Object * args,
                           in order to make the char fit properly.  O(N^2)
                           yuckage. */
                        val = Qnil;
-                        XMALLOC_ATOMIC_OR_ALLOCA( string_result, 
+                       XMALLOC_ATOMIC_OR_ALLOCA( string_result,
                                                  total_length * MAX_EMCHAR_LEN,
                                                  Bufbyte );
                        string_result_ptr = string_result;
@@ -889,9 +890,13 @@ concat(int nargs, Lisp_Object * args,
                                                   XINT(elt));
                        } else {
                                CHECK_CHAR_COERCE_INT(elt);
-                               string_result_ptr +=
-                                   set_charptr_emchar(string_result_ptr,
-                                                      XCHAR(elt));
+                               if(string_result_ptr != NULL) {
+                                       string_result_ptr +=
+                                               set_charptr_emchar(string_result_ptr,
+                                                                  XCHAR(elt));
+                               } else {
+                                       abort();
+                               }
                        }
                }
                if (args_mse) {
@@ -907,18 +912,22 @@ concat(int nargs, Lisp_Object * args,
                val =
                    make_string(string_result,
                                string_result_ptr - string_result);
-               for (argnum = 0; argnum < nargs; argnum++) {
-                       if (STRINGP(args_mse[argnum].string))
-                               copy_string_extents(val,
-                                                   args_mse[argnum].string,
-                                                   args_mse[argnum].
-                                                   entry_offset, 0,
-                                                   args_mse[argnum].
-                                                   entry_length);
+               if (args_mse != NULL) {
+                       for (argnum = 0; argnum < nargs; argnum++) {
+                               if (STRINGP(args_mse[argnum].string))
+                                       copy_string_extents(val,
+                                                           args_mse[argnum].string,
+                                                           args_mse[argnum].
+                                                           entry_offset, 0,
+                                                           args_mse[argnum].
+                                                           entry_length);
+                       }
+                       XMALLOC_UNBIND(string_result,
+                                      total_length * MAX_EMCHAR_LEN, speccount);
+                       XMALLOC_UNBIND(args_mse, nargs, speccount);
+               } else {
+                       abort();
                }
-                XMALLOC_UNBIND(string_result,
-                              total_length * MAX_EMCHAR_LEN, speccount);
-                XMALLOC_UNBIND(args_mse, nargs, speccount);
        }
 
        if (!NILP(prev))
@@ -1005,7 +1014,7 @@ END may be nil or omitted; then the substring runs to the end of STRING.
 If START or END is negative, it counts from the end.
 Relevant parts of the string-extent-data are copied to the new string.
 */
-      (string, start, end)) 
+      (string, start, end))
 {
        Charcount ccstart, ccend;
        Bytecount bstart, blen;
@@ -1890,7 +1899,7 @@ list_merge(Lisp_Object org_l1, Lisp_Object org_l2,
 }
 \f
 /************************************************************************/
-/*                     property-list functions                         */
+/*                     property-list functions                         */
 /************************************************************************/
 
 /* For properties of text, we need to do order-insensitive comparison of
@@ -2739,7 +2748,7 @@ internal_equalp (Lisp_Object obj1, Lisp_Object obj2, int depth)
                const struct lrecord_implementation
                        *imp1 = XRECORD_LHEADER_IMPLEMENTATION (obj1),
                        *imp2 = XRECORD_LHEADER_IMPLEMENTATION (obj2);
-               
+
                /* #### not yet implemented properly, needs another flag to specify
                   equalp-ness */
                return (imp1 == imp2) &&
@@ -3157,13 +3166,29 @@ This function updates the value of the variable `features'.
        return feature;
 }
 
-DEFUN("require", Frequire, 1, 2, 0,    /*
-If feature FEATURE is not loaded, load it from FILENAME.
-If FEATURE is not a member of the list `features', then the feature
-is not loaded; so load the file FILENAME.
-If FILENAME is omitted, the printname of FEATURE is used as the file name.
-*/
-      (feature, filename))
+DEFUN("require", Frequire, 1, 3, 0, /*
+Ensure that FEATURE is present in the Lisp environment.
+FEATURE is a symbol naming a collection of resources (functions, etc).
+Optional FILENAME is a library from which to load resources; it defaults to
+the print name of FEATURE.
+Optional NOERROR, if non-nil, causes require to return nil rather than signal
+an error if loading the library fails.
+
+If feature FEATURE is present in `features', update `load-history' to reflect
+the require and return FEATURE.  Otherwise, try to load it from a library.
+The normal messages at start and end of loading are suppressed.
+If the library is successfully loaded and it calls `(provide FEATURE)', add
+FEATURE to `features', update `load-history' and return FEATURE.
+If the load succeeds but FEATURE is not provided by the library, signal
+`invalid-state'.
+
+The byte-compiler treats top-level calls to `require' specially, by evaluating
+them at compile time (and then compiling them normally).  Thus a library may
+request that definitions that should be inlined such as macros and defsubsts
+be loaded into its compilation environment.  Achieving this in other contexts
+requires an explicit \(eval-and-compile ...\) block.
+                                    */
+       (feature, filename, noerror))
 {
        Lisp_Object tem;
 
@@ -3180,14 +3205,20 @@ If FILENAME is omitted, the printname of FEATURE is used as the file name.
                record_unwind_protect(un_autoload, Vautoload_queue);
                Vautoload_queue = Qt;
 
-               /* defined in code-files.el */
-               call4(Qload, NILP(filename) ? Fsymbol_name(feature) : filename,
-                     Qnil, Qt, Qnil);
+               tem = call4(Qload, NILP(filename) ? Fsymbol_name(feature) : filename,
+                            noerror, Qrequire, Qnil);
+               /* If load failed entirely, return nil.  */
+               if (NILP(tem))
+                       return unbind_to(speccount, Qnil);
 
                tem = Fmemq(feature, Vfeatures);
-               if (NILP(tem))
-                       error("Required feature %s was not provided",
-                             string_data(XSYMBOL(feature)->name));
+               if (NILP(tem) && NILP(noerror)) {
+                       signal_type_error(Qinvalid_state,
+                                         "Required feature was not provided",
+                                         feature);
+               } else if (!NILP(noerror)) {
+                       return unbind_to(speccount, Qnil);
+               }
 
                /* Once loading finishes, don't undo it.  */
                Vautoload_queue = Qt;
@@ -3268,7 +3299,7 @@ static short base64_char_to_value[128] = {
                 .--------.  .--------.  .--------.
                 |aaaaaabb|  |bbbbcccc|  |ccdddddd|
                 `--------'  `--------'  `--------'
-                    6   2      4   4       2   6
+                   6   2      4   4       2   6
               .--------+--------+--------+--------.
               |00aaaaaa|00bbbbbb|00cccccc|00dddddd|
               `--------+--------+--------+--------'
@@ -3593,14 +3624,17 @@ Characters out of the base64 alphabet are ignored.
 \f
 /* base16 encode/decode functions. */
 static Bytind
-base16_encode_1(Lstream * istream, int length, Bufbyte * to)
+base16_encode_1(Lstream * istream, int length, Bufbyte * to, int max)
 {
        Emchar ec;
-       int i;
+       int i, sz;
 
        for (i=0; i < length; i++) {
                ec = Lstream_get_emchar (istream);
-               sprintf((char *)to+2*i,"%02x", ec);
+               sz = snprintf((char *)to+2*i, 3, "%02x", ec);
+               assert( sz >= 0 && sz < 3);
+               max -= sz;
+               assert(max >= 0);
        }
 
        return 1;
@@ -3624,7 +3658,7 @@ base16_decode_1(Lstream * istream, int length, Bufbyte * to)
                        low = ec - 'A' + 10;
                else if (islower(ec))
                        low = ec - 'a' + 10;
-               else 
+               else
                        ignore_p = 1;
 
                if (low < 0 || low >= 16)
@@ -3655,18 +3689,19 @@ into shorter lines.
        Charcount length;
        Bufbyte *encoded;
        Lisp_Object input, result;
+       int sz;
        int speccount = specpdl_depth();
 
        CHECK_STRING(string);
 
        length = XSTRING_CHAR_LENGTH(string);
-
+       sz = 2 * length;
        input = make_lisp_string_input_stream(string, 0, -1);
-       XMALLOC_ATOMIC_OR_ALLOCA(encoded, 2*length, Bufbyte);
-       base16_encode_1(XLSTREAM(input), length, encoded);
+       XMALLOC_ATOMIC_OR_ALLOCA(encoded, sz+1, Bufbyte);
+       base16_encode_1(XLSTREAM(input), length, encoded, sz);
        Lstream_delete(XLSTREAM(input));
-       result = make_string(encoded, 2*length);
-       XMALLOC_UNBIND(encoded, 2*length, speccount);
+       result = make_string(encoded, sz);
+       XMALLOC_UNBIND(encoded, sz+1, speccount);
 
        XSTRING(result)->plist = XSTRING(string)->plist;