gawk-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gawk-diffs] [SCM] gawk branch, extgawk, updated. 577c3fc31a2718461fba2e


From: Andrew J. Schorr
Subject: [gawk-diffs] [SCM] gawk branch, extgawk, updated. 577c3fc31a2718461fba2e599d162de96fe838fa
Date: Thu, 24 May 2012 19:34:53 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gawk".

The branch, extgawk has been updated
       via  577c3fc31a2718461fba2e599d162de96fe838fa (commit)
      from  c62b9d773bc064bc1dd5d8db35207fd4e6d42f1e (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://git.sv.gnu.org/cgit/gawk.git/commit/?id=577c3fc31a2718461fba2e599d162de96fe838fa

commit 577c3fc31a2718461fba2e599d162de96fe838fa
Author: Andrew J. Schorr <address@hidden>
Date:   Thu May 24 15:34:17 2012 -0400

    First working version of new API mechanism (probably has memory leaks).

diff --git a/ChangeLog b/ChangeLog
index 1b8c7b0..8814c36 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,55 @@
+2012-05-24         Andrew J. Schorr     <address@hidden>
+
+       * gawkapi.h (awk_param_type_t): Remove (use awk_valtype_t instead).
+       (awk_ext_func_t): Pass a result argument, and return an awk_value_t *.
+       (gawk_api.get_curfunc_param): Add a result argument.
+       (gawk_api.set_return_value): Remove obsolete function.
+       (gawk_api.sym_lookup, gawk_api.get_array_element): Add a result
+       argument.
+       (gawk_api.api_make_string, gawk_api.api_make_number): Remove hooks,
+       since access to gawk internal state is not required to do this.
+       (set_return_value): Remove obsolete macro.
+       (get_curfunc_param, sym_lookup, get_array_element): Add result argument.
+       (r_make_string, make_number): New static inline functions.
+       (make_string, dup_string): Revise macro definitions.
+       (dl_load_func): Remove global_api_p and global_ext_id args,
+       and fix SEGV by setting api prior to checking its version members.
+       (GAWK): Expand ifdef to include more stuff.
+       * gawkapi.c (node_to_awk_value): Add result argument.
+       (api_get_curfunc_param): Add result argument, and use awk_valtype_t.
+       (api_set_return_value): Remove obsolete function.
+       (awk_value_to_node): New global function to convert back into internal
+       format.
+       (api_add_ext_func): Simply call make_builtin.
+       (node_to_awk_value): Add result argument, and handle Node_val case.
+       (api_sym_lookup, api_get_array_element): Add result argument.
+       (api_set_array_element): Implement.
+       (api_make_string, api_make_number): Remove functions that belong on
+       client side.
+       (api_impl): Remove 3 obsolete entries.
+       * TODO.xgawk: Update to reflect progress.
+       * Makefile.am (base_sources): Add gawkapi.c.
+       * awk.h: Include gawkapi.h earlier.
+       (api_impl, init_ext_api, awk_value_to_node): Add declarations
+       so we can hook in new API.
+       (INSTRUCTION): Add new union type efptr for external functions.
+       (extfunc): New define for d.efptr.
+       (load_ext): Remove 3rd obj argument that was never used for anything.
+       (make_builtin): Change signature for new API.
+       * awkgram.y (load_library): Change 2nd argument to load_ext
+       from dlload to dl_load, and remove pointless 3rd argument.
+       * main.c (main): Call init_ext_api() before loading shared libraries.
+       Change 2nd argument to load_ext from dlload to dl_load, and remove
+       pointless 3rd argument.
+       * ext.c (do_ext): Remove pointless 3rd argument to load_ext.
+       (load_ext): Remove 3rd argument.  Port to new API (change initialization
+       function signature).  If initialization function fails, issue a warning
+       and return -1, else return 0.
+       (make_builtin): Port to new API.
+       * interpret.h (r_interpret): For Op_ext_builtin, call external functions
+       with an awk_value_t result buffer, and convert the returned value
+       to a NODE *.  For Node_ext_func, code now in extfunc instead of builtin.
+
 2012-05-21         Andrew J. Schorr     <address@hidden>
 
        * configure.ac: Remove libtool, and call configure in the
diff --git a/Makefile.am b/Makefile.am
index d92920b..b41c878 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -99,6 +99,7 @@ base_sources = \
        field.c \
        floatcomp.c \
        floatmagic.h \
+       gawkapi.c \
        gawkmisc.c \
        getopt.c \
        getopt.h \
diff --git a/Makefile.in b/Makefile.in
index 4f109d0..b2c812b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -106,10 +106,10 @@ PROGRAMS = $(bin_PROGRAMS)
 am__objects_1 = array.$(OBJEXT) awkgram.$(OBJEXT) builtin.$(OBJEXT) \
        cint_array.$(OBJEXT) command.$(OBJEXT) debug.$(OBJEXT) \
        dfa.$(OBJEXT) eval.$(OBJEXT) ext.$(OBJEXT) field.$(OBJEXT) \
-       floatcomp.$(OBJEXT) gawkmisc.$(OBJEXT) getopt.$(OBJEXT) \
-       getopt1.$(OBJEXT) int_array.$(OBJEXT) io.$(OBJEXT) \
-       main.$(OBJEXT) mpfr.$(OBJEXT) msg.$(OBJEXT) node.$(OBJEXT) \
-       profile.$(OBJEXT) random.$(OBJEXT) re.$(OBJEXT) \
+       floatcomp.$(OBJEXT) gawkapi.$(OBJEXT) gawkmisc.$(OBJEXT) \
+       getopt.$(OBJEXT) getopt1.$(OBJEXT) int_array.$(OBJEXT) \
+       io.$(OBJEXT) main.$(OBJEXT) mpfr.$(OBJEXT) msg.$(OBJEXT) \
+       node.$(OBJEXT) profile.$(OBJEXT) random.$(OBJEXT) re.$(OBJEXT) \
        regex.$(OBJEXT) replace.$(OBJEXT) str_array.$(OBJEXT) \
        symbol.$(OBJEXT) version.$(OBJEXT)
 am_gawk_OBJECTS = $(am__objects_1)
@@ -398,6 +398,7 @@ base_sources = \
        field.c \
        floatcomp.c \
        floatmagic.h \
+       gawkapi.c \
        gawkmisc.c \
        getopt.c \
        getopt.h \
@@ -558,6 +559,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
diff --git a/TODO.xgawk b/TODO.xgawk
index fe14b71..0746a66 100644
--- a/TODO.xgawk
+++ b/TODO.xgawk
@@ -1,10 +1,9 @@
 To-do list for xgawk enhancements:
 
 - Finish implementing new interface using gawkapi.h
-   - extension functions should return awk_value_t
-   - dl_load_func should be inside #ifndef GAWK, and does not need
-   global_api_p and global_ext_id args.
-   - awk_value_to_node in gawkapi.c needs to be declared in awk.h
+   - must update the API do_lint value when changed by set_LINT
+   - what is the proper return value for load_ext?  It does not matter
+   unless called by the "extension" function that nobody uses.
 
 - Attempting to load the same file with -f and -i (or @include) should
   be a fatal error.
diff --git a/awk.h b/awk.h
index 31ed1d3..0ac5958 100644
--- a/awk.h
+++ b/awk.h
@@ -705,12 +705,20 @@ enum redirval {
 
 struct break_point;
 
+#if 1
+#include "gawkapi.h"
+extern gawk_api_t api_impl;
+extern void init_ext_api(void);
+extern NODE *awk_value_to_node(const awk_value_t *);
+#endif
+
 typedef struct exp_instruction {
        struct exp_instruction *nexti;
        union {
                NODE *dn;
                struct exp_instruction *di;
                NODE *(*fptr)(int);
+               awk_value_t *(*efptr)(int, awk_value_t *);
                long dl;
                char *name;
        } d;
@@ -731,6 +739,7 @@ typedef struct exp_instruction {
 
 #define memory          d.dn
 #define builtin         d.fptr
+#define extfunc         d.efptr
 #define builtin_idx     d.dl
 
 #define expr_count      x.xl
@@ -875,9 +884,7 @@ typedef struct exp_instruction {
 /* Op_store_var */
 #define initval         x.xn
 
-#if 1
-#include "gawkapi.h"
-#else
+#if 0
 typedef struct iobuf {
        const char *name;       /* filename */
        int fd;                 /* file descriptor */
@@ -1493,9 +1500,9 @@ extern void dump_fcall_stack(FILE *fp);
 extern int register_exec_hook(Func_pre_exec preh, Func_post_exec posth);
 /* ext.c */
 NODE *do_ext(int nargs);
-NODE *load_ext(const char *lib_name, const char *init_func, NODE *obj);
+NODE *load_ext(const char *lib_name, const char *init_func);
 #ifdef DYNAMIC
-void make_builtin(const char *, NODE *(*)(int), int);
+awk_bool_t make_builtin(const awk_ext_func_t *);
 NODE *get_argument(int);
 NODE *get_actual_argument(int, bool, bool);
 #define get_scalar_argument(i, opt)  get_actual_argument((i), (opt), false)
diff --git a/awkgram.c b/awkgram.c
index fe3fd13..7836dbe 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -5157,7 +5157,7 @@ load_library(INSTRUCTION *file)
                return -1;
        }
 
-       (void) load_ext(s->fullpath, "dlload", NULL);
+       (void) load_ext(s->fullpath, "dl_load");
        return 0;
 }
 
diff --git a/awkgram.y b/awkgram.y
index 2a48a6f..f7ea5d4 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -2437,7 +2437,7 @@ load_library(INSTRUCTION *file)
                return -1;
        }
 
-       (void) load_ext(s->fullpath, "dlload", NULL);
+       (void) load_ext(s->fullpath, "dl_load");
        return 0;
 }
 
diff --git a/doc/ChangeLog b/doc/ChangeLog
index 5757259..756b841 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,8 @@
+2012-05-24         Andrew J. Schorr     <address@hidden>
+
+       * gawk.texi, gawk.1: Replace references to dlload with dl_load.
+       But much more work needs to be done on the docs.
+       
 2012-05-19         Andrew J. Schorr     <address@hidden>
 
        * gawk.texi, gawk.1: Document new -i option, and describe new default
diff --git a/doc/gawk.1 b/doc/gawk.1
index dbc527e..a2cfab6 100644
--- a/doc/gawk.1
+++ b/doc/gawk.1
@@ -347,7 +347,7 @@ This searches for the library using the
 environment variable.  If the initial search fails, another attempt will
 be made after appending the default shared library suffix for the platform.
 The library initialization routine is expected to be named
-.BR dlload() .
+.BR dl_load() .
 .TP
 .PD 0
 .BR "\-L " [ \fIvalue\fR ]
diff --git a/doc/gawk.info b/doc/gawk.info
index 0eb5dad..7109ee6 100644
--- a/doc/gawk.info
+++ b/doc/gawk.info
@@ -2315,7 +2315,7 @@ The following list describes options mandated by the 
POSIX standard:
      `AWKLIBPATH' environment variable.  The correct library suffix for
      your platform will be supplied by default, so it need not be
      specified in the library name.  The library initialization routine
-     should be named `dlload()'.  An alternative is to use the address@hidden'
+     should be named `dl_load()'.  An alternative is to use the address@hidden'
      keyword inside the program to load a shared library.
 
 `-L [value]'
@@ -22970,7 +22970,7 @@ command line option `-l':
      $ gawk -l libname -f myprog
 
    This will work only if the initialization routine is named
-`dlload()'.
+`dl_load()'.
 
    If you use `extension()', the library will be loaded at run time.
 This means that the functions are available only to the rest of your
@@ -22990,7 +22990,7 @@ the name of your library is `mylib.so', you can simply 
type
      $ gawk -l mylib -f myprog
 
    and `gawk' will do everything necessary to load in your library, and
-then call your `dlload()' routine.
+then call your `dl_load()' routine.
 
    You can always specify the library using an absolute pathname, in
 which case `gawk' will not use `AWKLIBPATH' to search for it.
@@ -23264,17 +23264,8 @@ calls are shown here, since they all follow the same 
pattern:
 
    Finally, it's necessary to provide the "glue" that loads the new
 function(s) into `gawk'.  By convention, each library has a routine
-named `dlload()' that does the job:
-
-     /* dlload --- load new builtins in this library */
-
-     NODE *
-     dlload(NODE *tree, void *dl)
-     {
-         make_builtin("chdir", do_chdir, 1);
-         make_builtin("stat", do_stat, 2);
-         return make_number((AWKNUM) 0);
-     }
+named `dl_load()' that does the job.  The simplest way is to use the
+`dl_load_func' macro in `gawkapi.h'.
 
    And that's it!  As an exercise, consider adding functions to
 implement system calls such as `chown()', `chmod()', and `umask()'.
@@ -23309,7 +23300,7 @@ shared library:
 
      # file testff.awk
      BEGIN {
-         extension("./filefuncs.so", "dlload")
+         extension("./filefuncs.so", "dl_load")
 
          chdir(".")  # no-op
 
@@ -28561,402 +28552,402 @@ Node: When96625
 Node: Invoking Gawk98772
 Node: Command Line100233
 Node: Options101016
-Ref: Options-Footnote-1116413
-Node: Other Arguments116438
-Node: Naming Standard Input119096
-Node: Environment Variables120190
-Node: AWKPATH Variable120748
-Ref: AWKPATH Variable-Footnote-1123506
-Node: AWKLIBPATH Variable123766
-Node: Other Environment Variables124363
-Node: Exit Status126858
-Node: Include Files127533
-Node: Loading Shared Libraries131102
-Node: Obsolete132327
-Node: Undocumented133024
-Node: Regexp133267
-Node: Regexp Usage134656
-Node: Escape Sequences136682
-Node: Regexp Operators142445
-Ref: Regexp Operators-Footnote-1149825
-Ref: Regexp Operators-Footnote-2149972
-Node: Bracket Expressions150070
-Ref: table-char-classes151960
-Node: GNU Regexp Operators154486
-Node: Case-sensitivity158209
-Ref: Case-sensitivity-Footnote-1161177
-Ref: Case-sensitivity-Footnote-2161412
-Node: Leftmost Longest161520
-Node: Computed Regexps162721
-Node: Reading Files166131
-Node: Records168135
-Ref: Records-Footnote-1176809
-Node: Fields176846
-Ref: Fields-Footnote-1179879
-Node: Nonconstant Fields179965
-Node: Changing Fields182167
-Node: Field Separators188148
-Node: Default Field Splitting190777
-Node: Regexp Field Splitting191894
-Node: Single Character Fields195236
-Node: Command Line Field Separator196295
-Node: Field Splitting Summary199736
-Ref: Field Splitting Summary-Footnote-1202928
-Node: Constant Size203029
-Node: Splitting By Content207613
-Ref: Splitting By Content-Footnote-1211339
-Node: Multiple Line211379
-Ref: Multiple Line-Footnote-1217226
-Node: Getline217405
-Node: Plain Getline219621
-Node: Getline/Variable221710
-Node: Getline/File222851
-Node: Getline/Variable/File224173
-Ref: Getline/Variable/File-Footnote-1225772
-Node: Getline/Pipe225859
-Node: Getline/Variable/Pipe228419
-Node: Getline/Coprocess229526
-Node: Getline/Variable/Coprocess230769
-Node: Getline Notes231483
-Node: Getline Summary233425
-Ref: table-getline-variants233768
-Node: Read Timeout234627
-Ref: Read Timeout-Footnote-1238372
-Node: Command line directories238429
-Node: Printing239059
-Node: Print240690
-Node: Print Examples242027
-Node: Output Separators244811
-Node: OFMT246571
-Node: Printf247929
-Node: Basic Printf248835
-Node: Control Letters250374
-Node: Format Modifiers254186
-Node: Printf Examples260195
-Node: Redirection262910
-Node: Special Files269894
-Node: Special FD270427
-Ref: Special FD-Footnote-1274052
-Node: Special Network274126
-Node: Special Caveats274976
-Node: Close Files And Pipes275772
-Ref: Close Files And Pipes-Footnote-1282795
-Ref: Close Files And Pipes-Footnote-2282943
-Node: Expressions283093
-Node: Values284225
-Node: Constants284901
-Node: Scalar Constants285581
-Ref: Scalar Constants-Footnote-1286440
-Node: Nondecimal-numbers286622
-Node: Regexp Constants289681
-Node: Using Constant Regexps290156
-Node: Variables293211
-Node: Using Variables293866
-Node: Assignment Options295590
-Node: Conversion297462
-Ref: table-locale-affects302838
-Ref: Conversion-Footnote-1303465
-Node: All Operators303574
-Node: Arithmetic Ops304204
-Node: Concatenation306709
-Ref: Concatenation-Footnote-1309502
-Node: Assignment Ops309622
-Ref: table-assign-ops314610
-Node: Increment Ops316021
-Node: Truth Values and Conditions319491
-Node: Truth Values320574
-Node: Typing and Comparison321623
-Node: Variable Typing322412
-Ref: Variable Typing-Footnote-1326309
-Node: Comparison Operators326431
-Ref: table-relational-ops326841
-Node: POSIX String Comparison330393
-Ref: POSIX String Comparison-Footnote-1331349
-Node: Boolean Ops331487
-Ref: Boolean Ops-Footnote-1335565
-Node: Conditional Exp335656
-Node: Function Calls337388
-Node: Precedence340982
-Node: Locales344651
-Node: Patterns and Actions345740
-Node: Pattern Overview346794
-Node: Regexp Patterns348463
-Node: Expression Patterns349006
-Node: Ranges352691
-Node: BEGIN/END355657
-Node: Using BEGIN/END356419
-Ref: Using BEGIN/END-Footnote-1359150
-Node: I/O And BEGIN/END359256
-Node: BEGINFILE/ENDFILE361538
-Node: Empty364431
-Node: Using Shell Variables364747
-Node: Action Overview367032
-Node: Statements369389
-Node: If Statement371243
-Node: While Statement372742
-Node: Do Statement374786
-Node: For Statement375942
-Node: Switch Statement379094
-Node: Break Statement381191
-Node: Continue Statement383181
-Node: Next Statement384974
-Node: Nextfile Statement387364
-Node: Exit Statement389909
-Node: Built-in Variables392325
-Node: User-modified393420
-Ref: User-modified-Footnote-1401775
-Node: Auto-set401837
-Ref: Auto-set-Footnote-1411745
-Node: ARGC and ARGV411950
-Node: Arrays415801
-Node: Array Basics417306
-Node: Array Intro418132
-Node: Reference to Elements422450
-Node: Assigning Elements424720
-Node: Array Example425211
-Node: Scanning an Array426943
-Node: Controlling Scanning429257
-Ref: Controlling Scanning-Footnote-1434190
-Node: Delete434506
-Ref: Delete-Footnote-1436941
-Node: Numeric Array Subscripts436998
-Node: Uninitialized Subscripts439181
-Node: Multi-dimensional440809
-Node: Multi-scanning443903
-Node: Arrays of Arrays445494
-Node: Functions450139
-Node: Built-in450961
-Node: Calling Built-in452039
-Node: Numeric Functions454027
-Ref: Numeric Functions-Footnote-1457859
-Ref: Numeric Functions-Footnote-2458216
-Ref: Numeric Functions-Footnote-3458264
-Node: String Functions458533
-Ref: String Functions-Footnote-1482030
-Ref: String Functions-Footnote-2482159
-Ref: String Functions-Footnote-3482407
-Node: Gory Details482494
-Ref: table-sub-escapes484173
-Ref: table-sub-posix-92485530
-Ref: table-sub-proposed486876
-Ref: table-posix-sub488229
-Ref: table-gensub-escapes489778
-Ref: Gory Details-Footnote-1490988
-Ref: Gory Details-Footnote-2491039
-Node: I/O Functions491190
-Ref: I/O Functions-Footnote-1497845
-Node: Time Functions497992
-Ref: Time Functions-Footnote-1508884
-Ref: Time Functions-Footnote-2508952
-Ref: Time Functions-Footnote-3509110
-Ref: Time Functions-Footnote-4509221
-Ref: Time Functions-Footnote-5509333
-Ref: Time Functions-Footnote-6509560
-Node: Bitwise Functions509826
-Ref: table-bitwise-ops510384
-Ref: Bitwise Functions-Footnote-1514547
-Node: Type Functions514731
-Node: I18N Functions515201
-Node: User-defined516828
-Node: Definition Syntax517632
-Ref: Definition Syntax-Footnote-1522542
-Node: Function Example522611
-Node: Function Caveats525205
-Node: Calling A Function525626
-Node: Variable Scope526741
-Node: Pass By Value/Reference528716
-Node: Return Statement532156
-Node: Dynamic Typing535137
-Node: Indirect Calls535872
-Node: Internationalization545557
-Node: I18N and L10N546996
-Node: Explaining gettext547682
-Ref: Explaining gettext-Footnote-1552748
-Ref: Explaining gettext-Footnote-2552932
-Node: Programmer i18n553097
-Node: Translator i18n557297
-Node: String Extraction558090
-Ref: String Extraction-Footnote-1559051
-Node: Printf Ordering559137
-Ref: Printf Ordering-Footnote-1561921
-Node: I18N Portability561985
-Ref: I18N Portability-Footnote-1564434
-Node: I18N Example564497
-Ref: I18N Example-Footnote-1567132
-Node: Gawk I18N567204
-Node: Arbitrary Precision Arithmetic567821
-Ref: Arbitrary Precision Arithmetic-Footnote-1570696
-Node: Floating-point Programming570844
-Node: Floating-point Representation576114
-Node: Floating-point Context577218
-Ref: table-ieee-formats578053
-Node: Rounding Mode579425
-Ref: table-rounding-modes580052
-Ref: Rounding Mode-Footnote-1583177
-Node: Arbitrary Precision Floats583358
-Ref: Arbitrary Precision Floats-Footnote-1585399
-Node: Setting Precision585710
-Node: Setting Rounding Mode588468
-Node: Floating-point Constants589385
-Node: Changing Precision590804
-Ref: Changing Precision-Footnote-1592204
-Node: Exact Arithmetic592377
-Node: Integer Programming595390
-Node: Arbitrary Precision Integers597170
-Ref: Arbitrary Precision Integers-Footnote-1600194
-Node: MPFR and GMP Libraries600340
-Node: Advanced Features600725
-Node: Nondecimal Data602248
-Node: Array Sorting603831
-Node: Controlling Array Traversal604528
-Node: Array Sorting Functions612765
-Ref: Array Sorting Functions-Footnote-1616439
-Ref: Array Sorting Functions-Footnote-2616532
-Node: Two-way I/O616726
-Ref: Two-way I/O-Footnote-1622158
-Node: TCP/IP Networking622228
-Node: Profiling625072
-Node: Library Functions632526
-Ref: Library Functions-Footnote-1635533
-Node: Library Names635704
-Ref: Library Names-Footnote-1639175
-Ref: Library Names-Footnote-2639395
-Node: General Functions639481
-Node: Strtonum Function640434
-Node: Assert Function643364
-Node: Round Function646690
-Node: Cliff Random Function648233
-Node: Ordinal Functions649249
-Ref: Ordinal Functions-Footnote-1652319
-Ref: Ordinal Functions-Footnote-2652571
-Node: Join Function652780
-Ref: Join Function-Footnote-1654551
-Node: Gettimeofday Function654751
-Node: Data File Management658466
-Node: Filetrans Function659098
-Node: Rewind Function663237
-Node: File Checking664624
-Node: Empty Files665718
-Node: Ignoring Assigns667948
-Node: Getopt Function669501
-Ref: Getopt Function-Footnote-1680805
-Node: Passwd Functions681008
-Ref: Passwd Functions-Footnote-1689983
-Node: Group Functions690071
-Node: Walking Arrays698155
-Node: Sample Programs699724
-Node: Running Examples700389
-Node: Clones701117
-Node: Cut Program702341
-Node: Egrep Program712186
-Ref: Egrep Program-Footnote-1719959
-Node: Id Program720069
-Node: Split Program723685
-Ref: Split Program-Footnote-1727204
-Node: Tee Program727332
-Node: Uniq Program730135
-Node: Wc Program737564
-Ref: Wc Program-Footnote-1741830
-Ref: Wc Program-Footnote-2742030
-Node: Miscellaneous Programs742122
-Node: Dupword Program743310
-Node: Alarm Program745341
-Node: Translate Program750090
-Ref: Translate Program-Footnote-1754477
-Ref: Translate Program-Footnote-2754705
-Node: Labels Program754839
-Ref: Labels Program-Footnote-1758210
-Node: Word Sorting758294
-Node: History Sorting762178
-Node: Extract Program764017
-Ref: Extract Program-Footnote-1771500
-Node: Simple Sed771628
-Node: Igawk Program774690
-Ref: Igawk Program-Footnote-1789847
-Ref: Igawk Program-Footnote-2790048
-Node: Anagram Program790186
-Node: Signature Program793254
-Node: Debugger794354
-Node: Debugging795306
-Node: Debugging Concepts795739
-Node: Debugging Terms797595
-Node: Awk Debugging800192
-Node: Sample Debugging Session801084
-Node: Debugger Invocation801604
-Node: Finding The Bug802933
-Node: List of Debugger Commands809421
-Node: Breakpoint Control810755
-Node: Debugger Execution Control814419
-Node: Viewing And Changing Data817779
-Node: Execution Stack821135
-Node: Debugger Info822602
-Node: Miscellaneous Debugger Commands826583
-Node: Readline Support832028
-Node: Limitations832859
-Node: Language History835111
-Node: V7/SVR3.1836623
-Node: SVR4838944
-Node: POSIX840386
-Node: BTL841394
-Node: POSIX/GNU842128
-Node: Common Extensions847419
-Node: Ranges and Locales848526
-Ref: Ranges and Locales-Footnote-1853130
-Node: Contributors853351
-Node: Installation857612
-Node: Gawk Distribution858506
-Node: Getting858990
-Node: Extracting859816
-Node: Distribution contents861508
-Node: Unix Installation866730
-Node: Quick Installation867347
-Node: Additional Configuration Options869309
-Node: Configuration Philosophy870786
-Node: Non-Unix Installation873128
-Node: PC Installation873586
-Node: PC Binary Installation874885
-Node: PC Compiling876733
-Node: PC Testing879677
-Node: PC Using880853
-Node: Cygwin885038
-Node: MSYS886038
-Node: VMS Installation886552
-Node: VMS Compilation887155
-Ref: VMS Compilation-Footnote-1888162
-Node: VMS Installation Details888220
-Node: VMS Running889855
-Node: VMS Old Gawk891462
-Node: Bugs891936
-Node: Other Versions895788
-Node: Notes901103
-Node: Compatibility Mode901795
-Node: Additions902578
-Node: Accessing The Source903390
-Node: Adding Code904815
-Node: New Ports910782
-Node: Dynamic Extensions914895
-Node: Internals916335
-Node: Plugin License925157
-Node: Loading Extensions925795
-Node: Sample Library927634
-Node: Internal File Description928324
-Node: Internal File Ops932039
-Ref: Internal File Ops-Footnote-1936781
-Node: Using Internal File Ops936921
-Node: Future Extensions939298
-Node: Basic Concepts941802
-Node: Basic High Level942559
-Ref: Basic High Level-Footnote-1946594
-Node: Basic Data Typing946779
-Node: Floating Point Issues951304
-Node: String Conversion Precision952387
-Ref: String Conversion Precision-Footnote-1954087
-Node: Unexpected Results954196
-Node: POSIX Floating Point Problems956022
-Ref: POSIX Floating Point Problems-Footnote-1959727
-Node: Glossary959765
-Node: Copying984741
-Node: GNU Free Documentation License1022298
-Node: Index1047435
+Ref: Options-Footnote-1116414
+Node: Other Arguments116439
+Node: Naming Standard Input119097
+Node: Environment Variables120191
+Node: AWKPATH Variable120749
+Ref: AWKPATH Variable-Footnote-1123507
+Node: AWKLIBPATH Variable123767
+Node: Other Environment Variables124364
+Node: Exit Status126859
+Node: Include Files127534
+Node: Loading Shared Libraries131103
+Node: Obsolete132328
+Node: Undocumented133025
+Node: Regexp133268
+Node: Regexp Usage134657
+Node: Escape Sequences136683
+Node: Regexp Operators142446
+Ref: Regexp Operators-Footnote-1149826
+Ref: Regexp Operators-Footnote-2149973
+Node: Bracket Expressions150071
+Ref: table-char-classes151961
+Node: GNU Regexp Operators154487
+Node: Case-sensitivity158210
+Ref: Case-sensitivity-Footnote-1161178
+Ref: Case-sensitivity-Footnote-2161413
+Node: Leftmost Longest161521
+Node: Computed Regexps162722
+Node: Reading Files166132
+Node: Records168136
+Ref: Records-Footnote-1176810
+Node: Fields176847
+Ref: Fields-Footnote-1179880
+Node: Nonconstant Fields179966
+Node: Changing Fields182168
+Node: Field Separators188149
+Node: Default Field Splitting190778
+Node: Regexp Field Splitting191895
+Node: Single Character Fields195237
+Node: Command Line Field Separator196296
+Node: Field Splitting Summary199737
+Ref: Field Splitting Summary-Footnote-1202929
+Node: Constant Size203030
+Node: Splitting By Content207614
+Ref: Splitting By Content-Footnote-1211340
+Node: Multiple Line211380
+Ref: Multiple Line-Footnote-1217227
+Node: Getline217406
+Node: Plain Getline219622
+Node: Getline/Variable221711
+Node: Getline/File222852
+Node: Getline/Variable/File224174
+Ref: Getline/Variable/File-Footnote-1225773
+Node: Getline/Pipe225860
+Node: Getline/Variable/Pipe228420
+Node: Getline/Coprocess229527
+Node: Getline/Variable/Coprocess230770
+Node: Getline Notes231484
+Node: Getline Summary233426
+Ref: table-getline-variants233769
+Node: Read Timeout234628
+Ref: Read Timeout-Footnote-1238373
+Node: Command line directories238430
+Node: Printing239060
+Node: Print240691
+Node: Print Examples242028
+Node: Output Separators244812
+Node: OFMT246572
+Node: Printf247930
+Node: Basic Printf248836
+Node: Control Letters250375
+Node: Format Modifiers254187
+Node: Printf Examples260196
+Node: Redirection262911
+Node: Special Files269895
+Node: Special FD270428
+Ref: Special FD-Footnote-1274053
+Node: Special Network274127
+Node: Special Caveats274977
+Node: Close Files And Pipes275773
+Ref: Close Files And Pipes-Footnote-1282796
+Ref: Close Files And Pipes-Footnote-2282944
+Node: Expressions283094
+Node: Values284226
+Node: Constants284902
+Node: Scalar Constants285582
+Ref: Scalar Constants-Footnote-1286441
+Node: Nondecimal-numbers286623
+Node: Regexp Constants289682
+Node: Using Constant Regexps290157
+Node: Variables293212
+Node: Using Variables293867
+Node: Assignment Options295591
+Node: Conversion297463
+Ref: table-locale-affects302839
+Ref: Conversion-Footnote-1303466
+Node: All Operators303575
+Node: Arithmetic Ops304205
+Node: Concatenation306710
+Ref: Concatenation-Footnote-1309503
+Node: Assignment Ops309623
+Ref: table-assign-ops314611
+Node: Increment Ops316022
+Node: Truth Values and Conditions319492
+Node: Truth Values320575
+Node: Typing and Comparison321624
+Node: Variable Typing322413
+Ref: Variable Typing-Footnote-1326310
+Node: Comparison Operators326432
+Ref: table-relational-ops326842
+Node: POSIX String Comparison330394
+Ref: POSIX String Comparison-Footnote-1331350
+Node: Boolean Ops331488
+Ref: Boolean Ops-Footnote-1335566
+Node: Conditional Exp335657
+Node: Function Calls337389
+Node: Precedence340983
+Node: Locales344652
+Node: Patterns and Actions345741
+Node: Pattern Overview346795
+Node: Regexp Patterns348464
+Node: Expression Patterns349007
+Node: Ranges352692
+Node: BEGIN/END355658
+Node: Using BEGIN/END356420
+Ref: Using BEGIN/END-Footnote-1359151
+Node: I/O And BEGIN/END359257
+Node: BEGINFILE/ENDFILE361539
+Node: Empty364432
+Node: Using Shell Variables364748
+Node: Action Overview367033
+Node: Statements369390
+Node: If Statement371244
+Node: While Statement372743
+Node: Do Statement374787
+Node: For Statement375943
+Node: Switch Statement379095
+Node: Break Statement381192
+Node: Continue Statement383182
+Node: Next Statement384975
+Node: Nextfile Statement387365
+Node: Exit Statement389910
+Node: Built-in Variables392326
+Node: User-modified393421
+Ref: User-modified-Footnote-1401776
+Node: Auto-set401838
+Ref: Auto-set-Footnote-1411746
+Node: ARGC and ARGV411951
+Node: Arrays415802
+Node: Array Basics417307
+Node: Array Intro418133
+Node: Reference to Elements422451
+Node: Assigning Elements424721
+Node: Array Example425212
+Node: Scanning an Array426944
+Node: Controlling Scanning429258
+Ref: Controlling Scanning-Footnote-1434191
+Node: Delete434507
+Ref: Delete-Footnote-1436942
+Node: Numeric Array Subscripts436999
+Node: Uninitialized Subscripts439182
+Node: Multi-dimensional440810
+Node: Multi-scanning443904
+Node: Arrays of Arrays445495
+Node: Functions450140
+Node: Built-in450962
+Node: Calling Built-in452040
+Node: Numeric Functions454028
+Ref: Numeric Functions-Footnote-1457860
+Ref: Numeric Functions-Footnote-2458217
+Ref: Numeric Functions-Footnote-3458265
+Node: String Functions458534
+Ref: String Functions-Footnote-1482031
+Ref: String Functions-Footnote-2482160
+Ref: String Functions-Footnote-3482408
+Node: Gory Details482495
+Ref: table-sub-escapes484174
+Ref: table-sub-posix-92485531
+Ref: table-sub-proposed486877
+Ref: table-posix-sub488230
+Ref: table-gensub-escapes489779
+Ref: Gory Details-Footnote-1490989
+Ref: Gory Details-Footnote-2491040
+Node: I/O Functions491191
+Ref: I/O Functions-Footnote-1497846
+Node: Time Functions497993
+Ref: Time Functions-Footnote-1508885
+Ref: Time Functions-Footnote-2508953
+Ref: Time Functions-Footnote-3509111
+Ref: Time Functions-Footnote-4509222
+Ref: Time Functions-Footnote-5509334
+Ref: Time Functions-Footnote-6509561
+Node: Bitwise Functions509827
+Ref: table-bitwise-ops510385
+Ref: Bitwise Functions-Footnote-1514548
+Node: Type Functions514732
+Node: I18N Functions515202
+Node: User-defined516829
+Node: Definition Syntax517633
+Ref: Definition Syntax-Footnote-1522543
+Node: Function Example522612
+Node: Function Caveats525206
+Node: Calling A Function525627
+Node: Variable Scope526742
+Node: Pass By Value/Reference528717
+Node: Return Statement532157
+Node: Dynamic Typing535138
+Node: Indirect Calls535873
+Node: Internationalization545558
+Node: I18N and L10N546997
+Node: Explaining gettext547683
+Ref: Explaining gettext-Footnote-1552749
+Ref: Explaining gettext-Footnote-2552933
+Node: Programmer i18n553098
+Node: Translator i18n557298
+Node: String Extraction558091
+Ref: String Extraction-Footnote-1559052
+Node: Printf Ordering559138
+Ref: Printf Ordering-Footnote-1561922
+Node: I18N Portability561986
+Ref: I18N Portability-Footnote-1564435
+Node: I18N Example564498
+Ref: I18N Example-Footnote-1567133
+Node: Gawk I18N567205
+Node: Arbitrary Precision Arithmetic567822
+Ref: Arbitrary Precision Arithmetic-Footnote-1570697
+Node: Floating-point Programming570845
+Node: Floating-point Representation576115
+Node: Floating-point Context577219
+Ref: table-ieee-formats578054
+Node: Rounding Mode579426
+Ref: table-rounding-modes580053
+Ref: Rounding Mode-Footnote-1583178
+Node: Arbitrary Precision Floats583359
+Ref: Arbitrary Precision Floats-Footnote-1585400
+Node: Setting Precision585711
+Node: Setting Rounding Mode588469
+Node: Floating-point Constants589386
+Node: Changing Precision590805
+Ref: Changing Precision-Footnote-1592205
+Node: Exact Arithmetic592378
+Node: Integer Programming595391
+Node: Arbitrary Precision Integers597171
+Ref: Arbitrary Precision Integers-Footnote-1600195
+Node: MPFR and GMP Libraries600341
+Node: Advanced Features600726
+Node: Nondecimal Data602249
+Node: Array Sorting603832
+Node: Controlling Array Traversal604529
+Node: Array Sorting Functions612766
+Ref: Array Sorting Functions-Footnote-1616440
+Ref: Array Sorting Functions-Footnote-2616533
+Node: Two-way I/O616727
+Ref: Two-way I/O-Footnote-1622159
+Node: TCP/IP Networking622229
+Node: Profiling625073
+Node: Library Functions632527
+Ref: Library Functions-Footnote-1635534
+Node: Library Names635705
+Ref: Library Names-Footnote-1639176
+Ref: Library Names-Footnote-2639396
+Node: General Functions639482
+Node: Strtonum Function640435
+Node: Assert Function643365
+Node: Round Function646691
+Node: Cliff Random Function648234
+Node: Ordinal Functions649250
+Ref: Ordinal Functions-Footnote-1652320
+Ref: Ordinal Functions-Footnote-2652572
+Node: Join Function652781
+Ref: Join Function-Footnote-1654552
+Node: Gettimeofday Function654752
+Node: Data File Management658467
+Node: Filetrans Function659099
+Node: Rewind Function663238
+Node: File Checking664625
+Node: Empty Files665719
+Node: Ignoring Assigns667949
+Node: Getopt Function669502
+Ref: Getopt Function-Footnote-1680806
+Node: Passwd Functions681009
+Ref: Passwd Functions-Footnote-1689984
+Node: Group Functions690072
+Node: Walking Arrays698156
+Node: Sample Programs699725
+Node: Running Examples700390
+Node: Clones701118
+Node: Cut Program702342
+Node: Egrep Program712187
+Ref: Egrep Program-Footnote-1719960
+Node: Id Program720070
+Node: Split Program723686
+Ref: Split Program-Footnote-1727205
+Node: Tee Program727333
+Node: Uniq Program730136
+Node: Wc Program737565
+Ref: Wc Program-Footnote-1741831
+Ref: Wc Program-Footnote-2742031
+Node: Miscellaneous Programs742123
+Node: Dupword Program743311
+Node: Alarm Program745342
+Node: Translate Program750091
+Ref: Translate Program-Footnote-1754478
+Ref: Translate Program-Footnote-2754706
+Node: Labels Program754840
+Ref: Labels Program-Footnote-1758211
+Node: Word Sorting758295
+Node: History Sorting762179
+Node: Extract Program764018
+Ref: Extract Program-Footnote-1771501
+Node: Simple Sed771629
+Node: Igawk Program774691
+Ref: Igawk Program-Footnote-1789848
+Ref: Igawk Program-Footnote-2790049
+Node: Anagram Program790187
+Node: Signature Program793255
+Node: Debugger794355
+Node: Debugging795307
+Node: Debugging Concepts795740
+Node: Debugging Terms797596
+Node: Awk Debugging800193
+Node: Sample Debugging Session801085
+Node: Debugger Invocation801605
+Node: Finding The Bug802934
+Node: List of Debugger Commands809422
+Node: Breakpoint Control810756
+Node: Debugger Execution Control814420
+Node: Viewing And Changing Data817780
+Node: Execution Stack821136
+Node: Debugger Info822603
+Node: Miscellaneous Debugger Commands826584
+Node: Readline Support832029
+Node: Limitations832860
+Node: Language History835112
+Node: V7/SVR3.1836624
+Node: SVR4838945
+Node: POSIX840387
+Node: BTL841395
+Node: POSIX/GNU842129
+Node: Common Extensions847420
+Node: Ranges and Locales848527
+Ref: Ranges and Locales-Footnote-1853131
+Node: Contributors853352
+Node: Installation857613
+Node: Gawk Distribution858507
+Node: Getting858991
+Node: Extracting859817
+Node: Distribution contents861509
+Node: Unix Installation866731
+Node: Quick Installation867348
+Node: Additional Configuration Options869310
+Node: Configuration Philosophy870787
+Node: Non-Unix Installation873129
+Node: PC Installation873587
+Node: PC Binary Installation874886
+Node: PC Compiling876734
+Node: PC Testing879678
+Node: PC Using880854
+Node: Cygwin885039
+Node: MSYS886039
+Node: VMS Installation886553
+Node: VMS Compilation887156
+Ref: VMS Compilation-Footnote-1888163
+Node: VMS Installation Details888221
+Node: VMS Running889856
+Node: VMS Old Gawk891463
+Node: Bugs891937
+Node: Other Versions895789
+Node: Notes901104
+Node: Compatibility Mode901796
+Node: Additions902579
+Node: Accessing The Source903391
+Node: Adding Code904816
+Node: New Ports910783
+Node: Dynamic Extensions914896
+Node: Internals916336
+Node: Plugin License925158
+Node: Loading Extensions925796
+Node: Sample Library927637
+Node: Internal File Description928327
+Node: Internal File Ops932042
+Ref: Internal File Ops-Footnote-1936607
+Node: Using Internal File Ops936747
+Node: Future Extensions939125
+Node: Basic Concepts941629
+Node: Basic High Level942386
+Ref: Basic High Level-Footnote-1946421
+Node: Basic Data Typing946606
+Node: Floating Point Issues951131
+Node: String Conversion Precision952214
+Ref: String Conversion Precision-Footnote-1953914
+Node: Unexpected Results954023
+Node: POSIX Floating Point Problems955849
+Ref: POSIX Floating Point Problems-Footnote-1959554
+Node: Glossary959592
+Node: Copying984568
+Node: GNU Free Documentation License1022125
+Node: Index1047262
 
 End Tag Table
diff --git a/doc/gawk.texi b/doc/gawk.texi
index 7e35e76..8c6f371 100644
--- a/doc/gawk.texi
+++ b/doc/gawk.texi
@@ -3235,7 +3235,7 @@ that @command{gawk} accepts and then exit.
 Load a shared library @var{lib}. This searches for the library using the 
@env{AWKLIBPATH}
 environment variable.  The correct library suffix for your platform will be
 supplied by default, so it need not be specified in the library name.
-The library initialization routine should be named @code{dlload()}.
+The library initialization routine should be named @code{dl_load()}.
 An alternative is to use the @samp{@@load} keyword inside the program to load
 a shared library.
 
@@ -30552,7 +30552,7 @@ command line option @option{-l}:
 $ @kbd{gawk -l libname -f myprog}
 @end example
 
-This will work only if the initialization routine is named @code{dlload()}.
+This will work only if the initialization routine is named @code{dl_load()}.
 
 If you use @code{extension()}, the library will be loaded
 at run time. This means that the functions are available only to the rest of
@@ -30576,7 +30576,7 @@ $ @kbd{gawk -l mylib -f myprog}
 @end example
 
 and @command{gawk} will do everything necessary to load in your library,
-and then call your @code{dlload()} routine.
+and then call your @code{dl_load()} routine.
 
 You can always specify the library using an absolute pathname, in which
 case @command{gawk} will not use @env{AWKLIBPATH} to search for it.
@@ -30905,19 +30905,8 @@ When done, return the @code{lstat()} return value:
 @cindex programming conventions, @command{gawk} internals
 Finally, it's necessary to provide the ``glue'' that loads the
 new function(s) into @command{gawk}.  By convention, each library has
-a routine named @code{dlload()} that does the job:
-
address@hidden
-/* dlload --- load new builtins in this library */
-
-NODE *
-dlload(NODE *tree, void *dl)
address@hidden
-    make_builtin("chdir", do_chdir, 1);
-    make_builtin("stat", do_stat, 2);
-    return make_number((AWKNUM) 0);
address@hidden
address@hidden example
+a routine named @code{dl_load()} that does the job.  The simplest way
+is to use the @code{dl_load_func} macro in @code{gawkapi.h}.
 
 And that's it!  As an exercise, consider adding functions to
 implement system calls such as @code{chown()}, @code{chmod()},
@@ -30952,7 +30941,7 @@ within the shared library:
 @example
 # file testff.awk
 BEGIN @{
-    extension("./filefuncs.so", "dlload")
+    extension("./filefuncs.so", "dl_load")
 
     chdir(".")  # no-op
 
diff --git a/ext.c b/ext.c
index 4dacad3..0da6174 100644
--- a/ext.c
+++ b/ext.c
@@ -42,12 +42,12 @@ do_ext(int nargs)
        SRCFILE *s;
        extern SRCFILE *srcfiles;
 
-       fun = POP_STRING();
-       obj = POP_STRING();
+       fun = POP_STRING();     /* name of initialization function */
+       obj = POP_STRING();     /* name of shared object */
 
        s = add_srcfile(SRC_EXTLIB, obj->stptr, srcfiles, NULL, NULL);
        if (s != NULL)
-               ret = load_ext(s->fullpath, fun->stptr, obj);
+               ret = load_ext(s->fullpath, fun->stptr);
        DEREF(obj);
        DEREF(fun);
        if (ret == NULL)
@@ -58,10 +58,9 @@ do_ext(int nargs)
 /* load_ext --- load an external library */
 
 NODE *
-load_ext(const char *lib_name, const char *init_func, NODE *obj)
+load_ext(const char *lib_name, const char *init_func)
 {
-       NODE *tmp = NULL;
-       NODE *(*func)(NODE *, void *);
+       int (*func)(const gawk_api_t *const, awk_ext_id_t);
        void *dl;
        int flags = RTLD_LAZY;
        int *gpl_compat;
@@ -85,33 +84,31 @@ load_ext(const char *lib_name, const char *init_func, NODE 
*obj)
        if (gpl_compat == NULL)
                fatal(_("extension: library `%s': does not define 
`plugin_is_GPL_compatible' (%s)\n"),
                                lib_name, dlerror());
-       func = (NODE *(*)(NODE *, void *)) dlsym(dl, init_func);
+       func = (int (*)(const gawk_api_t *const, awk_ext_id_t)) dlsym(dl, 
init_func);
        if (func == NULL)
                fatal(_("extension: library `%s': cannot call function `%s' 
(%s)\n"),
                                lib_name, init_func, dlerror());
 
-       if (obj == NULL) {
-               obj = make_string(lib_name, strlen(lib_name));
-               tmp = (*func)(obj, dl);
-               unref(tmp);
-               unref(obj);
-               return NULL;
+       if ((*func)(& api_impl, NULL /* ext_id */) == 0) {
+               warning(_("extension: library `%s' initialization routine `%s' 
failed\n"),
+                               lib_name, init_func);
+               return make_number(-1);
        }
-
-       tmp = (*func)(obj, dl);
-       return tmp; 
+       return make_number(0);
 }
 
 
 /* make_builtin --- register name to be called as func with a builtin body */
 
-void
-make_builtin(const char *name, NODE *(*func)(int), int count)
+awk_bool_t
+make_builtin(const awk_ext_func_t *funcinfo)
 {
        NODE *symbol, *f;
        INSTRUCTION *b;
        const char *sp;
        char c;
+       const char *name = funcinfo->name;
+       int count = funcinfo->num_args_expected;
 
        sp = name;
        if (sp == NULL || *sp == '\0')
@@ -133,7 +130,7 @@ make_builtin(const char *name, NODE *(*func)(int), int 
count)
                        /* multiple extension() calls etc. */ 
                        if (do_lint)
                                lintwarn(_("extension: function `%s' already 
defined"), name);
-                       return;
+                       return false;
                } else
                        /* variable name etc. */ 
                        fatal(_("extension: function name `%s' previously 
defined"), name);
@@ -145,13 +142,14 @@ make_builtin(const char *name, NODE *(*func)(int), int 
count)
                                name);
 
        b = bcalloc(Op_symbol, 1, 0);
-       b->builtin = func;
+       b->extfunc = funcinfo->function;
        b->expr_count = count;
 
        /* NB: extension sub must return something */
 
                symbol = install_symbol(estrdup(name, strlen(name)), 
Node_ext_func);
        symbol->code_ptr = b;
+       return true;
 }
 
 
diff --git a/extension/ChangeLog b/extension/ChangeLog
index 692647a..11c9f4d 100644
--- a/extension/ChangeLog
+++ b/extension/ChangeLog
@@ -1,3 +1,15 @@
+2012-05-24         Andrew J. Schorr     <address@hidden>
+
+       * Makefile.am (AM_CPPFLAGS): Use $(srcdir) to work properly when
+       built outside the source directory.
+       * configure.ac (INSTALL): Set location manually since autoconf was
+       not specifying the proper path for install-sh.
+       * filefuncs2.c, ordchr2.c, readfile2.c: Deleted.
+       * filefuncs.c: Install filefuncs2.c and patch for recent API changes.
+       * ordchr.c: Install ordchr2.c and patch for recent API changes.
+       * readfile.c: Install readfile2.c and patch for recent API changes.
+       * fork.c: Port to new API.
+
 2012-05-21         Andrew J. Schorr     <address@hidden>
 
        * configure.ac: New file to run configure with libtool support
diff --git a/extension/Makefile.am b/extension/Makefile.am
index b8b4359..8161223 100644
--- a/extension/Makefile.am
+++ b/extension/Makefile.am
@@ -23,7 +23,7 @@
 
 ## Process this file with automake to produce Makefile.in.
 
-AM_CPPFLAGS = -I..
+AM_CPPFLAGS = -I$(srcdir)/..
 
 # This variable insures that aclocal runs
 # correctly after changing configure.ac
diff --git a/extension/Makefile.in b/extension/Makefile.in
index e8f10d0..c90a0b4 100644
--- a/extension/Makefile.in
+++ b/extension/Makefile.in
@@ -84,9 +84,10 @@ DIST_COMMON = README $(am__configure_deps) 
$(srcdir)/Makefile.am \
        $(top_srcdir)/build-aux/install-sh \
        $(top_srcdir)/build-aux/ltmain.sh \
        $(top_srcdir)/build-aux/missing $(top_srcdir)/configure \
-       AUTHORS COPYING ChangeLog INSTALL NEWS build-aux/ar-lib \
-       build-aux/config.guess build-aux/config.sub build-aux/depcomp \
-       build-aux/install-sh build-aux/ltmain.sh build-aux/missing
+       AUTHORS COPYING ChangeLog INSTALL NEWS build-aux/ChangeLog \
+       build-aux/ar-lib build-aux/config.guess build-aux/config.sub \
+       build-aux/depcomp build-aux/install-sh build-aux/ltmain.sh \
+       build-aux/missing
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
        $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
@@ -310,7 +311,7 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-AM_CPPFLAGS = -I..
+AM_CPPFLAGS = -I$(srcdir)/..
 
 # This variable insures that aclocal runs
 # correctly after changing configure.ac
diff --git a/extension/configure b/extension/configure
index bb78dde..7333bda 100755
--- a/extension/configure
+++ b/extension/configure
@@ -2138,6 +2138,9 @@ ac_configure="$SHELL $ac_aux_dir/configure"  # Please 
don't use this var.
 
 
 
+INSTALL="$ac_aux_dir/install-sh -c"
+export INSTALL
+
 am__api_version='1.12'
 
 # Find a good install program.  We prefer a C program (faster),
diff --git a/extension/configure.ac b/extension/configure.ac
index 9d58dc2..461826e 100644
--- a/extension/configure.ac
+++ b/extension/configure.ac
@@ -28,11 +28,15 @@ AC_INIT([GNU Awk Bundled Extensions], 4.0.70, 
address@hidden, gawk-extensions)
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_AUX_DIR([build-aux])
 
+INSTALL="$ac_aux_dir/install-sh -c"
+export INSTALL
+
 AM_INIT_AUTOMAKE([-Wall -Werror])
 
 AM_PROG_AR
 AC_DISABLE_STATIC
 AC_PROG_LIBTOOL
+dnl AC_PROG_INSTALL
 
 AC_SUBST([pkgextensiondir], ['${libdir}/gawk'])
 
diff --git a/extension/filefuncs.c b/extension/filefuncs.c
index 01f3fce..74a086a 100644
--- a/extension/filefuncs.c
+++ b/extension/filefuncs.c
@@ -7,7 +7,8 @@
  */
 
 /*
- * Copyright (C) 2001, 2004, 2005, 2010, 2011 the Free Software Foundation, 
Inc.
+ * Copyright (C) 2001, 2004, 2005, 2010, 2011, 2012
+ * the Free Software Foundation, Inc.
  * 
  * This file is part of GAWK, the GNU implementation of the
  * AWK Programming Language.
@@ -27,28 +28,40 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
  */
 
-#include "awk.h"
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "gawkapi.h"
+
+static const gawk_api_t *api;  /* for convenience macros to work */
+static awk_ext_id_t *ext_id;
 
 int plugin_is_GPL_compatible;
 
 /*  do_chdir --- provide dynamically loaded chdir() builtin for gawk */
 
-static NODE *
-do_chdir(int nargs)
+static awk_value_t *
+do_chdir(int nargs, awk_value_t *result)
 {
-       NODE *newdir;
+       awk_value_t newdir;
        int ret = -1;
 
        if (do_lint && nargs != 1)
-               lintwarn("chdir: called with incorrect number of arguments");
+               lintwarn(ext_id, "chdir: called with incorrect number of 
arguments");
 
-       newdir = get_scalar_argument(0, false);
-       (void) force_string(newdir);
-       ret = chdir(newdir->stptr);
-       if (ret < 0)
-               update_ERRNO_int(errno);
+       if (get_curfunc_param(0, AWK_STRING, &newdir) != NULL) {
+               ret = chdir(newdir.str_value.str);
+               if (ret < 0)
+                       update_ERRNO_int(errno);
+       }
 
-       return make_number((AWKNUM) ret);
+       return make_number(ret, result);
 }
 
 /* format_mode --- turn a stat mode field into something readable */
@@ -57,7 +70,15 @@ static char *
 format_mode(unsigned long fmode)
 {
        static char outbuf[12];
-       int i;
+       static struct mode_map {
+               int mask;
+               int rep;
+       } map[] = {
+               { S_IRUSR, 'r' }, { S_IWUSR, 'w' }, { S_IXUSR, 'x' },
+               { S_IRGRP, 'r' }, { S_IWGRP, 'w' }, { S_IXGRP, 'x' },
+               { S_IROTH, 'r' }, { S_IWOTH, 'w' }, { S_IXOTH, 'x' },
+       };
+       int i, j, k;
 
        strcpy(outbuf, "----------");
        /* first, get the file type */
@@ -97,39 +118,16 @@ format_mode(unsigned long fmode)
 #endif
        }
 
-       i++;
-       if ((fmode & S_IRUSR) != 0)
-               outbuf[i] = 'r';
-       i++;
-       if ((fmode & S_IWUSR) != 0)
-               outbuf[i] = 'w';
-       i++;
-       if ((fmode & S_IXUSR) != 0)
-               outbuf[i] = 'x';
-       i++;
-
-       if ((fmode & S_IRGRP) != 0)
-               outbuf[i] = 'r';
-       i++;
-       if ((fmode & S_IWGRP) != 0)
-               outbuf[i] = 'w';
-       i++;
-       if ((fmode & S_IXGRP) != 0)
-               outbuf[i] = 'x';
-       i++;
+       for (j = 0, k = sizeof(map)/sizeof(map[0]); j < k; j++) {
+               i++;
+               if ((fmode & map[j].mask) != 0)
+                       outbuf[i] = map[j].rep;
+       }
 
-       if ((fmode & S_IROTH) != 0)
-               outbuf[i] = 'r';
-       i++;
-       if ((fmode & S_IWOTH) != 0)
-               outbuf[i] = 'w';
        i++;
-       if ((fmode & S_IXOTH) != 0)
-               outbuf[i] = 'x';
-       i++;
-
        outbuf[i] = '\0';
 
+       /* setuid bit */
        if ((fmode & S_ISUID) != 0) {
                if (outbuf[3] == 'x')
                        outbuf[3] = 's';
@@ -145,6 +143,7 @@ format_mode(unsigned long fmode)
                        outbuf[6] = 'l';
        }
 
+       /* the so-called "sticky" bit */
        if ((fmode & S_ISVTX) != 0) {
                if (outbuf[9] == 'x')
                        outbuf[9] = 't';
@@ -158,7 +157,7 @@ format_mode(unsigned long fmode)
 /* read_symlink -- read a symbolic link into an allocated buffer.
    This is based on xreadlink; the basic problem is that lstat cannot be relied
    upon to return the proper size for a symbolic link.  This happens,
-   for example, on linux in the /proc filesystem, where the symbolic link
+   for example, on GNU/Linux in the /proc filesystem, where the symbolic link
    sizes are often 0. */
 
 #ifndef SIZE_MAX
@@ -176,10 +175,12 @@ read_symlink(const char *fname, size_t bufsize, ssize_t 
*linksize)
        if (bufsize)
                bufsize += 2;
        else
-               bufsize = BUFSIZ*2;
+               bufsize = BUFSIZ * 2;
+
        /* Make sure that bufsize >= 2 and within range */
-       if ((bufsize > MAXSIZE) || (bufsize < 2))
+       if (bufsize > MAXSIZE || bufsize < 2)
                bufsize = MAXSIZE;
+
        while (1) {
                char *buf;
 
@@ -212,93 +213,106 @@ read_symlink(const char *fname, size_t bufsize, ssize_t 
*linksize)
 /* array_set --- set an array element */
 
 static void
-array_set(NODE *array, const char *sub, NODE *value)
+array_set(awk_array_t array, const char *sub, awk_value_t *value)
+{
+       awk_element_t element;
+       awk_value_t tmp;
+
+       memset(& element, 0, sizeof(element));
+
+       element.index = dup_string(sub, strlen(sub), & tmp)->str_value;
+       element.value = *value;
+
+       set_array_element(array, & element);
+}
+
+static void
+array_set_numeric(awk_array_t array, const char *sub, double num)
 {
-       NODE *tmp;
-       NODE **aptr;
-
-       tmp = make_string(sub, strlen(sub));
-       aptr = assoc_lookup(array, tmp);
-       unref(tmp);
-       /* 
-        * Note: since we initialized with assoc_clear, we know that aptr
-        * has been initialized with Nnull_string.  Thus, the call to
-        * unref(*aptr) is not strictly necessary.  However, I think it is
-        * generally more correct to call unref to maintain the proper
-        * reference count.
-        */
-       unref(*aptr);
-       *aptr = value;
+       awk_value_t tmp;
+       return array_set(array, sub, make_number(num, & tmp));
 }
 
 /* do_stat --- provide a stat() function for gawk */
 
-static NODE *
-do_stat(int nargs)
+static awk_value_t *
+do_stat(int nargs, awk_value_t *result)
 {
-       NODE *file, *array;
+       awk_value_t file_param, array_param;
+       char *name;
+       awk_array_t array;
        struct stat sbuf;
        int ret;
        char *pmode;    /* printable mode */
        char *type = "unknown";
+       awk_value_t tmp;
 
-       if (do_lint && nargs > 2)
-               lintwarn("stat: called with too many arguments");
+       if (do_lint && nargs != 2) {
+               lintwarn(ext_id, "stat: called with wrong number of arguments");
+               /* XXX previous version returned 0; why? */
+               return make_number(-1, result);
+       }
 
        /* file is first arg, array to hold results is second */
-       file = get_scalar_argument(0, false);
-       array = get_array_argument(1, false);
+       if (get_curfunc_param(0, AWK_STRING, &file_param) == NULL ||
+           get_curfunc_param(1, AWK_ARRAY, &array_param) == NULL) {
+               warning(ext_id, "stat: bad parameters");
+               /* XXX previous version returned 0; why? */
+               return make_number(-1, result);
+       }
+
+       name = file_param.str_value.str;
+       array = array_param.array_cookie;
 
        /* empty out the array */
-       assoc_clear(array);
+       clear_array(array);
 
        /* lstat the file, if error, set ERRNO and return */
-       (void) force_string(file);
-       ret = lstat(file->stptr, & sbuf);
+       ret = lstat(name, & sbuf);
        if (ret < 0) {
                update_ERRNO_int(errno);
-               return make_number((AWKNUM) ret);
+               /* XXX previous version returned 0; why? */
+               return make_number(-1, result);
        }
 
        /* fill in the array */
-       array_set(array, "name", dupnode(file));
-       array_set(array, "dev", make_number((AWKNUM) sbuf.st_dev));
-       array_set(array, "ino", make_number((AWKNUM) sbuf.st_ino));
-       array_set(array, "mode", make_number((AWKNUM) sbuf.st_mode));
-       array_set(array, "nlink", make_number((AWKNUM) sbuf.st_nlink));
-       array_set(array, "uid", make_number((AWKNUM) sbuf.st_uid));
-       array_set(array, "gid", make_number((AWKNUM) sbuf.st_gid));
-       array_set(array, "size", make_number((AWKNUM) sbuf.st_size));
-       array_set(array, "blocks", make_number((AWKNUM) sbuf.st_blocks));
-       array_set(array, "atime", make_number((AWKNUM) sbuf.st_atime));
-       array_set(array, "mtime", make_number((AWKNUM) sbuf.st_mtime));
-       array_set(array, "ctime", make_number((AWKNUM) sbuf.st_ctime));
+       array_set(array, "name", make_string(name, file_param.str_value.len, 
&tmp));
+       array_set_numeric(array, "dev", sbuf.st_dev);
+       array_set_numeric(array, "ino", sbuf.st_ino);
+       array_set_numeric(array, "mode", sbuf.st_mode);
+       array_set_numeric(array, "nlink", sbuf.st_nlink);
+       array_set_numeric(array, "uid", sbuf.st_uid);
+       array_set_numeric(array, "gid", sbuf.st_gid);
+       array_set_numeric(array, "size", sbuf.st_size);
+       array_set_numeric(array, "blocks", sbuf.st_blocks);
+       array_set_numeric(array, "atime", sbuf.st_atime);
+       array_set_numeric(array, "mtime", sbuf.st_mtime);
+       array_set_numeric(array, "ctime", sbuf.st_ctime);
 
        /* for block and character devices, add rdev, major and minor numbers */
        if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) {
-               array_set(array, "rdev", make_number((AWKNUM) sbuf.st_rdev));
-               array_set(array, "major", make_number((AWKNUM) 
major(sbuf.st_rdev)));
-               array_set(array, "minor", make_number((AWKNUM) 
minor(sbuf.st_rdev)));
+               array_set_numeric(array, "rdev", sbuf.st_rdev);
+               array_set_numeric(array, "major", major(sbuf.st_rdev));
+               array_set_numeric(array, "minor", minor(sbuf.st_rdev));
        }
 
 #ifdef HAVE_ST_BLKSIZE
-       array_set(array, "blksize", make_number((AWKNUM) sbuf.st_blksize));
+       array_set_numeric(array, "blksize", sbuf.st_blksize);
 #endif /* HAVE_ST_BLKSIZE */
 
        pmode = format_mode(sbuf.st_mode);
-       array_set(array, "pmode", make_string(pmode, strlen(pmode)));
+       array_set(array, "pmode", make_string(pmode, strlen(pmode), &tmp));
 
        /* for symbolic links, add a linkval field */
        if (S_ISLNK(sbuf.st_mode)) {
                char *buf;
                ssize_t linksize;
 
-               if ((buf = read_symlink(file->stptr, sbuf.st_size,
+               if ((buf = read_symlink(name, sbuf.st_size,
                                        &linksize)) != NULL)
-                       array_set(array, "linkval", make_str_node(buf, 
linksize, ALREADY_MALLOCED));
+                       array_set(array, "linkval", make_string(buf, linksize, 
&tmp));
                else
-                       warning(_("unable to read symbolic link `%s'"),
-                               file->stptr);
+                       warning(ext_id, "unable to read symbolic link `%s'", 
name);
        }
 
        /* add a type field */
@@ -337,18 +351,19 @@ do_stat(int nargs)
 #endif
        }
 
-       array_set(array, "type", make_string(type, strlen(type)));
+       array_set(array, "type", make_string(type, strlen(type), &tmp));
 
-       return make_number((AWKNUM) ret);
+       ret = 1;        /* success */
+
+       return make_number(ret, result);
 }
 
-/* dlload --- load new builtins in this library */
+static awk_ext_func_t func_table[] = {
+       { "chdir", do_chdir, 1 },
+       { "stat", do_stat, 2 },
+};
 
-NODE *
-dlload(NODE *tree, void *dl)
-{
-       make_builtin("chdir", do_chdir, 1);
-       make_builtin("stat", do_stat, 2);
 
-       return make_number((AWKNUM) 0);
-}
+/* define the dl_load function using the boilerplate macro */
+
+dl_load_func(func_table, filefuncs, "")
diff --git a/extension/filefuncs2.c b/extension/filefuncs2.c
deleted file mode 100644
index 67b1418..0000000
--- a/extension/filefuncs2.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * filefuncs.c - Builtin functions that provide initial minimal iterface
- *              to the file system.
- *
- * Arnold Robbins, update for 3.1, Mon Nov 23 12:53:39 EST 1998
- * Arnold Robbins and John Haque, update for 3.1.4, applied Mon Jun 14 
13:55:30 IDT 2004
- */
-
-/*
- * Copyright (C) 2001, 2004, 2005, 2010, 2011, 2012
- * the Free Software Foundation, Inc.
- * 
- * This file is part of GAWK, the GNU implementation of the
- * AWK Programming Language.
- * 
- * GAWK is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- * 
- * GAWK is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "gawkapi.h"
-
-static const gawk_api_t *api;  /* for convenience macros to work */
-static awk_ext_id_t *ext_id;
-
-int plugin_is_GPL_compatible;
-
-/*  do_chdir --- provide dynamically loaded chdir() builtin for gawk */
-
-int
-do_chdir(int nargs)
-{
-       const awk_value_t *newdir;
-       awk_value_t result;
-       int ret = -1;
-
-       if (do_lint && nargs != 1)
-               lintwarn(ext_id, "chdir: called with incorrect number of 
arguments");
-
-       newdir = get_curfunc_param(0, AWK_PARAM_STRING);
-       ret = chdir(newdir->str_value.str);
-       if (ret < 0)
-               update_ERRNO_int(errno);
-
-       result.val_type = AWK_NUMBER;
-       result.num_value = ret;
-       set_return_value(& result);
-       return 1;
-}
-
-/* format_mode --- turn a stat mode field into something readable */
-
-static char *
-format_mode(unsigned long fmode)
-{
-       static char outbuf[12];
-       static struct mode_map {
-               int mask;
-               int rep;
-       } map[] = {
-               { S_IRUSR, 'r' }, { S_IWUSR, 'w' }, { S_IXUSR, 'x' },
-               { S_IRGRP, 'r' }, { S_IWGRP, 'w' }, { S_IXGRP, 'x' },
-               { S_IROTH, 'r' }, { S_IWOTH, 'w' }, { S_IXOTH, 'x' },
-       };
-       int i, j, k;
-
-       strcpy(outbuf, "----------");
-       /* first, get the file type */
-       i = 0;
-       switch (fmode & S_IFMT) {
-#ifdef S_IFSOCK
-       case S_IFSOCK:
-               outbuf[i] = 's';
-               break;
-#endif
-#ifdef S_IFLNK
-       case S_IFLNK:
-               outbuf[i] = 'l';
-               break;
-#endif
-       case S_IFREG:
-               outbuf[i] = '-';        /* redundant */
-               break;
-       case S_IFBLK:
-               outbuf[i] = 'b';
-               break;
-       case S_IFDIR:
-               outbuf[i] = 'd';
-               break;
-#ifdef S_IFDOOR        /* Solaris weirdness */
-       case S_IFDOOR:
-               outbuf[i] = 'D';
-               break;
-#endif /* S_IFDOOR */
-       case S_IFCHR:
-               outbuf[i] = 'c';
-               break;
-#ifdef S_IFIFO
-       case S_IFIFO:
-               outbuf[i] = 'p';
-               break;
-#endif
-       }
-
-       for (j = 0, k = sizeof(map)/sizeof(map[0]); j < k; j++) {
-               i++;
-               if ((fmode & map[j].mask) != 0)
-                       outbuf[i] = map[j].rep;
-       }
-
-       i++;
-       outbuf[i] = '\0';
-
-       /* setuid bit */
-       if ((fmode & S_ISUID) != 0) {
-               if (outbuf[3] == 'x')
-                       outbuf[3] = 's';
-               else
-                       outbuf[3] = 'S';
-       }
-
-       /* setgid without execute == locking */
-       if ((fmode & S_ISGID) != 0) {
-               if (outbuf[6] == 'x')
-                       outbuf[6] = 's';
-               else
-                       outbuf[6] = 'l';
-       }
-
-       /* the so-called "sticky" bit */
-       if ((fmode & S_ISVTX) != 0) {
-               if (outbuf[9] == 'x')
-                       outbuf[9] = 't';
-               else
-                       outbuf[9] = 'T';
-       }
-
-       return outbuf;
-}
-
-/* read_symlink -- read a symbolic link into an allocated buffer.
-   This is based on xreadlink; the basic problem is that lstat cannot be relied
-   upon to return the proper size for a symbolic link.  This happens,
-   for example, on GNU/Linux in the /proc filesystem, where the symbolic link
-   sizes are often 0. */
-
-#ifndef SIZE_MAX
-# define SIZE_MAX ((size_t) -1)
-#endif
-#ifndef SSIZE_MAX
-# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
-#endif
-
-#define MAXSIZE (SIZE_MAX < SSIZE_MAX ? SIZE_MAX : SSIZE_MAX)
-
-static char *
-read_symlink(const char *fname, size_t bufsize, ssize_t *linksize)
-{
-       if (bufsize)
-               bufsize += 2;
-       else
-               bufsize = BUFSIZ * 2;
-
-       /* Make sure that bufsize >= 2 and within range */
-       if (bufsize > MAXSIZE || bufsize < 2)
-               bufsize = MAXSIZE;
-
-       while (1) {
-               char *buf;
-
-               emalloc(buf, char *, bufsize, "read_symlink");
-               if ((*linksize = readlink(fname, buf, bufsize)) < 0) {
-                       /* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink
-                          returns -1 with errno == ERANGE if the buffer is
-                          too small.  */
-                       if (errno != ERANGE) {
-                               free(buf);
-                               return NULL;
-                       }
-               }
-               /* N.B. This test is safe because bufsize must be >= 2 */
-               else if ((size_t)*linksize <= bufsize-2) {
-                       buf[*linksize] = '\0';
-                       return buf;
-               }
-               free(buf);
-               if (bufsize <= MAXSIZE/2)
-                       bufsize *= 2;
-               else if (bufsize < MAXSIZE)
-                       bufsize = MAXSIZE;
-               else
-                       return NULL;
-       }
-       return NULL;
-}
-
-/* array_set --- set an array element */
-
-static void
-array_set(awk_array_t array, const char *sub, awk_value_t *value)
-{
-       awk_element_t element;
-
-       memset(& element, 0, sizeof(element));
-
-       element.index = dup_string(sub, strlen(sub))->str_value;
-       element.value = *value;
-
-       set_array_element(array, & element);
-}
-
-/* do_stat --- provide a stat() function for gawk */
-
-static int
-do_stat(int nargs)
-{
-       awk_value_t *file_param, *array_param;
-       char *name;
-       awk_array_t array;
-       struct stat sbuf;
-       int ret;
-       char *pmode;    /* printable mode */
-       char *type = "unknown";
-
-       if (do_lint && nargs != 2) {
-               lintwarn(ext_id, "stat: called with wrong number of arguments");
-               ret = 0;
-               goto out;
-       }
-
-       /* file is first arg, array to hold results is second */
-       file_param = get_curfunc_param(0, AWK_PARAM_STRING);
-       array_param = get_curfunc_param(0, AWK_PARAM_ARRAY);
-
-       if (file_param == NULL || array_param == NULL) {
-               warning(ext_id, "stat: bad paramaters");
-               ret = 0;
-               goto out;
-       }
-
-       name = file_param->str_value.str;
-       array = array_param->array_cookie;
-
-       /* empty out the array */
-       clear_array(array);
-
-       /* lstat the file, if error, set ERRNO and return */
-       ret = lstat(name, & sbuf);
-       if (ret < 0) {
-               update_ERRNO_int(errno);
-               ret = 0;
-               goto out;
-       }
-
-       /* fill in the array */
-       array_set(array, "name", make_string(name, file_param->str_value.len));
-       array_set(array, "dev", make_number((double) sbuf.st_dev));
-       array_set(array, "ino", make_number((double) sbuf.st_ino));
-       array_set(array, "mode", make_number((double) sbuf.st_mode));
-       array_set(array, "nlink", make_number((double) sbuf.st_nlink));
-       array_set(array, "uid", make_number((double) sbuf.st_uid));
-       array_set(array, "gid", make_number((double) sbuf.st_gid));
-       array_set(array, "size", make_number((double) sbuf.st_size));
-       array_set(array, "blocks", make_number((double) sbuf.st_blocks));
-       array_set(array, "atime", make_number((double) sbuf.st_atime));
-       array_set(array, "mtime", make_number((double) sbuf.st_mtime));
-       array_set(array, "ctime", make_number((double) sbuf.st_ctime));
-
-       /* for block and character devices, add rdev, major and minor numbers */
-       if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) {
-               array_set(array, "rdev", make_number((double) sbuf.st_rdev));
-               array_set(array, "major", make_number((double) 
major(sbuf.st_rdev)));
-               array_set(array, "minor", make_number((double) 
minor(sbuf.st_rdev)));
-       }
-
-#ifdef HAVE_ST_BLKSIZE
-       array_set(array, "blksize", make_number((double) sbuf.st_blksize));
-#endif /* HAVE_ST_BLKSIZE */
-
-       pmode = format_mode(sbuf.st_mode);
-       array_set(array, "pmode", make_string(pmode, strlen(pmode)));
-
-       /* for symbolic links, add a linkval field */
-       if (S_ISLNK(sbuf.st_mode)) {
-               char *buf;
-               ssize_t linksize;
-
-               if ((buf = read_symlink(name, sbuf.st_size,
-                                       &linksize)) != NULL)
-                       array_set(array, "linkval", make_string(buf, linksize));
-               else
-                       warning(ext_id, "unable to read symbolic link `%s'", 
name);
-       }
-
-       /* add a type field */
-       switch (sbuf.st_mode & S_IFMT) {
-#ifdef S_IFSOCK
-       case S_IFSOCK:
-               type = "socket";
-               break;
-#endif
-#ifdef S_IFLNK
-       case S_IFLNK:
-               type = "symlink";
-               break;
-#endif
-       case S_IFREG:
-               type = "file";
-               break;
-       case S_IFBLK:
-               type = "blockdev";
-               break;
-       case S_IFDIR:
-               type = "directory";
-               break;
-#ifdef S_IFDOOR
-       case S_IFDOOR:
-               type = "door";
-               break;
-#endif
-       case S_IFCHR:
-               type = "chardev";
-               break;
-#ifdef S_IFIFO
-       case S_IFIFO:
-               type = "fifo";
-               break;
-#endif
-       }
-
-       array_set(array, "type", make_string(type, strlen(type)));
-
-       ret = 1;        /* success */
-
-out:
-       set_return_value(make_number((double) ret));
-}
-
-static awk_ext_func_t func_table[] = {
-       { "chdir", do_chdir, 1 },
-       { "stat", do_stat, 2 },
-};
-
-
-/* define the dl_load function using the boilerplate macro */
-
-dl_load_func(api, ext_id, func_table, filefuncs, "")
diff --git a/extension/fork.c b/extension/fork.c
index 3c288c0..a7f9601 100644
--- a/extension/fork.c
+++ b/extension/fork.c
@@ -25,102 +25,122 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
  */
 
-#include "awk.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "gawkapi.h"
+
+static const gawk_api_t *api;  /* for convenience macros to work */
+static awk_ext_id_t *ext_id;
 
 int plugin_is_GPL_compatible;
 
+
+/* array_set --- set an array element */
+
+static void
+array_set_numeric(awk_array_t array, const char *sub, double num)
+{
+       awk_element_t element;
+       awk_value_t tmp;
+
+       memset(& element, 0, sizeof(element));
+
+       element.index = dup_string(sub, strlen(sub), & tmp)->str_value;
+       make_number(num, &element.value);
+
+       set_array_element(array, & element);
+}
+
 /*  do_fork --- provide dynamically loaded fork() builtin for gawk */
 
-static NODE *
-do_fork(int nargs)
+static awk_value_t *
+do_fork(int nargs, awk_value_t *result)
 {
        int ret = -1;
-       NODE **aptr;
-       NODE *tmp;
 
        if  (do_lint && nargs > 0)
-               lintwarn("fork: called with too many arguments");
+               lintwarn(ext_id, "fork: called with too many arguments");
 
        ret = fork();
 
        if (ret < 0)
                update_ERRNO_int(errno);
-       else if (ret == 0 && PROCINFO_node != NULL) {
-               /* update PROCINFO in the child */
-
-               aptr = assoc_lookup(PROCINFO_node, tmp = make_string("pid", 3));
-               unref(*aptr);
-               *aptr = make_number((AWKNUM) getpid());
-               unref(tmp);
-
-               aptr = assoc_lookup(PROCINFO_node, tmp = make_string("ppid", 
4));
-               unref(*aptr);
-               *aptr = make_number((AWKNUM) getppid());
-               unref(tmp);
+       else if (ret == 0) {
+               /* update PROCINFO in the child, if the array exists */
+               awk_value_t procinfo;
+               if (sym_lookup("PROCINFO", &procinfo) != NULL) {
+                       if (procinfo.val_type != AWK_ARRAY) {
+                               if (do_lint)
+                                       lintwarn(ext_id, "fork: PROCINFO is not 
an array!");
+                       } else {
+                               array_set_numeric(procinfo.array_cookie, "pid", 
getpid());
+                               array_set_numeric(procinfo.array_cookie, 
"ppid", getppid());
+                       }
+               }
        }
 
        /* Set the return value */
-       return make_number((AWKNUM) ret);
+       return make_number(ret, result);
 }
 
 
 /*  do_waitpid --- provide dynamically loaded waitpid() builtin for gawk */
 
-static NODE *
-do_waitpid(int nargs)
+static awk_value_t *
+do_waitpid(int nargs, awk_value_t *result)
 {
-       NODE *pidnode;
+       awk_value_t pid;
        int ret = -1;
-       double pidval;
-       pid_t pid;
        int options = 0;
 
        if  (do_lint && nargs > 1)
-               lintwarn("waitpid: called with too many arguments");
+               lintwarn(ext_id, "waitpid: called with too many arguments");
 
-       pidnode = get_scalar_argument(0, false);
-       if (pidnode != NULL) {
-               pidval = get_number_d(pidnode);
-               pid = (int) pidval;
+       if (get_curfunc_param(0, AWK_NUMBER, &pid) != NULL) {
                options = WNOHANG|WUNTRACED;
-               ret = waitpid(pid, NULL, options);
+               ret = waitpid(pid.num_value, NULL, options);
                if (ret < 0)
                        update_ERRNO_int(errno);
        } else if (do_lint)
-               lintwarn("wait: called with no arguments");
+               lintwarn(ext_id, "wait: called with no arguments");
 
        /* Set the return value */
-       return make_number((AWKNUM) ret);
+       return make_number(ret, result);
 }
 
 
 /*  do_wait --- provide dynamically loaded wait() builtin for gawk */
 
-static NODE *
-do_wait(int nargs)
+static awk_value_t *
+do_wait(int nargs, awk_value_t *result)
 {
        int ret;
 
        if  (do_lint && nargs > 0)
-               lintwarn("wait: called with too many arguments");
+               lintwarn(ext_id, "wait: called with too many arguments");
 
        ret = wait(NULL);
        if (ret < 0)
                update_ERRNO_int(errno);
 
        /* Set the return value */
-       return make_number((AWKNUM) ret);
+       return make_number(ret, result);
 }
 
-/* dlload --- load new builtins in this library */
+static awk_ext_func_t func_table[] = {
+       { "fork", do_fork, 0 },
+       { "waitpid", do_waitpid, 1 },
+       { "wait", do_wait, 0 },
+};
 
-NODE *
-dlload(tree, dl)
-NODE *tree;
-void *dl;
-{
-       make_builtin("fork", do_fork, 0);
-       make_builtin("waitpid", do_waitpid, 1);
-       make_builtin("wait", do_wait, 0);
-       return make_number((AWKNUM) 0);
-}
+/* define the dl_load function using the boilerplate macro */
+
+dl_load_func(func_table, fork, "")
diff --git a/extension/ordchr.c b/extension/ordchr.c
index 6abda18..9540165 100644
--- a/extension/ordchr.c
+++ b/extension/ordchr.c
@@ -28,71 +28,75 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
  */
 
-#include "awk.h"
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "gawkapi.h"
+
+static const gawk_api_t *api;  /* for convenience macros to work */
+static awk_ext_id_t *ext_id;
 
 int plugin_is_GPL_compatible;
 
 /*  do_ord --- return numeric value of first char of string */
 
-static NODE *
-do_ord(int nargs)
+static awk_value_t *
+do_ord(int nargs, awk_value_t *result)
 {
-       NODE *str;
-       int ret = -1;
+       awk_value_t str;
+       double ret = -1;
 
        if  (do_lint && nargs > 1)
-               lintwarn("ord: called with too many arguments");
+               lintwarn(ext_id, "ord: called with too many arguments");
 
-       str = get_scalar_argument(0, false);
-       if (str != NULL) {
-               (void) force_string(str);
-               ret = str->stptr[0];
+       if (get_curfunc_param(0, AWK_STRING, &str) != NULL) {
+               ret = str.str_value.str[0];
        } else if (do_lint)
-               lintwarn("ord: called with no arguments");
-
+               lintwarn(ext_id, "ord: called with no arguments");
 
        /* Set the return value */
-       return make_number((AWKNUM) ret);
+       return make_number(ret, result);
 }
 
 /*  do_chr --- turn numeric value into a string */
 
-static NODE *
-do_chr(int nargs)
+static awk_value_t *
+do_chr(int nargs, awk_value_t *result)
 {
-       NODE *num;
+       awk_value_t num;
        unsigned int ret = 0;
-       AWKNUM val = 0.0;
+       double val = 0.0;
        char str[2];
 
        str[0] = str[1] = '\0';
 
        if  (do_lint && nargs > 1)
-               lintwarn("chr: called with too many arguments");
+               lintwarn(ext_id, "chr: called with too many arguments");
 
-       num = get_scalar_argument(0, false);
-       if (num != NULL) {
-               val = get_number_d(num);
+       if (get_curfunc_param(0, AWK_NUMBER, &num) != NULL) {
+               val = num.num_value;
                ret = val;      /* convert to int */
                ret &= 0xff;
                str[0] = ret;
                str[1] = '\0';
        } else if (do_lint)
-               lintwarn("chr: called with no arguments");
+               lintwarn(ext_id, "chr: called with no arguments");
 
        /* Set the return value */
-       return make_string(str, 1);
+       return dup_string(str, 1, result);
 }
 
-/* dlload --- load new builtins in this library */
+static awk_ext_func_t func_table[] = {
+       { "ord", do_ord, 1 },
+       { "chr", do_chr, 1 },
+};
 
-NODE *
-dlload(tree, dl)
-NODE *tree;
-void *dl;
-{
-       make_builtin("ord", do_ord, 1);
-       make_builtin("chr", do_chr, 1);
+/* define the dl_load function using the boilerplate macro */
 
-       return make_number((AWKNUM) 0);
-}
+dl_load_func(func_table, ord_chr, "")
diff --git a/extension/ordchr2.c b/extension/ordchr2.c
deleted file mode 100644
index 1f4a1fc..0000000
--- a/extension/ordchr2.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * ordchr.c - Builtin functions that provide ord() and chr() functions.
- *
- * Arnold Robbins
- * address@hidden
- * 8/2001
- * Revised 6/2004
- */
-
-/*
- * Copyright (C) 2001, 2004, 2011 the Free Software Foundation, Inc.
- * 
- * This file is part of GAWK, the GNU implementation of the
- * AWK Programming Language.
- * 
- * GAWK is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- * 
- * GAWK is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "gawkapi.h"
-
-static const gawk_api_t *api;  /* for convenience macros to work */
-static awk_ext_id_t *ext_id;
-
-int plugin_is_GPL_compatible;
-
-/*  do_ord --- return numeric value of first char of string */
-
-static int
-do_ord(int nargs)
-{
-       const awk_value_t *str;
-       awk_value_t result;
-       double ret = -1;
-
-       if  (do_lint && nargs > 1)
-               lintwarn(ext_id, "ord: called with too many arguments");
-
-       str = get_curfunc_param(0, AWK_PARAM_STRING);
-       if (str != NULL) {
-               ret = str->str_value.str[0];
-       } else if (do_lint)
-               lintwarn(ext_id, "ord: called with no arguments");
-
-       /* Set the return value */
-       set_return_value(make_number(ret));
-       return 1;
-}
-
-/*  do_chr --- turn numeric value into a string */
-
-static int
-do_chr(int nargs)
-{
-       const awk_value_t *num;
-       awk_value_t result;
-       unsigned int ret = 0;
-       double val = 0.0;
-       char str[2];
-
-       str[0] = str[1] = '\0';
-
-       if  (do_lint && nargs > 1)
-               lintwarn(ext_id, "chr: called with too many arguments");
-
-       num = get_curfunc_param(0, AWK_PARAM_NUMBER);
-       if (num != NULL) {
-               val = num->num_value;
-               ret = val;      /* convert to int */
-               ret &= 0xff;
-               str[0] = ret;
-               str[1] = '\0';
-       } else if (do_lint)
-               lintwarn(ext_id, "chr: called with no arguments");
-
-       /* Set the return value */
-       set_return_value(dup_string(str, 1));
-       return 1;
-}
-
-static awk_ext_func_t func_table[] = {
-       { "ord", do_ord, 1 },
-       { "chr", do_chr, 1 },
-};
-
-/* define the dl_load function using the boilerplate macro */
-
-dl_load_func(api, ext_id, func_table, ord_chr, "")
diff --git a/extension/readfile.c b/extension/readfile.c
index 17e70a6..639c897 100644
--- a/extension/readfile.c
+++ b/extension/readfile.c
@@ -30,34 +30,43 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
  */
 
-#include "awk.h"
+#include <stdio.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "gawkapi.h"
 
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
 
+static const gawk_api_t *api;  /* for convenience macros to work */
+static awk_ext_id_t *ext_id;
+
 int plugin_is_GPL_compatible;
 
 /* do_readfile --- read a file into memory */
 
-static NODE *
-do_readfile(int nargs)
+static awk_value_t *
+do_readfile(int nargs, awk_value_t *result)
 {
-       NODE *filename;
-       int ret = -1;
+       awk_value_t filename;
+       double ret = -1;
        struct stat sbuf;
        char *text;
        int fd;
 
        if  (do_lint && nargs > 1)
-               lintwarn("readfile: called with too many arguments");
-
-       filename = get_scalar_argument(0, false);
-       if (filename != NULL) {
-               (void) force_string(filename);
+               lintwarn(ext_id, "readfile: called with too many arguments");
 
-               ret = stat(filename->stptr, & sbuf);
+       if (get_curfunc_param(0, AWK_STRING, &filename) != NULL) {
+               ret = stat(filename.str_value.str, & sbuf);
                if (ret < 0) {
                        update_ERRNO_int(errno);
                        goto done;
@@ -68,7 +77,7 @@ do_readfile(int nargs)
                        goto done;
                }
 
-               if ((fd = open(filename->stptr, O_RDONLY|O_BINARY)) < 0) {
+               if ((fd = open(filename.str_value.str, O_RDONLY|O_BINARY)) < 0) 
{
                        ret = -1;
                        update_ERRNO_int(errno);
                        goto done;
@@ -85,25 +94,20 @@ do_readfile(int nargs)
                }
 
                close(fd);
-               return make_string(text, sbuf.st_size);
+               return make_string(text, sbuf.st_size, result);
        } else if (do_lint)
-               lintwarn("filename: called with no arguments");
+               lintwarn(ext_id, "readfile: called with no arguments");
 
 
 done:
        /* Set the return value */
-       return make_number((AWKNUM) ret);
+       return make_number(ret, result);
 }
 
+static awk_ext_func_t func_table[] = {
+       { "readfile", do_readfile, 1 },
+};
 
-/* dlload --- load new builtins in this library */
+/* define the dl_load function using the boilerplate macro */
 
-NODE *
-dlload(tree, dl)
-NODE *tree;
-void *dl;
-{
-       make_builtin("readfile", do_readfile, 1);
-
-       return make_number((AWKNUM) 0);
-}
+dl_load_func(func_table, readfile, "")
diff --git a/extension/readfile2.c b/extension/readfile2.c
deleted file mode 100644
index 4d8cd24..0000000
--- a/extension/readfile2.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * readfile.c - Read an entire file into a string.
- *
- * Arnold Robbins
- * Tue Apr 23 17:43:30 IDT 2002
- * Revised per Peter Tillier
- * Mon Jun  9 17:05:11 IDT 2003
- * Revised for new dynamic function facilities
- * Mon Jun 14 14:53:07 IDT 2004
- */
-
-/*
- * Copyright (C) 2002, 2003, 2004, 2011 the Free Software Foundation, Inc.
- * 
- * This file is part of GAWK, the GNU implementation of the
- * AWK Programming Language.
- * 
- * GAWK is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- * 
- * GAWK is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "gawkapi.h"
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-static const gawk_api_t *api;  /* for convenience macros to work */
-static awk_ext_id_t *ext_id;
-
-int plugin_is_GPL_compatible;
-
-/* do_readfile --- read a file into memory */
-
-static int
-do_readfile(int nargs)
-{
-       const awk_value_t *filename;
-       awk_value_t result;
-       double ret = -1;
-       struct stat sbuf;
-       char *text;
-       int fd;
-
-       if  (do_lint && nargs > 1)
-               lintwarn(ext_id, "readfile: called with too many arguments");
-
-       filename = get_curfunc_param(0, AWK_PARAM_STRING);
-       if (filename != NULL) {
-               ret = stat(filename->str_value.str, & sbuf);
-               if (ret < 0) {
-                       update_ERRNO_int(errno);
-                       goto done;
-               } else if ((sbuf.st_mode & S_IFMT) != S_IFREG) {
-                       errno = EINVAL;
-                       ret = -1;
-                       update_ERRNO_int(errno);
-                       goto done;
-               }
-
-               if ((fd = open(filename->str_value.str, O_RDONLY|O_BINARY)) < 
0) {
-                       ret = -1;
-                       update_ERRNO_int(errno);
-                       goto done;
-               }
-
-               emalloc(text, char *, sbuf.st_size + 2, "do_readfile");
-               memset(text, '\0', sbuf.st_size + 2);
-
-               if ((ret = read(fd, text, sbuf.st_size)) != sbuf.st_size) {
-                       (void) close(fd);
-                       ret = -1;
-                       update_ERRNO_int(errno);
-                       goto done;
-               }
-
-               close(fd);
-               set_return_value(make_string(text, sbuf.st_size));
-               return 1;
-       } else if (do_lint)
-               lintwarn(ext_id, "readfile: called with no arguments");
-
-
-done:
-       /* Set the return value */
-       set_return_value(make_number(ret));
-       return 0;
-}
-
-static awk_ext_func_t func_table[] = {
-       { "readfile", do_readfile, 1 },
-};
-
-/* define the dl_load function using the boilerplate macro */
-
-dl_load_func(api, ext_id, func_table, readfile, "")
diff --git a/gawkapi.c b/gawkapi.c
index e1d2a51..dbaa730 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -25,18 +25,7 @@
 
 #include "awk.h"
 
-static const awk_value_t *const node_to_awk_value(NODE *node);
-
-/*
- * This value is passed back to gawk when an extension function returns.
- * Having it static is not wonderful, but on the other hand gawk is not
- * multithreaded and calls to extension functions are not multithreaded.
- *
- * Hmm. They should not be recursive either, but since C code cannot call
- * back into awk code, there should not be a problem. But we should
- * document how this works.
- */
-static NODE *ext_ret_val;
+static awk_value_t *node_to_awk_value(NODE *node, awk_value_t *result);
 
 /*
  * Get the count'th paramater, zero-based.
@@ -45,31 +34,33 @@ static NODE *ext_ret_val;
  */
 static awk_value_t *
 api_get_curfunc_param(awk_ext_id_t id, size_t count,
-                       awk_param_type_t wanted)
+                       awk_valtype_t wanted, awk_value_t *result)
 {
        NODE *arg;
 
-       arg = (wanted == AWK_PARAM_ARRAY
+       arg = (wanted == AWK_ARRAY
                        ? get_array_argument(count, false)
                        : get_scalar_argument(count, false) );
        if (arg == NULL)
                return NULL;
 
        if (arg->type != Node_var_array) {
-               if (wanted == AWK_PARAM_NUMBER) {
+               if (wanted == AWK_NUMBER) {
                        (void) force_number(arg);
                } else {
                        (void) force_string(arg);
                }
        }
 
-       return (awk_value_t *) node_to_awk_value(arg);
+       return node_to_awk_value(arg, result);
 }
 
 /* Set the return value. Gawk takes ownership of string memory */
-static void
-api_set_return_value(awk_ext_id_t id, const awk_value_t *retval)
+NODE *
+awk_value_to_node(const awk_value_t *retval)
 {
+       NODE *ext_ret_val;
+
        if (retval == NULL)
                fatal(_("api_set_return_value: received null retval"));
 
@@ -79,19 +70,13 @@ api_set_return_value(awk_ext_id_t id, const awk_value_t 
*retval)
                *ext_ret_val = *((NODE *) retval->array_cookie);
        } else if (retval->val_type == AWK_UNDEFINED) {
                /* free node */
-               ext_ret_val = Nnull_string;
+               ext_ret_val = dupnode(Nnull_string);
        } else if (retval->val_type == AWK_NUMBER) {
-               ext_ret_val->type = Node_val;
-               ext_ret_val->flags |= NUMBER|NUMCUR;
-               /* FIXME: How to do this?
-               ext_ret_val->numbr = retval->num_value;
-                */
+               ext_ret_val = make_number(retval->num_value);
        } else {
-               ext_ret_val->type = Node_val;
-               ext_ret_val->flags |= STRING|STRCUR;
-               ext_ret_val->stptr = retval->str_value.str;
-               ext_ret_val->stlen = retval->str_value.len;
+               ext_ret_val = make_string(retval->str_value.str, 
retval->str_value.len);
        }
+       return ext_ret_val;
 }
 
 /* Functions to print messages */
@@ -171,7 +156,7 @@ api_add_ext_func(awk_ext_id_t id,
                const awk_ext_func_t *func,
                const char *namespace)
 {
-       return true;    /* for now */
+       return make_builtin(func);
 }
 
 /* Stuff for exit handler - do it as linked list */
@@ -226,50 +211,60 @@ api_awk_atexit(awk_ext_id_t id,
  *     - Use sym_update() to change a value, including from UNDEFINED
  *       to scalar or array. 
  */
-static const awk_value_t *const
-node_to_awk_value(NODE *node)
+static awk_value_t *
+node_to_awk_value(NODE *node, awk_value_t *val)
 {
-       static awk_value_t val;
-
-       memset(& val, 0, sizeof(val));
+       memset(val, 0, sizeof(*val));
        switch (node->type) {
+       case Node_val:
+               if (node->flags & NUMBER) {
+                       val->val_type = AWK_NUMBER;
+                       val->num_value = get_number_d(node);
+               } else if (node->flags & STRING) {
+                       val->val_type = AWK_STRING;
+                       val->str_value.str = node->stptr;
+                       val->str_value.len = node->stlen;
+               } else {
+                       return NULL;
+               }
+
        case Node_var_new:
-               val.val_type = AWK_UNDEFINED;
+               val->val_type = AWK_UNDEFINED;
                break;
        case Node_var:
                if ((node->var_value->flags & NUMBER) != 0) {
-                       val.val_type = AWK_NUMBER;
-                       val.num_value = get_number_d(node->var_value);
+                       val->val_type = AWK_NUMBER;
+                       val->num_value = get_number_d(node->var_value);
                } else {
-                       val.val_type = AWK_STRING;
-                       val.str_value.str = node->var_value->stptr;
-                       val.str_value.len = node->var_value->stlen;
+                       val->val_type = AWK_STRING;
+                       val->str_value.str = node->var_value->stptr;
+                       val->str_value.len = node->var_value->stlen;
                }
                break;
        case Node_var_array:
-               val.val_type = AWK_ARRAY;
-               val.array_cookie = node;
+               val->val_type = AWK_ARRAY;
+               val->array_cookie = node;
                break;
        default:
                return NULL;
        }
 
-       return & val;
+       return val;
 }
 
 /*
  * Lookup a variable, return its value. No messing with the value
  * returned. Return value is NULL if the variable doesn't exist.
  */
-static const awk_value_t *const
-api_sym_lookup(awk_ext_id_t id, const char *name)
+static awk_value_t *
+api_sym_lookup(awk_ext_id_t id, const char *name, awk_value_t *result)
 {
        NODE *node;
 
        if (name == NULL || (node = lookup(name)) == NULL)
                return NULL;
 
-       return node_to_awk_value(node);
+       return node_to_awk_value(node, result);
 }
 
 /*
@@ -287,9 +282,10 @@ api_sym_update(awk_ext_id_t id, const char *name, 
awk_value_t *value)
  * Return the value of an element - read only!
  * Use set_array_element to change it.
  */
-static const awk_value_t *const
+static awk_value_t *
 api_get_array_element(awk_ext_id_t id,
-               awk_array_t a_cookie, const awk_value_t *const index)
+               awk_array_t a_cookie, const awk_value_t *const index,
+               awk_value_t *result)
 {
        return NULL;    /* for now */
 }
@@ -302,7 +298,16 @@ static awk_bool_t
 api_set_array_element(awk_ext_id_t id, awk_array_t a_cookie,
                                awk_element_t *element)
 {
-       return true;    /* for now */
+       NODE *array = (NODE *)a_cookie;
+       NODE *tmp;
+       NODE **aptr;
+
+       tmp = make_string(element->index.str, element->index.len);
+       aptr = assoc_lookup(array, tmp);
+       unref(tmp);
+       unref(*aptr);
+       *aptr = awk_value_to_node(& element->value);
+       return true;
 }
 
 /*
@@ -376,51 +381,12 @@ api_release_flattened_array(awk_ext_id_t id,
        return true;    /* for now */
 }
 
-/* Constructor functions */
-static awk_value_t *
-api_make_string(awk_ext_id_t id,
-               const char *string,
-               size_t length,
-               awk_bool_t duplicate)
-{
-       static awk_value_t result;
-       char *cp = NULL;
-
-       result.val_type = AWK_STRING;
-       result.str_value.len = length;
-
-       if (duplicate) {
-               emalloc(cp, char *, length + 1, "api_make_string");
-               memcpy(cp, string, length);
-               cp[length] = '\0';
-
-               result.str_value.str = cp;
-       } else {
-               result.str_value.str = (char *) string;
-       }
-
-
-       return & result;
-}
-
-static awk_value_t *
-api_make_number(awk_ext_id_t id, double num)
-{
-       static awk_value_t result;
-
-       result.val_type = AWK_NUMBER;
-       result.num_value = num;
-
-       return & result;
-}
-
-static gawk_api_t api_impl = {
+gawk_api_t api_impl = {
        GAWK_API_MAJOR_VERSION, /* major and minor versions */
        GAWK_API_MINOR_VERSION,
        { 0 },                  /* do_flags */
 
        api_get_curfunc_param,
-       api_set_return_value,
 
        api_fatal,
        api_warning,
@@ -447,10 +413,6 @@ static gawk_api_t api_impl = {
        api_clear_array,
        api_flatten_array,
        api_release_flattened_array,
-
-       /* Constructor functions */
-       api_make_string,
-       api_make_number,
 };
 
 /* init_ext_api --- init the extension API */
diff --git a/gawkapi.h b/gawkapi.h
index 76c1026..3b52bff 100644
--- a/gawkapi.h
+++ b/gawkapi.h
@@ -126,13 +126,6 @@ typedef struct {
 #define array_cookie   u.a
 } awk_value_t;
 
-/* possible kinds of function parameters */
-typedef enum {
-       AWK_PARAM_STRING,       /* expecting a scalar string */
-       AWK_PARAM_NUMBER,       /* expecting a scalar number */
-       AWK_PARAM_ARRAY,        /* expecting an array */
-} awk_param_type_t;
-
 /*
  * A "flattened" array element. Gawk produces an array of these.
  * ALL memory pointed to belongs to gawk. Individual elements may
@@ -159,7 +152,7 @@ typedef struct awk_element {
  */
 typedef struct {
        const char *name;
-       int (*function)(int num_args_actual);
+       awk_value_t *(*function)(int num_args_actual, awk_value_t *result);
        size_t num_args_expected;
 } awk_ext_func_t;
 
@@ -190,10 +183,8 @@ typedef struct gawk_api {
         * does not match what is specified in wanted.
         */
        awk_value_t *(*get_curfunc_param)(awk_ext_id_t id, size_t count,
-                                       awk_param_type_t wanted);
-
-       /* Set the return value. Gawk takes ownership of string memory */
-       void (*set_return_value)(awk_ext_id_t id, const awk_value_t *retval);
+                                         awk_valtype_t wanted,
+                                         awk_value_t *result);
 
        /* Functions to print messages */
        void (*api_fatal)(awk_ext_id_t id, const char *format, ...);
@@ -231,14 +222,14 @@ typedef struct gawk_api {
         *
         * Returns a pointer to a static variable. Correct usage is thus:
         *
-        *      awk_value_t val, *vp;
-        *      vp = api->sym_lookup(id, name);
-        *      if (vp == NULL)
+        *      awk_value_t val;
+        *      if (api->sym_lookup(id, name, &val) == NULL)
         *              error_code();
-        *      val = *vp;
-        *      // use val from here on
+        *      else {
+        *              // safe to use val
+        *      }
         */
-       const awk_value_t *const (*sym_lookup)(awk_ext_id_t id, const char 
*name);
+       awk_value_t *(*sym_lookup)(awk_ext_id_t id, const char *name, 
awk_value_t *result);
 
        /*
         * Update a value. Adds it to the symbol table if not there.
@@ -250,12 +241,10 @@ typedef struct gawk_api {
        /*
         * Return the value of an element - read only!
         * Use set_array_element to change it.
-        *
-        * As for sym_lookup(), this also returns a static pointer whose
-        * value should be copied before use.
         */
-       const awk_value_t *const (*get_array_element)(awk_ext_id_t id,
-                       awk_array_t a_cookie, const awk_value_t *const index);
+       awk_value_t *(*get_array_element)(awk_ext_id_t id,
+                       awk_array_t a_cookie, const awk_value_t *const index,
+                       awk_value_t *result);
 
        /*
         * Change (or create) element in existing array with
@@ -298,12 +287,6 @@ typedef struct gawk_api {
                        awk_array_t a_cookie,
                        size_t count,
                        awk_element_t *data);
-
-       /* Constructor functions */
-       awk_value_t *(*api_make_string)(awk_ext_id_t id,
-                       const char *string, size_t length, awk_bool_t 
duplicate);
-       awk_value_t *(*api_make_number)(awk_ext_id_t id, double num);
-
 } gawk_api_t;
 
 #ifndef GAWK   /* these are not for the gawk code itself */
@@ -318,11 +301,8 @@ typedef struct gawk_api {
 #define do_debug       api->do_flags[gawk_do_debug]
 #define do_mpfr                api->do_flags[gawk_do_mpfr]
 
-#define get_curfunc_param(count, wanted) \
-       api->get_curfunc_param(ext_id, count, wanted)
-
-#define set_return_value(retval) \
-       api->set_return_value(ext_id, retval)
+#define get_curfunc_param(count, wanted, result) \
+       api->get_curfunc_param(ext_id, count, wanted, result)
 
 #define fatal          api->api_fatal
 #define warning                api->api_warning
@@ -338,12 +318,12 @@ typedef struct gawk_api {
 #define add_ext_func(func, ns) api->add_ext_func(ext_id, func, ns)
 #define awk_atexit(funcp, arg0)        api->awk_atexit(ext_id, funcp, arg0)
 
-#define sym_lookup(name)       api->sym_lookup(ext_id, name)
+#define sym_lookup(name, result)       api->sym_lookup(ext_id, name, result)
 #define sym_update(name, value) \
        api->sym_update(ext_id, name, value)
 
-#define get_array_element(array, element) \
-       api->get_array_element(ext_id, array, element)
+#define get_array_element(array, element, result) \
+       api->get_array_element(ext_id, array, element, result)
 
 #define set_array_element(array, element) \
        api->set_array_element(ext_id, array, element)
@@ -364,17 +344,47 @@ typedef struct gawk_api {
 #define release_flattened_array(array, count, data) \
        api->release_flattened_array(ext_id, array, count, data)
 
-#define make_string(str, len)  api->api_make_string(ext_id, str, len, 0)
-#define dup_string(str, len)   api->api_make_string(ext_id, str, len, 1)
-#define make_number(num)       api->api_make_number(ext_id, num)
-
 #define emalloc(pointer, type, size, message) \
        do { \
                if ((pointer = (type) malloc(size)) == 0) \
                        fatal(ext_id, "malloc of %d bytes failed\n", size); \
        } while(0)
 
-#endif /* GAWK */
+/* Constructor functions */
+static inline awk_value_t *
+r_make_string(const gawk_api_t *api,
+             awk_ext_id_t *ext_id,
+             const char *string,
+             size_t length,
+             awk_bool_t duplicate,
+             awk_value_t *result)
+{
+       char *cp = NULL;
+
+       result->val_type = AWK_STRING;
+       result->str_value.len = length;
+
+       if (duplicate) {
+               emalloc(cp, char *, length + 2, "make_string");
+               memcpy(cp, string, length);
+               cp[length] = '\0';
+               result->str_value.str = cp;
+       } else {
+               result->str_value.str = (char *) string;
+       }
+       return result;
+}
+
+#define make_string(str, len, result)  r_make_string(api, ext_id, str, len, 0, 
result)
+#define dup_string(str, len, result)   r_make_string(api, ext_id, str, len, 1, 
result)
+
+static inline awk_value_t *
+make_number(double num, awk_value_t *result)
+{
+       result->val_type = AWK_NUMBER;
+       result->num_value = num;
+       return result;
+}
 
 /*
  * Each extension must define a function with this prototype:
@@ -397,15 +407,18 @@ static awk_ext_func_t func_table[] = {
        /* ... */
 };
 
-dl_load_func(api, ext_id, func_table, some_name, "name_space_in_quotes")
+dl_load_func(func_table, some_name, "name_space_in_quotes")
 #endif
 
-#define dl_load_func(global_api_p, global_ext_id, func_table, module, 
name_space) \
+#define dl_load_func(func_table, module, name_space) \
 int dl_load(const gawk_api_t *const api_p, awk_ext_id_t id)  \
 { \
        size_t i, j; \
        int errors = 0; \
- \
+\
+       api = api_p; \
+       ext_id = id; \
+\
        if (api->major_version != GAWK_API_MAJOR_VERSION \
            || api->minor_version < GAWK_API_MINOR_VERSION) { \
                fprintf(stderr, #module ": version mismatch with gawk!\n"); \
@@ -414,9 +427,6 @@ int dl_load(const gawk_api_t *const api_p, awk_ext_id_t id) 
 \
                        api->major_version, api->minor_version); \
                exit(1); \
        } \
- \
-       global_api_p = api_p; \
-       global_ext_id = id; \
 \
        /* load functions */ \
        for (i = 0, j = sizeof(func_table) / sizeof(func_table[0]); i < j; i++) 
{ \
@@ -430,6 +440,8 @@ int dl_load(const gawk_api_t *const api_p, awk_ext_id_t id) 
 \
        return (errors == 0); \
 }
 
+#endif /* GAWK */
+
 #ifdef __cplusplus
 }
 #endif /* C++ */
diff --git a/interpret.h b/interpret.h
index 3ff5e92..abffbda 100644
--- a/interpret.h
+++ b/interpret.h
@@ -785,9 +785,10 @@ arrayfor:
                case Op_ext_builtin:
                {
                        int arg_count = pc->expr_count;
+                       awk_value_t result;
 
                        PUSH_CODE(pc);
-                       r = pc->builtin(arg_count);
+                       r = awk_value_to_node(pc->extfunc(arg_count, & result));
                        (void) POP_CODE();
                        while (arg_count-- > 0) {
                                t1 = POP();
@@ -919,7 +920,7 @@ match_re:
                                bc = f->code_ptr;
                                assert(bc->opcode == Op_symbol);
                                pc->opcode = Op_ext_builtin;    /* self 
modifying code */
-                               pc->builtin = bc->builtin;
+                               pc->extfunc = bc->extfunc;
                                pc->expr_count = arg_count;             /* 
actual argument count */
                                (pc + 1)->func_name = fname;    /* name of the 
builtin */
                                (pc + 1)->expr_count = bc->expr_count;  /* 
defined max # of arguments */
diff --git a/main.c b/main.c
index 4bdbbc5..844052f 100644
--- a/main.c
+++ b/main.c
@@ -638,10 +638,13 @@ out:
        if (os_isatty(fileno(stdout)))
                output_is_tty = true;
 
+       /* initialize API before loading extension libraries */
+       init_ext_api();
+
        /* load extension libs */
         for (s = srcfiles->next; s != srcfiles; s = s->next) {
                 if (s->stype == SRC_EXTLIB)
-                       (void) load_ext(s->fullpath, "dlload", NULL);
+                       (void) load_ext(s->fullpath, "dl_load");
                else if (s->stype != SRC_INC)
                        have_srcfile++;
         }
diff --git a/test/ChangeLog b/test/ChangeLog
index 755caeb..72c7b9e 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,8 @@
+2012-05-24         Andrew J. Schorr     <address@hidden>
+
+       * Makefile.am (fmtspcl, include2, incdupe, incdup2, incdupe3): Fix
+       paths to work properly when built in another directory.
+
 2012-05-19         Andrew J. Schorr     <address@hidden>
 
        * Makefile.am (EXTRA_DIST): Add new files hello.awk, inclib.awk,
diff --git a/test/Makefile.am b/test/Makefile.am
index e782d1c..2af0e38 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1159,7 +1159,7 @@ fmtspcl.ok: fmtspcl.tok Makefile
 fmtspcl: fmtspcl.ok
        @echo $@
        @$(AWK) -f $(srcdir)/fmtspcl.awk  --lint >_$@ 2>&1 || echo EXIT CODE: 
$$? >>_$@
-       @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/address@hidden _$@ && 
rm -f _$@ ; else \
+       @-if test -z "$$AWKFLAGS" ; then $(CMP) address@hidden _$@ && rm -f _$@ 
; else \
        $(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@ ; \
        fi
 
@@ -1559,22 +1559,22 @@ readfile::
 
 include2::
        @echo $@
-       @$(AWK) -i inclib 'BEGIN {print sandwich("a", "b", "c")}' >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @AWKPATH=$(srcdir) $(AWK) -i inclib 'BEGIN {print sandwich("a", "b", 
"c")}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 incdupe::
        @echo $@
-       @$(AWK) --lint -i inclib -i inclib.awk 'BEGIN {print sandwich("a", "b", 
"c")}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @AWKPATH=$(srcdir) $(AWK) --lint -i inclib -i inclib.awk 'BEGIN {print 
sandwich("a", "b", "c")}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 incdupe2::
        @echo $@
-       @$(AWK) --lint -f inclib -f inclib.awk >_$@ 2>&1 || echo EXIT CODE: $$? 
>>_$@
+       @AWKPATH=$(srcdir) $(AWK) --lint -f inclib -f inclib.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 incdupe3::
        @echo $@
-       @$(AWK) --lint -f hello -f hello.awk >_$@ 2>&1 || echo EXIT CODE: $$? 
>>_$@
+       @AWKPATH=$(srcdir) $(AWK) --lint -f hello -f hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 # Targets generated for other tests:
diff --git a/test/Makefile.in b/test/Makefile.in
index c0462ab..0c99091 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -1540,7 +1540,7 @@ fmtspcl.ok: fmtspcl.tok Makefile
 fmtspcl: fmtspcl.ok
        @echo $@
        @$(AWK) -f $(srcdir)/fmtspcl.awk  --lint >_$@ 2>&1 || echo EXIT CODE: 
$$? >>_$@
-       @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/address@hidden _$@ && 
rm -f _$@ ; else \
+       @-if test -z "$$AWKFLAGS" ; then $(CMP) address@hidden _$@ && rm -f _$@ 
; else \
        $(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@ ; \
        fi
 
@@ -1940,22 +1940,22 @@ readfile::
 
 include2::
        @echo $@
-       @$(AWK) -i inclib 'BEGIN {print sandwich("a", "b", "c")}' >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @AWKPATH=$(srcdir) $(AWK) -i inclib 'BEGIN {print sandwich("a", "b", 
"c")}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 incdupe::
        @echo $@
-       @$(AWK) --lint -i inclib -i inclib.awk 'BEGIN {print sandwich("a", "b", 
"c")}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @AWKPATH=$(srcdir) $(AWK) --lint -i inclib -i inclib.awk 'BEGIN {print 
sandwich("a", "b", "c")}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 incdupe2::
        @echo $@
-       @$(AWK) --lint -f inclib -f inclib.awk >_$@ 2>&1 || echo EXIT CODE: $$? 
>>_$@
+       @AWKPATH=$(srcdir) $(AWK) --lint -f inclib -f inclib.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 incdupe3::
        @echo $@
-       @$(AWK) --lint -f hello -f hello.awk >_$@ 2>&1 || echo EXIT CODE: $$? 
>>_$@
+       @AWKPATH=$(srcdir) $(AWK) --lint -f hello -f hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 Gt-dummy:
 # file Maketests, generated from Makefile.am by the Gentests program

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog              |   52 +++
 Makefile.am            |    1 +
 Makefile.in            |   10 +-
 TODO.xgawk             |    7 +-
 awk.h                  |   17 +-
 awkgram.c              |    2 +-
 awkgram.y              |    2 +-
 doc/ChangeLog          |    5 +
 doc/gawk.1             |    2 +-
 doc/gawk.info          |  815 ++++++++++++++++++++++++------------------------
 doc/gawk.texi          |   23 +-
 ext.c                  |   38 +--
 extension/ChangeLog    |   12 +
 extension/Makefile.am  |    2 +-
 extension/Makefile.in  |    9 +-
 extension/configure    |    3 +
 extension/configure.ac |    4 +
 extension/filefuncs.c  |  221 +++++++------
 extension/filefuncs2.c |  365 ----------------------
 extension/fork.c       |  114 ++++---
 extension/ordchr.c     |   70 +++--
 extension/ordchr2.c    |  107 -------
 extension/readfile.c   |   54 ++--
 extension/readfile2.c  |  116 -------
 gawkapi.c              |  148 ++++------
 gawkapi.h              |  108 ++++---
 interpret.h            |    5 +-
 main.c                 |    5 +-
 test/ChangeLog         |    5 +
 test/Makefile.am       |   10 +-
 test/Makefile.in       |   10 +-
 31 files changed, 922 insertions(+), 1420 deletions(-)
 delete mode 100644 extension/filefuncs2.c
 delete mode 100644 extension/ordchr2.c
 delete mode 100644 extension/readfile2.c


hooks/post-receive
-- 
gawk



reply via email to

[Prev in Thread] Current Thread [Next in Thread]