FLTK logo

[master] 7abc09a - Merge pull request #116 from erco77/fl_strdup

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.commit  ]
 
Previous Message ]Next Message ]

[master] 7abc09a - Merge pull request #116 from erco77/fl_strdup "erco77" Aug 01, 2020  
 
commit 7abc09ad89b4c3d0c17ee8dc9d02ccd261cd13f2
Merge: 7514a73 e968882
Author: erco77 <erco@seriss.com>
Date:   Sat Aug 1 14:35:44 2020 -0700

    Merge pull request #116 from erco77/fl_strdup
    
    fl_strdup() implemented + deployed

commit e9688822ec68f066f425953278a853e049b93dfb
Author: Greg Ercolano <erco@seriss.com>
Date:   Wed Jul 22 20:14:07 2020 -0700

    Convert example from strdup -> std::string

commit b4095880125b2f0d1d56c80a2bbf3fb0f6f98cb9
Author: Greg Ercolano <erco@seriss.com>
Date:   Tue Jul 21 23:57:45 2020 -0700

    Remove unneeded strdup from example, fold tabs

commit 2141c63628a831d3f53dad7035c94028f8d0d629
Author: Greg Ercolano <erco@seriss.com>
Date:   Tue Jul 21 20:15:41 2020 -0700

    Implement + deploy fl_strdup()

 FL/fl_string.h                                     | 47 ++++++++++++++++++
 examples/table-as-container.cxx                    |  3 +-
 examples/table-sort.cxx                            | 55 ++++++++++++----------
 fluid/ExternalCodeEditor_UNIX.cxx                  |  3 +-
 fluid/ExternalCodeEditor_WIN32.cxx                 |  3 +-
 fluid/Fl_Function_Type.cxx                         | 15 +++---
 fluid/Fluid_Image.cxx                              |  3 +-
 fluid/code.cxx                                     |  5 +-
 fluid/file.cxx                                     | 13 ++---
 fluid/fluid.cxx                                    |  3 +-
 fluid/print_panel.cxx                              |  3 +-
 fluid/print_panel.fl                               |  5 +-
 fluid/template_panel.cxx                           |  3 +-
 fluid/template_panel.fl                            |  5 +-
 src/CMakeLists.txt                                 |  1 +
 src/Fl_Check_Browser.cxx                           |  3 +-
 src/Fl_File_Browser.cxx                            |  3 +-
 src/Fl_File_Chooser2.cxx                           |  3 +-
 src/Fl_Help_View.cxx                               |  5 +-
 src/Fl_Image_Reader.cxx                            |  5 +-
 src/Fl_MacOS_Sys_Menu_Bar.mm                       |  3 +-
 src/Fl_Menu_add.cxx                                |  5 +-
 src/Fl_Native_File_Chooser_GTK.cxx                 |  7 +--
 src/Fl_Native_File_Chooser_MAC.mm                  |  7 +--
 src/Fl_Preferences.cxx                             | 29 ++++++------
 src/Fl_SVG_Image.cxx                               |  3 +-
 src/Fl_System_Driver.H                             |  3 ++
 src/Fl_Text_Buffer.cxx                             |  3 +-
 src/Fl_Text_Display.cxx                            |  7 +--
 src/Fl_Tooltip.cxx                                 |  4 +-
 src/Fl_Tree.cxx                                    |  3 +-
 src/Fl_Tree_Item.cxx                               |  6 ++-
 src/Fl_Widget.cxx                                  |  3 +-
 src/Fl_Window.cxx                                  |  5 +-
 src/Fl_cocoa.mm                                    |  5 +-
 src/Fl_get_system_colors.cxx                       |  7 +--
 src/Fl_win32.cxx                                   |  3 +-
 src/Makefile                                       |  3 +-
 src/drivers/Android/Fl_Android_Application.cxx     |  3 +-
 src/drivers/Android/Fl_Android_System_Driver.H     |  3 +-
 src/drivers/Android/Fl_Android_System_Driver.cxx   |  3 +-
 src/drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm       |  3 +-
 src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx    |  9 ++--
 src/drivers/Posix/Fl_Posix_System_Driver.H         |  2 +
 src/drivers/Posix/Fl_Posix_System_Driver.cxx       |  3 +-
 src/drivers/PostScript/Fl_PostScript.cxx           |  3 +-
 .../Quartz/Fl_Quartz_Graphics_Driver_font.cxx      |  5 +-
 src/drivers/SVG/Fl_SVG_File_Surface.cxx            | 12 +++--
 src/drivers/WinAPI/Fl_WinAPI_System_Driver.H       |  3 ++
 src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx     |  3 +-
 src/drivers/X11/Fl_X11_System_Driver.cxx           |  3 +-
 .../Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx        |  5 +-
 .../Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx      | 11 +++--
 src/filename_absolute.cxx                          |  3 +-
 src/fl_ask.cxx                                     |  3 +-
 src/fl_string.cxx                                  | 34 +++++++++++++
 src/flstring.h                                     |  4 --
 src/print_panel.cxx                                |  5 +-
 src/xutf8/utf8Wrap.c                               |  3 +-
 test/menubar.cxx                                   |  3 +-
 test/unittests.cxx                                 |  3 +-
 test/utf8.cxx                                      |  5 +-
 62 files changed, 287 insertions(+), 139 deletions(-)

diff --git FL/fl_string.h FL/fl_string.h
new file mode 100644
index 0000000..adcefa4
--- /dev/null
+++ FL/fl_string.h
@@ -0,0 +1,47 @@
+/*
+ * Platform agnostic string portability functions for the Fast Light Tool Kit (FLTK).
+ *
+ * Copyright 2020 by Bill Spitzak and others.
+ *
+ * This library is free software. Distribution and use rights are outlined in
+ * the file "COPYING" which should have been included with this file.  If this
+ * file is missing or damaged, see the license at:
+ *
+ *     https://www.fltk.org/COPYING.php
+ *
+ * Please see the following page on how to report bugs and issues:
+ *
+ *     https://www.fltk.org/bugs.php
+ */
+
+/**
+  \file fl_string.h
+  \brief Public header for FLTK's own platform agnostic string handling.
+*/
+
+#ifndef _FL_fl_string_h_
+#define _FL_fl_string_h_
+
+#include "Fl_Export.H"
+#include "fl_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \addtogroup fl_string
+    @{
+*/
+
+FL_EXPORT char* fl_strdup(const char *s);
+
+/** @} */
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* _FL_fl_string_h_ */
diff --git examples/table-as-container.cxx examples/table-as-container.cxx
index 515ad88..d588743 100644
--- examples/table-as-container.cxx
+++ examples/table-as-container.cxx
@@ -75,7 +75,8 @@ public:
           } else {
             // Create the light buttons
             sprintf(s, "%d/%d ", r, c);
-            Fl_Light_Button *butt = new Fl_Light_Button(X,Y,W,H,strdup(s));
+            Fl_Light_Button *butt = new Fl_Light_Button(X,Y,W,H);
+            butt->copy_label(s);
             butt->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
             butt->callback(button_cb, (void*)0);
             butt->value( ((r+c*2) & 4 ) ? 1 : 0);
diff --git examples/table-sort.cxx examples/table-sort.cxx
index d492bf5..b508922 100644
--- examples/table-sort.cxx
+++ examples/table-sort.cxx
@@ -30,6 +30,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#include <string>
 #include <vector>
 #include <algorithm>            // STL sort
 
@@ -57,7 +58,7 @@ static const char *G_header[] = { "Perms", "#L", "Own", "Group", "Size", "Date",
 // A single row of columns
 class Row {
 public:
-    std::vector<char*> cols;
+    std::vector<std::string> cols;
 };
 
 // Sort class to handle sorting column using std::sort
@@ -69,8 +70,8 @@ public:
         _reverse = reverse;
     }
     bool operator()(const Row &a, const Row &b) {
-        const char *ap = ( _col < (int)a.cols.size() ) ? a.cols[_col] : "",
-                   *bp = ( _col < (int)b.cols.size() ) ? b.cols[_col] : "";
+        const char *ap = ( _col < (int)a.cols.size() ) ? a.cols[_col].c_str() : "",
+                   *bp = ( _col < (int)b.cols.size() ) ? b.cols[_col].c_str() : "";
         if ( isdigit(*ap) && isdigit(*bp) ) {           // cheezy detection of numeric data
             // Numeric sort
             int av=0; sscanf(ap, "%d", &av);
@@ -86,9 +87,9 @@ public:
 // Derive a custom class from Fl_Table_Row
 class MyTable : public Fl_Table_Row {
 private:
-    std::vector<Row> _rowdata;                                  // data in each row
-    int _sort_reverse;
-    int _sort_lastcol;
+    std::vector<Row> rowdata_;                                  // data in each row
+    int sort_reverse_;
+    int sort_lastcol_;
 
     static void event_callback(Fl_Widget*, void*);
     void event_callback2();                                     // callback for table events
@@ -102,8 +103,8 @@ protected:
 public:
     // Ctor
     MyTable(int x, int y, int w, int h, const char *l=0) : Fl_Table_Row(x,y,w,h,l) {
-        _sort_reverse = 0;
-        _sort_lastcol = -1;
+        sort_reverse_ = 0;
+        sort_lastcol_ = -1;
         end();
         callback(event_callback, (void*)this);
     }
@@ -115,7 +116,7 @@ public:
 
 // Sort a column up or down
 void MyTable::sort_column(int col, int reverse) {
-    std::sort(_rowdata.begin(), _rowdata.end(), SortColumn(col, reverse));
+    std::sort(rowdata_.begin(), rowdata_.end(), SortColumn(col, reverse));
     redraw();
 }
 
@@ -126,7 +127,7 @@ void MyTable::draw_sort_arrow(int X,int Y,int W,int H) {
     int xrit = X+(W-6)-0;
     int ytop = Y+(H/2)-4;
     int ybot = Y+(H/2)+4;
-    if ( _sort_reverse ) {
+    if ( sort_reverse_ ) {
         // Engraved down arrow
         fl_color(FL_WHITE);
         fl_line(xrit, ytop, xctr, ybot);
@@ -146,8 +147,8 @@ void MyTable::draw_sort_arrow(int X,int Y,int W,int H) {
 // Handle drawing all cells in table
 void MyTable::draw_cell(TableContext context, int R, int C, int X, int Y, int W, int H) {
     const char *s = "";
-    if ( R < (int)_rowdata.size() && C < (int)_rowdata[R].cols.size() )
-        s = _rowdata[R].cols[C];
+    if ( R < (int)rowdata_.size() && C < (int)rowdata_[R].cols.size() )
+        s = rowdata_[R].cols[C].c_str();
     switch ( context ) {
         case CONTEXT_COL_HEADER:
             fl_push_clip(X,Y,W,H); {
@@ -157,7 +158,7 @@ void MyTable::draw_cell(TableContext context, int R, int C, int X, int Y, int W,
                     fl_color(FL_BLACK);
                     fl_draw(G_header[C], X+2,Y,W,H, FL_ALIGN_LEFT, 0, 0);         // +2=pad left
                     // Draw sort arrow
-                    if ( C == _sort_lastcol ) {
+                    if ( C == sort_lastcol_ ) {
                         draw_sort_arrow(X,Y,W,H);
                     }
                 }
@@ -192,9 +193,9 @@ void MyTable::autowidth(int pad) {
         col_width(c, w+pad);
     }
     fl_font(ROW_FONTFACE, ROW_FONTSIZE);
-    for ( int r=0; r<(int)_rowdata.size(); r++ ) {
-        for ( int c=0; c<(int)_rowdata[r].cols.size(); c++ ) {
-            w=0; fl_measure(_rowdata[r].cols[c], w, h, 0);       // pixel width of row text
+    for ( int r=0; r<(int)rowdata_.size(); r++ ) {
+        for ( int c=0; c<(int)rowdata_[r].cols.size(); c++ ) {
+            w=0; fl_measure(rowdata_[r].cols[c].c_str(), w, h, 0);       // pixel width of row text
             if ( (w + pad) > col_width(c)) col_width(c, w + pad);
         }
     }
@@ -205,8 +206,9 @@ void MyTable::autowidth(int pad) {
 // Resize parent window to size of table
 void MyTable::resize_window() {
     // Determine exact outer width of table with all columns visible
-    int width = 4;                                          // width of table borders
+    int width = 2;                                          // width of table borders
     for ( int t=0; t<cols(); t++ ) width += col_width(t);   // total width of all columns
+    width += vscrollbar->w();                               // include width of scrollbar
     width += MARGIN*2;
     if ( width < 200 || width > Fl::w() ) return;
     window()->resize(window()->x(), window()->y(), width, window()->h());  // resize window to fit
@@ -218,14 +220,15 @@ void MyTable::load_command(const char *cmd) {
     FILE *fp = popen(cmd, "r");
     cols(0);
     for ( int r=0; fgets(s, sizeof(s)-1, fp); r++ ) {
+        if ( r==0 && strncmp(s,"total ",6)==0) { --r; continue; }
         // Add a new row
-        Row newrow; _rowdata.push_back(newrow);
-        std::vector<char*> &rc = _rowdata[r].cols;
+        Row newrow; rowdata_.push_back(newrow);
+        std::vector<std::string> &rc = rowdata_[r].cols;
         // Break line into separate word 'columns'
         char *ss;
         const char *delim = " \t\n";
         for(int t=0; (t==0)?(ss=strtok(s,delim)):(ss=strtok(NULL,delim)); t++) {
-            rc.push_back(strdup(ss));
+            rc.push_back(ss);  // char* -> std::string
         }
         // Keep track of max # columns
         if ( (int)rc.size() > cols() ) {
@@ -233,7 +236,7 @@ void MyTable::load_command(const char *cmd) {
         }
     }
     // How many rows we loaded
-    rows((int)_rowdata.size());
+    rows((int)rowdata_.size());
     // Auto-calculate widths, with 20 pixel padding
     autowidth(20);
 }
@@ -251,13 +254,13 @@ void MyTable::event_callback2() {
     switch ( context ) {
         case CONTEXT_COL_HEADER: {              // someone clicked on column header
             if ( Fl::event() == FL_RELEASE && Fl::event_button() == 1 ) {
-                if ( _sort_lastcol == COL ) {   // Click same column? Toggle sort
-                    _sort_reverse ^= 1;
+                if ( sort_lastcol_ == COL ) {   // Click same column? Toggle sort
+                    sort_reverse_ ^= 1;
                 } else {                        // Click diff column? Up sort
-                    _sort_reverse = 0;
+                    sort_reverse_ = 0;
                 }
-                sort_column(COL, _sort_reverse);
-                _sort_lastcol = COL;
+                sort_column(COL, sort_reverse_);
+                sort_lastcol_ = COL;
             }
             break;
         }
diff --git fluid/ExternalCodeEditor_UNIX.cxx fluid/ExternalCodeEditor_UNIX.cxx
index 189f297..c0f7535 100644
--- fluid/ExternalCodeEditor_UNIX.cxx
+++ fluid/ExternalCodeEditor_UNIX.cxx
@@ -16,6 +16,7 @@
 
 #include <FL/Fl.H>      /* Fl_Timeout_Handler.. */
 #include <FL/fl_ask.H>  /* fl_alert() */
+#include <FL/fl_string.h> /* fl_strdup() */
 
 #include "ExternalCodeEditor_UNIX.h"
 
@@ -61,7 +62,7 @@ ExternalCodeEditor::~ExternalCodeEditor() {
 //
 void ExternalCodeEditor::set_filename(const char *val) {
   if ( filename_ ) free((void*)filename_);
-  filename_ = val ? strdup(val) : 0;
+  filename_ = val ? fl_strdup(val) : 0;
 }
 
 // [Public] Is editor running?
diff --git fluid/ExternalCodeEditor_WIN32.cxx fluid/ExternalCodeEditor_WIN32.cxx
index 9be5a30..45ad612 100644
--- fluid/ExternalCodeEditor_WIN32.cxx
+++ fluid/ExternalCodeEditor_WIN32.cxx
@@ -8,6 +8,7 @@
 #include <FL/Fl.H>      // Fl_Timeout_Handler..
 #include <FL/fl_ask.H>  // fl_alert()
 #include <FL/fl_utf8.h> // fl_utf8fromwc()
+#include <FL/fl_string.h> // fl_strdup()
 
 #include "ExternalCodeEditor_WIN32.h"
 
@@ -83,7 +84,7 @@ ExternalCodeEditor::~ExternalCodeEditor() {
 //
 void ExternalCodeEditor::set_filename(const char *val) {
   if ( filename_ ) free((void*)filename_);
-  filename_ = val ? strdup(val) : 0;
+  filename_ = val ? fl_strdup(val) : 0;
 }
 
 // [Public] Is editor running?
diff --git fluid/Fl_Function_Type.cxx fluid/Fl_Function_Type.cxx
index f6e8f5b..54b4a73 100644
--- fluid/Fl_Function_Type.cxx
+++ fluid/Fl_Function_Type.cxx
@@ -17,6 +17,7 @@
 #include <FL/Fl_Window.H>
 #include <FL/Fl_Preferences.H>
 #include <FL/Fl_File_Chooser.H>
+#include <FL/fl_string.h>
 #include "Fl_Type.h"
 #include <FL/fl_show_input.H>
 #include <FL/Fl_File_Chooser.H>
@@ -843,7 +844,7 @@ void Fl_Data_Type::open() {
     }
     // store the variable name:
     const char*c = data_input->value();
-    char *s = strdup(c), *p = s, *q, *n;
+    char *s = fl_strdup(c), *p = s, *q, *n;
     for (;;++p) {
       if (!isspace((unsigned char)(*p))) break;
     }
@@ -890,7 +891,7 @@ void Fl_Data_Type::open() {
     else if (!filename_ && *c)
       set_modflag(1);
     if (filename_) { free((void*)filename_); filename_ = 0L; }
-    if (c && *c) filename_ = strdup(c);
+    if (c && *c) filename_ = fl_strdup(c);
     // store the comment
     c = data_comment_input->buffer()->text();
     if (c && *c) {
@@ -1016,7 +1017,7 @@ Fl_Type *Fl_DeclBlock_Type::make() {
   Fl_DeclBlock_Type *o = new Fl_DeclBlock_Type();
   o->name("#if 1");
   o->public_ = 0;
-  o->after = strdup("#endif");
+  o->after = fl_strdup("#endif");
   o->add(p);
   o->factory = this;
   return o;
@@ -1188,7 +1189,7 @@ void Fl_Comment_Type::open() {
                                        "Use forward slashes '/' to create submenus.",
                                        "My Comment");
           if (xname) {
-            char *name = strdup(xname);
+            char *name = fl_strdup(xname);
             for (char*s=name;*s;s++) if (*s==':') *s = ';';
             int n;
             Fl_Preferences db(Fl_Preferences::USER, "fltk.org", "fluid_comments");
@@ -1305,7 +1306,7 @@ void Fl_Comment_Type::write_code1() {
     return;
   }
   // copy the comment line by line, add the double slash if needed
-  char *txt = strdup(c);
+  char *txt = fl_strdup(c);
   char *b = txt, *e = txt;
   for (;;) {
     // find the end of the line and set it to NUL
@@ -1374,7 +1375,7 @@ int Fl_Class_Type::is_public() const {return public_;}
 
 void Fl_Class_Type::prefix(const char*p) {
   free((void*) class_prefix);
-  class_prefix=strdup(p ? p : "" );
+  class_prefix=fl_strdup(p ? p : "" );
 }
 
 Fl_Type *Fl_Class_Type::make() {
@@ -1440,7 +1441,7 @@ void Fl_Class_Type::open() {
       else if (!w) Fl::wait();
     }
     const char*c = c_name_input->value();
-    char *s = strdup(c);
+    char *s = fl_strdup(c);
     size_t len = strlen(s);
     if (!*s) goto OOPS;
     p = (char*) (s+len-1);
diff --git fluid/Fluid_Image.cxx fluid/Fluid_Image.cxx
index 19784e0..1f41a09 100644
--- fluid/Fluid_Image.cxx
+++ fluid/Fluid_Image.cxx
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <FL/filename.H>
+#include <FL/fl_string.h>
 
 extern void goto_source_dir(); // in fluid.cxx
 extern void leave_source_dir(); // in fluid.cxx
@@ -204,7 +205,7 @@ Fluid_Image* Fluid_Image::find(const char *iname) {
 }
 
 Fluid_Image::Fluid_Image(const char *iname) {
-  name_ = strdup(iname);
+  name_ = fl_strdup(iname);
   written = 0;
   refcount = 0;
   img = Fl_Shared_Image::get(iname);
diff --git fluid/code.cxx fluid/code.cxx
index 7b156f5..4603e95 100644
--- fluid/code.cxx
+++ fluid/code.cxx
@@ -20,6 +20,7 @@
 #include <stdarg.h>
 
 #include <FL/Fl.H>
+#include <FL/fl_string.h>
 #include "Fl_Type.h"
 #include "alignment_panel.h"
 
@@ -46,7 +47,7 @@ struct id {
   char* text;
   void* object;
   id *left, *right;
-  id (const char* t, void* o) : text(strdup(t)), object(o) {left = right = 0;}
+  id (const char* t, void* o) : text(fl_strdup(t)), object(o) {left = right = 0;}
   ~id();
 };
 
@@ -109,7 +110,7 @@ struct included {
   char *text;
   included *left, *right;
   included(const char *t) {
-    text = strdup(t);
+    text = fl_strdup(t);
     left = right = 0;
   }
   ~included();
diff --git fluid/file.cxx fluid/file.cxx
index dd2ef34..30335a2 100644
--- fluid/file.cxx
+++ fluid/file.cxx
@@ -25,6 +25,7 @@
 #include <stdarg.h>
 #include "alignment_panel.h"
 #include <FL/Fl.H>
+#include <FL/fl_string.h>
 #include "Fl_Widget_Type.h"
 
 ////////////////////////////////////////////////////////////////
@@ -405,19 +406,19 @@ static void read_children(Fl_Type *p, int paste) {
       goto CONTINUE;
     }
     if (!strcmp(c,"i18n_function")) {
-      i18n_function = strdup(read_word());
+      i18n_function = fl_strdup(read_word());
       goto CONTINUE;
     }
     if (!strcmp(c,"i18n_file")) {
-      i18n_file = strdup(read_word());
+      i18n_file = fl_strdup(read_word());
       goto CONTINUE;
     }
     if (!strcmp(c,"i18n_set")) {
-      i18n_set = strdup(read_word());
+      i18n_set = fl_strdup(read_word());
       goto CONTINUE;
     }
     if (!strcmp(c,"i18n_include")) {
-      i18n_include = strdup(read_word());
+      i18n_include = fl_strdup(read_word());
       goto CONTINUE;
     }
     if (!strcmp(c,"i18n_type"))
@@ -431,13 +432,13 @@ static void read_children(Fl_Type *p, int paste) {
       goto CONTINUE;
     }
     if (!strcmp(c,"header_name")) {
-      if (!header_file_set) header_file_name = strdup(read_word());
+      if (!header_file_set) header_file_name = fl_strdup(read_word());
       else read_word();
       goto CONTINUE;
     }
 
     if (!strcmp(c,"code_name")) {
-      if (!code_file_set) code_file_name = strdup(read_word());
+      if (!code_file_set) code_file_name = fl_strdup(read_word());
       else read_word();
       goto CONTINUE;
     }
diff --git fluid/fluid.cxx fluid/fluid.cxx
index 0cd6788..e9025a4 100644
--- fluid/fluid.cxx
+++ fluid/fluid.cxx
@@ -36,6 +36,7 @@
 #include <FL/Fl_Native_File_Chooser.H>
 #include <FL/Fl_Printer.H>
 #include <FL/fl_utf8.h>
+#include <FL/fl_string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -1544,7 +1545,7 @@ show_shell_window() {
 
 void set_filename(const char *c) {
   if (filename) free((void *)filename);
-  filename = c ? strdup(c) : NULL;
+  filename = c ? fl_strdup(c) : NULL;
 
   if (filename && !batch_mode)
     update_history(filename);
diff --git fluid/print_panel.cxx fluid/print_panel.cxx
index f41cae2..c5e520f 100644
--- fluid/print_panel.cxx
+++ fluid/print_panel.cxx
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include "../src/flstring.h"
 #include <FL/Fl_Preferences.H>
+#include <FL/fl_string.h>
 extern Fl_Preferences fluid_prefs;
 
 Fl_Double_Window *print_panel=(Fl_Double_Window *)0;
@@ -531,7 +532,7 @@ void print_load() {
         }
         *qptr = '\0';
 
-        print_choice->add(qname, 0, 0, (void *)strdup(name), 0);
+        print_choice->add(qname, 0, 0, (void *)fl_strdup(name), 0);
       } else if (!strncmp(line, "system default destination: ", 28)) {
         if (sscanf(line + 28, "%s", defname) != 1) defname[0] = '\0';
       }
diff --git fluid/print_panel.fl fluid/print_panel.fl
index 1dd0861..e2042f5 100644
--- fluid/print_panel.fl
+++ fluid/print_panel.fl
@@ -29,6 +29,9 @@ decl {\#include <stdlib.h>} {private local
 decl {\#include "../src/flstring.h"} {private local
 }
 
+decl {\#include <FL/fl_string.h>} {private local
+}
+
 decl {\#include <FL/Fl_Preferences.H>} {private local
 }
 
@@ -307,7 +310,7 @@ if ((lpstat = popen("LC_MESSAGES=C LANG=C lpstat -p -d", "r")) != NULL) {
       }
       *qptr = '\\0';
 
-      print_choice->add(qname, 0, 0, (void *)strdup(name), 0);
+      print_choice->add(qname, 0, 0, (void *)fl_strdup(name), 0);
     } else if (!strncmp(line, "system default destination: ", 28)) {
       if (sscanf(line + 28, "%s", defname) != 1) defname[0] = '\\0';
     }
diff --git fluid/template_panel.cxx fluid/template_panel.cxx
index f46b85d..fc04495 100644
--- fluid/template_panel.cxx
+++ fluid/template_panel.cxx
@@ -25,6 +25,7 @@
 #include <FL/fl_ask.H>
 #include <FL/Fl_Shared_Image.H>
 #include <FL/Fl_Preferences.H>
+#include <FL/fl_string.h>
 #if defined(_WIN32) && !defined(__CYGWIN__)
 #include <io.h>
 #else
@@ -257,7 +258,7 @@ void template_load() {
 
       // Add the template to the browser...
       snprintf(filename, sizeof(filename), "%s/%s", path, files[i]->d_name);
-      template_browser->add(name, strdup(filename));
+      template_browser->add(name, fl_strdup(filename));
     }
 
     free(files[i]);
diff --git fluid/template_panel.fl fluid/template_panel.fl
index 5da8874..b0d5b9f 100644
--- fluid/template_panel.fl
+++ fluid/template_panel.fl
@@ -29,6 +29,9 @@ decl {\#include <stdlib.h>} {private local
 decl {\#include "../src/flstring.h"} {private local
 }
 
+decl {\#include <FL/fl_string.h>} {private local
+}
+
 decl {\#include <errno.h>} {private local
 }
 
@@ -253,7 +256,7 @@ for (i = 0; i < num_files; i ++) {
 
     // Add the template to the browser...
     snprintf(filename, sizeof(filename), "%s/%s", path, files[i]->d_name);
-    template_browser->add(name, strdup(filename));
+    template_browser->add(name, fl_strdup(filename));
   }
 
   free(files[i]);
diff --git src/CMakeLists.txt src/CMakeLists.txt
index d3ef394..d5eee5d 100644
--- src/CMakeLists.txt
+++ src/CMakeLists.txt
@@ -157,6 +157,7 @@ set (CPPFILES
   fl_vertex.cxx
   screen_xywh.cxx
   fl_utf8.cxx
+  fl_string.cxx
   fl_encoding_latin1.cxx
   fl_encoding_mac_roman.cxx
 )
diff --git src/Fl_Check_Browser.cxx src/Fl_Check_Browser.cxx
index 6d80268..6f286e4 100644
--- src/Fl_Check_Browser.cxx
+++ src/Fl_Check_Browser.cxx
@@ -18,6 +18,7 @@
 #include <stdlib.h>
 #include "flstring.h"
 #include <FL/fl_draw.H>
+#include <FL/fl_string.h> // fl_strdup()
 #include <FL/Fl_Check_Browser.H>
 
 /* This uses a cache for faster access when you're scanning the list
@@ -243,7 +244,7 @@ int Fl_Check_Browser::add(char *s, int b) {
         p->prev = 0;
         p->checked = b;
         p->selected = 0;
-    p->text = strdup(s?s:"");
+    p->text = fl_strdup(s?s:"");
 
         if (b) {
                 nchecked_++;
diff --git src/Fl_File_Browser.cxx src/Fl_File_Browser.cxx
index cb92428..da70c87 100644
--- src/Fl_File_Browser.cxx
+++ src/Fl_File_Browser.cxx
@@ -34,6 +34,7 @@
 #include "Fl_System_Driver.H"
 #include <FL/fl_draw.H>
 #include <FL/filename.H>
+#include <FL/fl_string.h>
 #include <FL/Fl_Image.H>        // icon
 #include <stdio.h>
 #include <stdlib.h>
@@ -387,7 +388,7 @@ Fl_File_Browser::~Fl_File_Browser() {
  */
 void Fl_File_Browser::errmsg(const char* emsg) {
   if ( errmsg_ ) { free((void*)errmsg_); errmsg_ = NULL; }
-  errmsg_ = emsg ? strdup(emsg) : NULL;
+  errmsg_ = emsg ? fl_strdup(emsg) : NULL;
 }
 
 
diff --git src/Fl_File_Chooser2.cxx src/Fl_File_Chooser2.cxx
index ec04bd7..ddbb3e5 100644
--- src/Fl_File_Chooser2.cxx
+++ src/Fl_File_Chooser2.cxx
@@ -325,6 +325,7 @@
 #include <FL/platform.H>
 #include <FL/Fl_Shared_Image.H>
 #include <FL/fl_draw.H>
+#include <FL/fl_string.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -945,7 +946,7 @@ Fl_File_Chooser::filter(const char *p)          // I - Pattern(s)
   if (!p || !*p) p = "*";
 
   // Copy the pattern string...
-  copyp = strdup(p);
+  copyp = fl_strdup(p);
 
   // Separate the pattern string as necessary...
   showChoice->clear();
diff --git src/Fl_Help_View.cxx src/Fl_Help_View.cxx
index f6c6407..e27f81e 100644
--- src/Fl_Help_View.cxx
+++ src/Fl_Help_View.cxx
@@ -56,6 +56,7 @@
 #include <stdlib.h>
 #include <FL/fl_utf8.h>
 #include <FL/filename.H>        // fl_open_uri()
+#include <FL/fl_string.h>       // fl_strdup()
 #include "flstring.h"
 #include <ctype.h>
 #include <errno.h>
@@ -3404,7 +3405,7 @@ int Fl_Help_View::load(const char *f)
              "<P>Unable to follow the link \"%s\" - "
              "%s.</P></BODY>",
              localname, strerror(errno));
-    value_ = strdup(error);
+    value_ = fl_strdup(error);
     ret = -1;
   }
 
@@ -3543,7 +3544,7 @@ Fl_Help_View::value(const char *val)    // I - Text to view
   if (!val)
     return;
 
-  value_ = strdup(val);
+  value_ = fl_strdup(val);
 
   initial_load = 1;
   format();
diff --git src/Fl_Image_Reader.cxx src/Fl_Image_Reader.cxx
index 1f19379..f9a886b 100644
--- src/Fl_Image_Reader.cxx
+++ src/Fl_Image_Reader.cxx
@@ -22,6 +22,7 @@
 #include "Fl_Image_Reader.h"
 
 #include <FL/fl_utf8.h>
+#include <FL/fl_string.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -40,7 +41,7 @@
 int Fl_Image_Reader::open(const char *filename) {
   if (!filename)
     return -1;
-  pName = strdup(filename);
+  pName = fl_strdup(filename);
   if ( (pFile = fl_fopen(filename, "rb")) == NULL ) {
     return -1;
   }
@@ -51,7 +52,7 @@ int Fl_Image_Reader::open(const char *filename) {
 // Initialize the reader for memory access, name is copied and stored
 int Fl_Image_Reader::open(const char *imagename, const unsigned char *data) {
   if (imagename)
-    pName = strdup(imagename);
+    pName = fl_strdup(imagename);
   if (data) {
     pStart = pData = data;
     pIsData = 1;
diff --git src/Fl_MacOS_Sys_Menu_Bar.mm src/Fl_MacOS_Sys_Menu_Bar.mm
index 7f7abba..c589f81 100644
--- src/Fl_MacOS_Sys_Menu_Bar.mm
+++ src/Fl_MacOS_Sys_Menu_Bar.mm
@@ -17,6 +17,7 @@
 #if defined(__APPLE__)
 
 #include <FL/platform.H>
+#include <FL/fl_string.h>
 #include "drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H"
 #include "flstring.h"
 #include <stdio.h>
@@ -291,7 +292,7 @@ static void setMenuFlags( NSMenu* mh, int miCnt, const Fl_Menu_Item *m )
 
 static char *remove_ampersand(const char *s)
 {
-  char *ret = strdup(s);
+  char *ret = fl_strdup(s);
   const char *p = s;
   char *q = ret;
   while(*p != 0) {
diff --git src/Fl_Menu_add.cxx src/Fl_Menu_add.cxx
index b2282b6..d5fdae9 100644
--- src/Fl_Menu_add.cxx
+++ src/Fl_Menu_add.cxx
@@ -25,6 +25,7 @@
 // string with a % sign in it!
 
 #include <FL/Fl_Menu_.H>
+#include <FL/fl_string.h>
 #include "flstring.h"
 #include <stdio.h>
 #include <stdlib.h>
@@ -62,7 +63,7 @@ static Fl_Menu_Item* array_insert(
   memmove(array+n+1, array+n, sizeof(Fl_Menu_Item)*(size-n));
   // create the new item:
   Fl_Menu_Item* m = array+n;
-  m->text = text ? strdup(text) : 0;
+  m->text = text ? fl_strdup(text) : 0;
   m->shortcut_ = 0;
   m->callback_ = 0;
   m->user_data_ = 0;
@@ -455,7 +456,7 @@ void Fl_Menu_::replace(int i, const char *str) {
   if (!alloc) copy(menu_);
   if (alloc > 1) {
     free((void *)menu_[i].text);
-      str = strdup(str?str:"");
+      str = fl_strdup(str?str:"");
   }
   menu_[i].text = str;
 }
diff --git src/Fl_Native_File_Chooser_GTK.cxx src/Fl_Native_File_Chooser_GTK.cxx
index 4de7343..16ed1f4 100644
--- src/Fl_Native_File_Chooser_GTK.cxx
+++ src/Fl_Native_File_Chooser_GTK.cxx
@@ -25,6 +25,7 @@
 #include <FL/Fl_Shared_Image.H>
 #include <FL/Fl_Image_Surface.H>
 #include <FL/fl_draw.H>
+#include <FL/fl_string.h>
 #include <dlfcn.h>   // for dlopen et al
 #include "drivers/X11/Fl_X11_System_Driver.H"
 
@@ -110,7 +111,7 @@ private:
     const char *filter; // a filter string of the chooser
     pair(Fl_GTK_Native_File_Chooser_Driver* c, const char *f) {
       running = c;
-      filter = strdup(f);
+      filter = fl_strdup(f);
     };
     ~pair() {
       free((char*)filter);
@@ -490,7 +491,7 @@ static char *extract_dir_from_path(const char *path)
   }
   if (*path != '/') return NULL;
   if (dir) free(dir);
-  dir = strdup(path);
+  dir = fl_strdup(path);
   do {
     char *p = strrchr(dir, '/');
     if (p == dir) p++;
@@ -710,7 +711,7 @@ int Fl_GTK_Native_File_Chooser_Driver::fl_gtk_chooser_wrapper()
   GtkFileFilter **filter_tab = NULL;
   if (_parsedfilt) {
     filter_tab = new GtkFileFilter*[_nfilters];
-    char *filter = strdup(_parsedfilt);
+    char *filter = fl_strdup(_parsedfilt);
     p = strtok(filter, "\t");
     int count = 0;
     while (p) {
diff --git src/Fl_Native_File_Chooser_MAC.mm src/Fl_Native_File_Chooser_MAC.mm
index 0f6191d..6ae29be 100644
--- src/Fl_Native_File_Chooser_MAC.mm
+++ src/Fl_Native_File_Chooser_MAC.mm
@@ -27,6 +27,7 @@
 #include <FL/Fl_Native_File_Chooser.H>
 #include <FL/Fl_File_Chooser.H>
 #include <FL/filename.H>
+#include <FL/fl_string.h>
 #define MAXFILTERS      80
 #import <Cocoa/Cocoa.h>
 
@@ -402,7 +403,7 @@ int Fl_Quartz_Native_File_Chooser_Driver::filters() const {
 #define UNLIKELYPREFIX "___fl_very_unlikely_prefix_"
 
 int Fl_Quartz_Native_File_Chooser_Driver::get_saveas_basename(void) {
-  char *q = strdup( [[[_panel URL] path] UTF8String] );
+  char *q = fl_strdup( [[[_panel URL] path] UTF8String] );
   if ( !(_options & Fl_Native_File_Chooser::SAVEAS_CONFIRM) ) {
     const char *d = [[[[_panel URL] path] stringByDeletingLastPathComponent] UTF8String];
     int l = (int)strlen(d) + 1;
@@ -520,7 +521,7 @@ static char *prepareMacFilter(int count, const char *filter, char **patterns) {
 // correspondingly changes the extension of the output file name
 {
   if (fl_mac_os_version < 100600) return; // because of setNameFieldStringValue and nameFieldStringValue
-  char *s = strdup([[(NSPopUpButton*)sender titleOfSelectedItem] UTF8String]);
+  char *s = fl_strdup([[(NSPopUpButton*)sender titleOfSelectedItem] UTF8String]);
   if (!s) return;
   char *p = strchr(s, '(');
   if (!p) p = s;
@@ -724,7 +725,7 @@ int Fl_Quartz_Native_File_Chooser_Driver::post() {
           char *p = _filt_patt[_filt_value];
           char *q = strchr(p, '.'); if(!q) q = p-1;
           do q++; while (*q==' ' || *q=='{');
-          p = strdup(q);
+          p = fl_strdup(q);
           q = strchr(p, ','); if (q) *q = 0;
           [_panel setAllowedFileTypes:[NSArray arrayWithObject:[NSString stringWithUTF8String:p]]];
           free(p);
diff --git src/Fl_Preferences.cxx src/Fl_Preferences.cxx
index e732701..11851c0 100644
--- src/Fl_Preferences.cxx
+++ src/Fl_Preferences.cxx
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <FL/fl_utf8.h>
+#include <FL/fl_string.h>
 #include "flstring.h"
 
 
@@ -636,7 +637,7 @@ char Fl_Preferences::get( const char *key, char *&text, const char *defaultValue
   }
   if ( !v ) v = defaultValue;
   if ( v )
-    text = strdup( v );
+    text = fl_strdup( v );
   else
     text = 0;
   return ( v != defaultValue );
@@ -911,9 +912,9 @@ Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, Root root, const char
   root_(root)
 {
   char *filename = Fl::system_driver()->preference_rootnode(prefs, root, vendor, application);
-  filename_    = filename ? strdup(filename) : 0L;
-  vendor_      = strdup(vendor);
-  application_ = strdup(application);
+  filename_    = filename ? fl_strdup(filename) : 0L;
+  vendor_      = fl_strdup(vendor);
+  application_ = fl_strdup(application);
   read();
 }
 
@@ -931,14 +932,14 @@ Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, const char *path, con
     vendor = "unknown";
   if (!application) {
     application = "unknown";
-    filename_ = strdup(path);
+    filename_ = fl_strdup(path);
   } else {
     char filename[ FL_PATH_MAX ]; filename[0] = 0;
     snprintf(filename, sizeof(filename), "%s/%s.prefs", path, application);
-    filename_  = strdup(filename);
+    filename_  = fl_strdup(filename);
   }
-  vendor_      = strdup(vendor);
-  application_ = strdup(application);
+  vendor_      = fl_strdup(vendor);
+  application_ = fl_strdup(application);
   read();
 }
 
@@ -1112,7 +1113,7 @@ char Fl_Preferences::RootNode::getPath( char *path, int pathlen ) {
 // create a node that represents a group
 // - path must be a single word, prferable alnum(), dot and underscore only. Space is ok.
 Fl_Preferences::Node::Node( const char *path ) {
-  if ( path ) path_ = strdup( path ); else path_ = 0;
+  if ( path ) path_ = fl_strdup( path ); else path_ = 0;
   child_ = 0; next_ = 0; parent_ = 0;
   entry_ = 0;
   nEntry_ = NEntry_ = 0;
@@ -1225,7 +1226,7 @@ void Fl_Preferences::Node::setParent( Node *pn ) {
   pn->child_ = this;
   sprintf( nameBuffer, "%s/%s", pn->path_, path_ );
   free( path_ );
-  path_ = strdup( nameBuffer );
+  path_ = fl_strdup( nameBuffer );
 }
 
 // find the corresponding root node
@@ -1242,7 +1243,7 @@ Fl_Preferences::RootNode *Fl_Preferences::Node::findRoot() {
 // add a child to this node and set its path (try to find it first...)
 Fl_Preferences::Node *Fl_Preferences::Node::addChild( const char *path ) {
   sprintf( nameBuffer, "%s/%s", path_, path );
-  char *name = strdup( nameBuffer );
+  char *name = fl_strdup( nameBuffer );
   Node *nd = find( name );
   free( name );
   updateIndex();
@@ -1258,7 +1259,7 @@ void Fl_Preferences::Node::set( const char *name, const char *value )
       if ( strcmp( value, entry_[i].value ) != 0 ) {
         if ( entry_[i].value )
           free( entry_[i].value );
-        entry_[i].value = strdup( value );
+        entry_[i].value = fl_strdup( value );
         dirty_ = 1;
       }
       lastEntrySet = i;
@@ -1269,8 +1270,8 @@ void Fl_Preferences::Node::set( const char *name, const char *value )
     NEntry_ = NEntry_ ? NEntry_*2 : 10;
     entry_ = (Entry*)realloc( entry_, NEntry_ * sizeof(Entry) );
   }
-  entry_[ nEntry_ ].name = strdup( name );
-  entry_[ nEntry_ ].value = value?strdup( value ):0;
+  entry_[ nEntry_ ].name = fl_strdup( name );
+  entry_[ nEntry_ ].value = value?fl_strdup(value):0;
   lastEntrySet = nEntry_;
   nEntry_++;
   dirty_ = 1;
diff --git src/Fl_SVG_Image.cxx src/Fl_SVG_Image.cxx
index ca9644f..93aaee2 100644
--- src/Fl_SVG_Image.cxx
+++ src/Fl_SVG_Image.cxx
@@ -21,6 +21,7 @@
 #include <FL/Fl_SVG_Image.H>
 #include <FL/fl_utf8.h>
 #include <FL/fl_draw.H>
+#include <FL/fl_string.h>
 #include "Fl_Screen_Driver.H"
 #include <stdio.h>
 #include <stdlib.h>
@@ -152,7 +153,7 @@ void Fl_SVG_Image::init_(const char *filename, const char *in_filedata, Fl_SVG_I
     if (!filedata) ld(ERR_FILE_ACCESS);
   } else {
     // XXX: Make internal copy -- nsvgParse() modifies filedata during parsing (!)
-    filedata = in_filedata ? strdup(in_filedata) : NULL;
+    filedata = in_filedata ? fl_strdup(in_filedata) : NULL;
   }
   if (filedata) {
     counted_svg_image_->svg_image = nsvgParse(filedata, "px", 96);
diff --git src/Fl_System_Driver.H src/Fl_System_Driver.H
index 77a5897..73f197f 100644
--- src/Fl_System_Driver.H
+++ src/Fl_System_Driver.H
@@ -98,6 +98,9 @@ public:
   virtual int putenv(const char *var) {return -1;}
   virtual int open(const char* f, int oflags, int pmode) {return -1;}
 
+  // implement these to support cross-platform string operations
+  virtual char *strdup(const char *s) {return NULL;}
+
   // Note: the default implementation ignores the 'binary' argument.
   // Some platforms (notably Windows) may use this argument.
   virtual int open_ext(const char* f, int binary, int oflags, int pmode) {
diff --git src/Fl_Text_Buffer.cxx src/Fl_Text_Buffer.cxx
index 9691d7a..476f1ec 100644
--- src/Fl_Text_Buffer.cxx
+++ src/Fl_Text_Buffer.cxx
@@ -17,6 +17,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <FL/fl_utf8.h>
+#include <FL/fl_string.h>
 #include "flstring.h"
 #include <ctype.h>
 #include <FL/Fl.H>
@@ -462,7 +463,7 @@ int Fl_Text_Buffer::undo(int *cursorPos)
   if (xlen && ilen) {
     undobuffersize(ilen + 1);
     undobuffer[ilen] = 0;
-    char *tmp = strdup(undobuffer);
+    char *tmp = fl_strdup(undobuffer);
     replace(b, undoat, tmp);
     if (cursorPos)
       *cursorPos = mCursorPosHint;
diff --git src/Fl_Text_Display.cxx src/Fl_Text_Display.cxx
index 8b4450c..34f6f38 100644
--- src/Fl_Text_Display.cxx
+++ src/Fl_Text_Display.cxx
@@ -20,10 +20,11 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <FL/fl_utf8.h>
+#include <FL/fl_string.h>     // fl_strdup()
 #include "flstring.h"
 #include <limits.h>
 #include <ctype.h>
-#include <string.h>     // strdup()
+#include <string.h>
 #include <FL/Fl.H>
 #include <FL/platform.H>
 #include <FL/Fl_Text_Buffer.H>
@@ -171,7 +172,7 @@ Fl_Text_Display::Fl_Text_Display(int X, int Y, int W, int H, const char* l)
   linenumber_fgcolor_ = FL_INACTIVE_COLOR;
   linenumber_bgcolor_ = 53;     // ~90% gray
   linenumber_align_   = FL_ALIGN_RIGHT;
-  linenumber_format_  = strdup("%d");
+  linenumber_format_  = fl_strdup("%d");
 
   // Method calls -- only AFTER all members initialized
   color(FL_BACKGROUND2_COLOR, FL_SELECTION_COLOR);
@@ -326,7 +327,7 @@ Fl_Align Fl_Text_Display::linenumber_align() const {
 */
 void Fl_Text_Display::linenumber_format(const char* val) {
   if ( linenumber_format_ ) free((void*)linenumber_format_);
-  linenumber_format_ = val ? strdup(val) : 0;
+  linenumber_format_ = val ? fl_strdup(val) : 0;
 }
 
 /**
diff --git src/Fl_Tooltip.cxx src/Fl_Tooltip.cxx
index 53fcdb1..220e460 100644
--- src/Fl_Tooltip.cxx
+++ src/Fl_Tooltip.cxx
@@ -18,10 +18,10 @@
 #include <FL/fl_draw.H>
 #include <FL/Fl_Menu_Window.H>
 #include <FL/Fl.H>
+#include <FL/fl_string.h>
 #include "Fl_System_Driver.H"
 
 #include <stdio.h>
-#include <string.h>   // strdup()
 
 float     Fl_Tooltip::delay_ = 1.0f;
 float     Fl_Tooltip::hidedelay_ = 12.0f;
@@ -379,7 +379,7 @@ void Fl_Widget::copy_tooltip(const char *text) {
   if (flags() & COPIED_TOOLTIP) free((void *)(tooltip_));
   if (text) {
     set_flag(COPIED_TOOLTIP);
-    tooltip_ = strdup(text);
+    tooltip_ = fl_strdup(text);
   } else {
     clear_flag(COPIED_TOOLTIP);
     tooltip_ = (char *)0;
diff --git src/Fl_Tree.cxx src/Fl_Tree.cxx
index ec1d481..5dab99c 100644
--- src/Fl_Tree.cxx
+++ src/Fl_Tree.cxx
@@ -6,6 +6,7 @@
 
 #include <FL/Fl_Tree.H>
 #include <FL/Fl_Preferences.H>
+#include <FL/fl_string.h>
 
 //////////////////////
 // Fl_Tree.cxx
@@ -2643,7 +2644,7 @@ void Fl_Tree::load(Fl_Preferences &prefs) {
   n = prefs.entries();
   for (i=0; i<n; i++) {
     // We must remove all fwd slashes in the key and value strings. Replace with backslash.
-    char *key = strdup(prefs.entry(i));
+    char *key = fl_strdup(prefs.entry(i));
     int kn = (int) strlen(key);
     for (j=0; j<kn; j++) {
       if (key[j]=='/') key[j]='\\';
diff --git src/Fl_Tree_Item.cxx src/Fl_Tree_Item.cxx
index 3df432c..9861127 100644
--- src/Fl_Tree_Item.cxx
+++ src/Fl_Tree_Item.cxx
@@ -3,10 +3,12 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <FL/Fl.H>
 #include <FL/Fl_Widget.H>
 #include <FL/Fl_Tree_Item.H>
 #include <FL/Fl_Tree_Prefs.H>
 #include <FL/Fl_Tree.H>
+#include <FL/fl_string.h>
 
 //////////////////////
 // Fl_Tree_Item.cxx
@@ -103,7 +105,7 @@ Fl_Tree_Item::~Fl_Tree_Item() {
 /// Copy constructor.
 Fl_Tree_Item::Fl_Tree_Item(const Fl_Tree_Item *o) {
   _tree             = o->_tree;
-  _label        = o->label() ? strdup(o->label()) : 0;
+  _label        = o->label() ? fl_strdup(o->label()) : 0;
   _labelfont    = o->labelfont();
   _labelsize    = o->labelsize();
   _labelfgcolor = o->labelfgcolor();
@@ -154,7 +156,7 @@ void Fl_Tree_Item::show_self(const char *indent) const {
 ///
 void Fl_Tree_Item::label(const char *name) {
   if ( _label ) { free((void*)_label); _label = 0; }
-  _label = name ? strdup(name) : 0;
+  _label = name ? fl_strdup(name) : 0;
   recalc_tree();                // may change label geometry
 }
 
diff --git src/Fl_Widget.cxx src/Fl_Widget.cxx
index 25a4bb9..8b4de1a 100644
--- src/Fl_Widget.cxx
+++ src/Fl_Widget.cxx
@@ -19,6 +19,7 @@
 #include <FL/Fl_Group.H>
 #include <FL/Fl_Tooltip.H>
 #include <FL/fl_draw.H>
+#include <FL/fl_string.h>
 #include <stdlib.h>
 #include "flstring.h"
 
@@ -291,7 +292,7 @@ void Fl_Widget::copy_label(const char *a) {
   if ((flags() & COPIED_LABEL) && (label_.value == a))
     return;
   if (a) {
-    label(strdup(a));
+    label(fl_strdup(a));
     set_flag(COPIED_LABEL);
   } else {
     label(0);
diff --git src/Fl_Window.cxx src/Fl_Window.cxx
index dee4b32..a999511 100644
--- src/Fl_Window.cxx
+++ src/Fl_Window.cxx
@@ -28,6 +28,7 @@
 #include <FL/Fl_Window.H>
 #include <FL/Fl_Tooltip.H>
 #include <FL/fl_draw.H>
+#include <FL/fl_string.h>
 #include <stdlib.h>
 #include "flstring.h"
 
@@ -225,7 +226,7 @@ void Fl_Window::default_xclass(const char *xc)
     default_xclass_ = 0L;
   }
   if (xc) {
-    default_xclass_ = strdup(xc);
+    default_xclass_ = fl_strdup(xc);
   }
 }
 
@@ -260,7 +261,7 @@ void Fl_Window::xclass(const char *xc)
     xclass_ = 0L;
   }
   if (xc) {
-    xclass_ = strdup(xc);
+    xclass_ = fl_strdup(xc);
     if (!default_xclass_) {
       default_xclass(xc);
     }
diff --git src/Fl_cocoa.mm src/Fl_cocoa.mm
index 934dd2f..50c658e 100644
--- src/Fl_cocoa.mm
+++ src/Fl_cocoa.mm
@@ -30,6 +30,7 @@ extern "C" {
 #include <FL/Fl_Printer.H>
 #include <FL/fl_draw.H>
 #include <FL/Fl_Rect.H>
+#include <FL/fl_string.h>
 #include "drivers/Quartz/Fl_Quartz_Graphics_Driver.H"
 #include "drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.H"
 #include "drivers/Cocoa/Fl_Cocoa_Screen_Driver.H"
@@ -1587,7 +1588,7 @@ static void drain_dropped_files_list() {
     return;
   }
   NSString *s = (NSString*)[dropped_files_list objectAtIndex:0];
-  char *fname = strdup([s UTF8String]);
+  char *fname = fl_strdup([s UTF8String]);
   [dropped_files_list removeObjectAtIndex:0];
   if ([dropped_files_list count] == 0) {
     [dropped_files_list release];
@@ -3529,7 +3530,7 @@ static int get_plain_text_from_clipboard(int clipboard)
                                                         [data length],
                                                         [found isEqualToString:@"public.utf16-plain-text"] ? kCFStringEncodingUnicode : kCFStringEncodingMacRoman,
                                                         false);
-        aux_c = strdup([auxstring UTF8String]);
+        aux_c = fl_strdup([auxstring UTF8String]);
         [auxstring release];
         len = strlen(aux_c) + 1;
       }
diff --git src/Fl_get_system_colors.cxx src/Fl_get_system_colors.cxx
index e1b7fc2..73388c8 100644
--- src/Fl_get_system_colors.cxx
+++ src/Fl_get_system_colors.cxx
@@ -21,6 +21,7 @@
 #include <FL/platform.H>
 #include <FL/math.h>
 #include <FL/fl_utf8.h>
+#include <FL/fl_string.h>
 #include "flstring.h"
 #include <stdio.h>
 #include <stdlib.h>
@@ -163,9 +164,9 @@ int Fl::scheme(const char *s) {
 
   if (s) {
     if (!fl_ascii_strcasecmp(s, "none") || !fl_ascii_strcasecmp(s, "base") || !*s) s = 0;
-    else if (!fl_ascii_strcasecmp(s, "gtk+")) s = strdup("gtk+");
-    else if (!fl_ascii_strcasecmp(s, "plastic")) s = strdup("plastic");
-    else if (!fl_ascii_strcasecmp(s, "gleam")) s = strdup("gleam");
+    else if (!fl_ascii_strcasecmp(s, "gtk+")) s = fl_strdup("gtk+");
+    else if (!fl_ascii_strcasecmp(s, "plastic")) s = fl_strdup("plastic");
+    else if (!fl_ascii_strcasecmp(s, "gleam")) s = fl_strdup("gleam");
     else s = 0;
   }
   if (scheme_) free((void*)scheme_);
diff --git src/Fl_win32.cxx src/Fl_win32.cxx
index d234f7a..e0d5c9f 100644
--- src/Fl_win32.cxx
+++ src/Fl_win32.cxx
@@ -60,6 +60,7 @@ void fl_cleanup_dc_list(void);
 #include "drivers/WinAPI/Fl_WinAPI_Screen_Driver.H"
 #include "drivers/GDI/Fl_GDI_Graphics_Driver.H"
 #include <FL/fl_utf8.h>
+#include <FL/fl_string.h>
 #include <FL/Fl_Window.H>
 #include <FL/fl_draw.H>
 #include <FL/Enumerations.H>
@@ -1919,7 +1920,7 @@ public:
       NName += 5;
       name = (char **)realloc(name, NName * sizeof(char *));
     }
-    name[nName++] = strdup(n);
+    name[nName++] = fl_strdup(n);
   }
   char has_name(const char *n) {
     int i;
diff --git src/Makefile src/Makefile
index 123aef0..c1409a5 100644
--- src/Makefile
+++ src/Makefile
@@ -160,7 +160,8 @@ CPPFILES = \
 	fl_symbols.cxx \
 	fl_vertex.cxx \
 	screen_xywh.cxx \
-	fl_utf8.cxx
+	fl_utf8.cxx \
+	fl_string.cxx
 
 OBJCPPFILES = \
 	Fl_cocoa.mm \
diff --git src/drivers/Android/Fl_Android_Application.cxx src/drivers/Android/Fl_Android_Application.cxx
index 8705354..793ebb5 100644
--- src/drivers/Android/Fl_Android_Application.cxx
+++ src/drivers/Android/Fl_Android_Application.cxx
@@ -25,6 +25,7 @@
 
 #include <FL/platform.H>
 #include <FL/fl_draw.H>
+#include <FL/fl_string.h>
 
 #include <jni.h>
 
@@ -376,7 +377,7 @@ void *Fl_Android_Application::thread_entry(void* param)
   pthread_cond_broadcast(&pCond);
   pthread_mutex_unlock(&pMutex);
 
-  char *argv[] = { strdup(pActivity->obbPath), 0 };
+  char *argv[] = { fl_strdup(pActivity->obbPath), 0 };
   main(1, argv);
 
   destroy();
diff --git src/drivers/Android/Fl_Android_System_Driver.H src/drivers/Android/Fl_Android_System_Driver.H
index 198d7a2..84f8262 100644
--- src/drivers/Android/Fl_Android_System_Driver.H
+++ src/drivers/Android/Fl_Android_System_Driver.H
@@ -22,6 +22,7 @@
 #ifndef FL_ANDROID_SYSTEM_DRIVER_H
 #define FL_ANDROID_SYSTEM_DRIVER_H
 
+#include <FL/fl_string.h>
 #include "../../Fl_System_Driver.H"
 #include <stdarg.h>
 
@@ -46,7 +47,7 @@ public:
   virtual void fatal(const char *format, va_list args);
   virtual char *utf2mbcs(const char *s);
   virtual char *getenv(const char *var);
-  virtual int putenv(const char *var) { return ::putenv(strdup(var)); }
+  virtual int putenv(const char *var) { return ::putenv(fl_strdup(var)); }
   virtual int open(const char *fnam, int oflags, int pmode);
   virtual int open_ext(const char *fnam, int binary, int oflags, int pmode);
   virtual FILE *fopen(const char *fnam, const char *mode);
diff --git src/drivers/Android/Fl_Android_System_Driver.cxx src/drivers/Android/Fl_Android_System_Driver.cxx
index 0fa9671..d25e964 100644
--- src/drivers/Android/Fl_Android_System_Driver.cxx
+++ src/drivers/Android/Fl_Android_System_Driver.cxx
@@ -18,6 +18,7 @@
 #include "Fl_Android_System_Driver.H"
 #include <FL/Fl.H>
 #include <FL/fl_utf8.h>
+#include <FL/fl_string.h>
 #include <FL/filename.H>
 #include <FL/Fl_File_Browser.H>
 #include <FL/Fl_File_Icon.H>
@@ -545,7 +546,7 @@ Fl_WinAPI_System_Driver::filename_relative(char *to,    // O - Relative filename
   char          *newslash;              // Directory separator
   const char    *slash;                 // Directory separator
   char          *cwd = 0L, *cwd_buf = 0L;
-  if (base) cwd = cwd_buf = strdup(base);
+  if (base) cwd = cwd_buf = fl_strdup(base);
 
   // return if "from" is not an absolute path
   if (from[0] == '\0' ||
diff --git src/drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm src/drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm
index ab3d90f..2a09556 100644
--- src/drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm
+++ src/drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm
@@ -26,6 +26,7 @@
 #include <FL/platform.H>
 #include <FL/fl_ask.H>
 #include <FL/fl_draw.H>
+#include <FL/fl_string.h>
 #import <Cocoa/Cocoa.h>
 
 typedef OSStatus (*PMSessionSetDocumentFormatGeneration_type)(
@@ -196,7 +197,7 @@ int Fl_Cocoa_Printer_Driver::begin_job (int pagecount, int *frompage, int *topag
     if (perr_message) {
       NSError *nserr = [NSError errorWithDomain:NSCocoaErrorDomain code:status userInfo:nil];
       NSString *s = [nserr localizedDescription];
-      if (s) *perr_message = strdup([s UTF8String]);
+      if (s) *perr_message = fl_strdup([s UTF8String]);
     }
     return 2;
   }
diff --git src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx
index 1e2b492..3371c4e 100644
--- src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx
+++ src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx
@@ -41,6 +41,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <FL/fl_string.h>
 
 // This function fills in the FLTK font table with all the fonts that
 // are found on the X server.  It tries to place the fonts into families
@@ -98,12 +99,12 @@ enumcbw(CONST LOGFONTW    *lpelf,
     if (!strcmp(Fl::get_font_name((Fl_Font)i),n)) {free(n);return 1;}
   char buffer[LF_FACESIZE + 1];
   strcpy(buffer+1, n);
-  buffer[0] = ' '; Fl::set_font((Fl_Font)(fl_free_font++), strdup(buffer));
+  buffer[0] = ' '; Fl::set_font((Fl_Font)(fl_free_font++), fl_strdup(buffer));
   if (lpelf->lfWeight <= 400)
-    buffer[0] = 'B', Fl::set_font((Fl_Font)(fl_free_font++), strdup(buffer));
-  buffer[0] = 'I'; Fl::set_font((Fl_Font)(fl_free_font++), strdup(buffer));
+    buffer[0] = 'B', Fl::set_font((Fl_Font)(fl_free_font++), fl_strdup(buffer));
+  buffer[0] = 'I'; Fl::set_font((Fl_Font)(fl_free_font++), fl_strdup(buffer));
   if (lpelf->lfWeight <= 400)
-    buffer[0] = 'P', Fl::set_font((Fl_Font)(fl_free_font++), strdup(buffer));
+    buffer[0] = 'P', Fl::set_font((Fl_Font)(fl_free_font++), fl_strdup(buffer));
   free(n);
   return 1;
 } /* enumcbw */
diff --git src/drivers/Posix/Fl_Posix_System_Driver.H src/drivers/Posix/Fl_Posix_System_Driver.H
index 55255b8..3f4cf72 100644
--- src/drivers/Posix/Fl_Posix_System_Driver.H
+++ src/drivers/Posix/Fl_Posix_System_Driver.H
@@ -38,6 +38,7 @@
  - directory and file access
  - system time and system timer
  - multithreading
+ - string management
  */
 
 class Fl_Posix_System_Driver : public Fl_System_Driver
@@ -74,6 +75,7 @@ public:
   virtual const char *home_directory_name() { return ::getenv("HOME"); }
   virtual int dot_file_hidden() {return 1;}
   virtual void gettime(time_t *sec, int *usec);
+  virtual char* strdup(const char *s) {return ::strdup(s);}
 };
 
 #endif // FL_POSIX_SYSTEM_DRIVER_H
diff --git src/drivers/Posix/Fl_Posix_System_Driver.cxx src/drivers/Posix/Fl_Posix_System_Driver.cxx
index d39ea6c..9f255f3 100644
--- src/drivers/Posix/Fl_Posix_System_Driver.cxx
+++ src/drivers/Posix/Fl_Posix_System_Driver.cxx
@@ -20,6 +20,7 @@
 #include <FL/Fl_File_Browser.H>
 #include <FL/Fl_File_Icon.H>
 #include <FL/filename.H>
+#include <FL/fl_string.h>
 #include <FL/Fl.H>
 #include <locale.h>
 #include <stdio.h>
@@ -65,7 +66,7 @@ void *Fl_Posix_System_Driver::dlopen(const char *filename)
   ptr = double_dlopen(filename);
 #  ifdef __APPLE_CC__ // allows testing on Darwin + XQuartz + fink
   if (!ptr) {
-    char *f_dylib = strdup(filename);
+    char *f_dylib = fl_strdup(filename);
     strcpy(strrchr(f_dylib, '.'), ".dylib");
     char path[FL_PATH_MAX];
     sprintf(path, "/sw/lib/%s", f_dylib);
diff --git src/drivers/PostScript/Fl_PostScript.cxx src/drivers/PostScript/Fl_PostScript.cxx
index b7b10da..5adf205 100644
--- src/drivers/PostScript/Fl_PostScript.cxx
+++ src/drivers/PostScript/Fl_PostScript.cxx
@@ -23,6 +23,7 @@
 #include <FL/Fl_PostScript.H>
 #include <FL/Fl_Native_File_Chooser.H>
 #include "../../Fl_System_Driver.H"
+#include <FL/fl_string.h>
 #include <stdarg.h>
 #include <time.h>
 
@@ -83,7 +84,7 @@ int Fl_PostScript_File_Device::begin_job (int pagecount, enum Fl_Paged_Device::P
   Fl_PostScript_Graphics_Driver *ps = driver();
   ps->output = fl_fopen(fnfc.filename(), "w");
   if(ps->output == NULL) return 2;
-  ps->ps_filename_ = strdup(fnfc.filename());
+  ps->ps_filename_ = fl_strdup(fnfc.filename());
   ps->start_postscript(pagecount, format, layout);
   this->set_current();
   return 0;
diff --git src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx
index e6352af..fe43f0c 100644
--- src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx
+++ src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx
@@ -79,6 +79,7 @@
 #include <FL/Fl.H>
 #include <FL/platform.H>
 #include <FL/fl_utf8.h> // for fl_utf8toUtf16()
+#include <FL/fl_string.h> // fl_strdup()
 
 Fl_Fontdesc* fl_fonts = NULL;
 
@@ -682,7 +683,7 @@ Fl_Font Fl_Quartz_Graphics_Driver::ADD_SUFFIX(set_fonts, _CoreText)(const char*
     CFRelease(font);
     static char fname[200];
     CFStringGetCString(cfname, fname, sizeof(fname), kCFStringEncodingUTF8);
-    tabfontnames[i] = strdup(fname); // never free'ed
+    tabfontnames[i] = fl_strdup(fname); // never free'ed
     CFRelease(cfname);
   }
   CFRelease(arrayref);
@@ -869,7 +870,7 @@ Fl_Font Fl_Quartz_Graphics_Driver::ADD_SUFFIX(set_fonts, _ATSU)(const char* xsta
       oName[511] = 0;
     else
       oName[actualLength] = 0;
-    Fl::set_font((Fl_Font)(fl_free_font++), strdup(oName));
+    Fl::set_font((Fl_Font)(fl_free_font++), fl_strdup(oName));
     //  free(oName);
   }
   free(oFontIDs);
diff --git src/drivers/SVG/Fl_SVG_File_Surface.cxx src/drivers/SVG/Fl_SVG_File_Surface.cxx
index d0946da..5106c64 100644
--- src/drivers/SVG/Fl_SVG_File_Surface.cxx
+++ src/drivers/SVG/Fl_SVG_File_Surface.cxx
@@ -28,6 +28,8 @@
 #include <FL/Fl_RGB_Image.H>
 #include <FL/Fl_Pixmap.H>
 #include <FL/Fl_Bitmap.H>
+#include <FL/fl_string.h>
+
 extern "C" {
 #if defined(HAVE_LIBPNG)
 #  ifdef HAVE_PNG_H
@@ -137,7 +139,7 @@ Fl_SVG_Graphics_Driver::Fl_SVG_Graphics_Driver(FILE *f) {
   clip_count_ = 0;
   clip_ = NULL;
   user_dash_array_ = 0;
-  dasharray_ = strdup("none");
+  dasharray_ = fl_strdup("none");
   p_size = 0;
   p = NULL;
   last_rgb_name_ = NULL;
@@ -205,13 +207,13 @@ void Fl_SVG_Graphics_Driver::compute_dasharray(float s, char *dashes) {
       sprintf(dasharray_+strlen(dasharray_), "%.3f,", (*p)/s);
     }
     dasharray_[strlen(dasharray_) - 1] = 0;
-    if (user_dash_array_ != dashes) user_dash_array_ = strdup(dashes);
+    if (user_dash_array_ != dashes) user_dash_array_ = fl_strdup(dashes);
     return;
   }
   int dash_part = line_style_ & 0xFF;
   if (dash_part == FL_SOLID)  {
     if (dasharray_ && strcmp(dasharray_, "none")) free(dasharray_);
-    dasharray_ = strdup("none");
+    dasharray_ = fl_strdup("none");
   } else {
     int cap_part = (line_style_ & 0xF00);
     bool is_flat = (cap_part == FL_CAP_FLAT || cap_part == 0);
@@ -458,7 +460,7 @@ void Fl_SVG_Graphics_Driver::define_rgb_png(Fl_RGB_Image *rgb, const char *name,
   }
   if (name) {
     if (last_rgb_name_) free(last_rgb_name_);
-    last_rgb_name_ = strdup(name);
+    last_rgb_name_ = fl_strdup(name);
   }
   float f = rgb->data_w() > rgb->data_h() ? float(rgb->w()) / rgb->data_w(): float(rgb->h()) / rgb->data_h();
   if (name) fprintf(out_, "<defs><image id=\"%s\" ", name);
@@ -547,7 +549,7 @@ static void term_destination(jpeg_compress_struct *cinfo) {
 void Fl_SVG_Graphics_Driver::define_rgb_jpeg(Fl_RGB_Image *rgb, const char *name, int x, int y) {
   if (name) {
     if (last_rgb_name_) free(last_rgb_name_);
-    last_rgb_name_ = strdup(name);
+    last_rgb_name_ = fl_strdup(name);
   }
   float f = rgb->data_w() > rgb->data_h() ? float(rgb->w()) / rgb->data_w(): float(rgb->h()) / rgb->data_h();
   if (name) fprintf(out_, "<defs><image id=\"%s\" ", name);
diff --git src/drivers/WinAPI/Fl_WinAPI_System_Driver.H src/drivers/WinAPI/Fl_WinAPI_System_Driver.H
index 91b230d..0dd12ca 100644
--- src/drivers/WinAPI/Fl_WinAPI_System_Driver.H
+++ src/drivers/WinAPI/Fl_WinAPI_System_Driver.H
@@ -24,6 +24,7 @@
 
 #include "../../Fl_System_Driver.H"
 #include <stdarg.h>
+#include <string.h>  // strdup
 
 /*
  Move everything here that manages the system interface.
@@ -34,6 +35,7 @@
  - directory and file access
  - system time and system timer
  - multithreading
+ - string management
  */
 
 class Fl_WinAPI_System_Driver : public Fl_System_Driver
@@ -116,6 +118,7 @@ public:
   virtual void remove_fd(int, int when);
   virtual void remove_fd(int);
   virtual void gettime(time_t *sec, int *usec);
+  virtual char* strdup(const char *s) { return ::_strdup(s); }
 };
 
 #endif // FL_WINAPI_SYSTEM_DRIVER_H
diff --git src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx
index 592e192..025d4ee 100644
--- src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx
+++ src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx
@@ -18,6 +18,7 @@
 #include "Fl_WinAPI_System_Driver.H"
 #include <FL/Fl.H>
 #include <FL/fl_utf8.h>
+#include <FL/fl_string.h>  // fl_strdup()
 #include <FL/filename.H>
 #include <FL/Fl_File_Browser.H>
 #include <FL/Fl_File_Icon.H>
@@ -548,7 +549,7 @@ Fl_WinAPI_System_Driver::filename_relative(char *to,    // O - Relative filename
   char          *newslash;              // Directory separator
   const char    *slash;                 // Directory separator
   char          *cwd = 0L, *cwd_buf = 0L;
-  if (base) cwd = cwd_buf = strdup(base);
+  if (base) cwd = cwd_buf = fl_strdup(base);
 
   // return if "from" is not an absolute path
   if (from[0] == '\0' ||
diff --git src/drivers/X11/Fl_X11_System_Driver.cxx src/drivers/X11/Fl_X11_System_Driver.cxx
index 28827bc..6dcaee0 100644
--- src/drivers/X11/Fl_X11_System_Driver.cxx
+++ src/drivers/X11/Fl_X11_System_Driver.cxx
@@ -17,6 +17,7 @@
 
 #include "Fl_X11_System_Driver.H"
 #include <FL/Fl_File_Browser.H>
+#include <FL/fl_string.h>  // fl_strdup
 #include "../../flstring.h"
 
 #include <X11/Xlib.h>
@@ -592,7 +593,7 @@ bool Fl_X11_System_Driver::probe_for_GTK(int major, int minor, void **ptr_gtk) {
   char *before = NULL;
   // record in "before" the calling program's current locale
   char *p = setlocale(LC_ALL, NULL);
-  if (p) before = strdup(p);
+  if (p) before = fl_strdup(p);
   int ac = 0;
   init_f(&ac, NULL); // may change the locale
   if (before) {
diff --git src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx
index 8b37845..9251eaf 100644
--- src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx
+++ src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx
@@ -20,6 +20,7 @@
 #include <FL/Fl.H>
 #include <FL/fl_draw.H>
 #include <FL/platform.H>
+#include <FL/fl_string.h>
 #include "Fl_Font.H"
 
 #include <stdio.h>
@@ -305,7 +306,7 @@ Fl_Font Fl_Xlib_Graphics_Driver::set_fonts(const char* xstarname) {
         if (fl_fonts[j].name && !strcmp(fl_fonts[j].name, p)) break;
       } else */{
         j = fl_free_font++;
-        if (p == canon) p = strdup(p); else used_xlist = 1;
+        if (p == canon) p = fl_strdup(p); else used_xlist = 1;
         Fl::set_font((Fl_Font)j, p);
         break;
       }
@@ -521,7 +522,7 @@ static char *put_font_size(const char *n, int size)
         const char *f;
         char *name;
         int nbf = 1;
-        name = strdup(n);
+        name = fl_strdup(n);
         while (name[i]) {
                 if (name[i] == ',') {nbf++; name[i] = '\0';}
                 i++;
diff --git src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx
index 5a80904..5c88ec1 100644
--- src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx
+++ src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx
@@ -20,6 +20,7 @@
 #include "Fl_Xlib_Graphics_Driver.H"
 #include <FL/Fl.H>
 #include <FL/fl_draw.H>
+#include <FL/fl_string.h>  // fl_strdup()
 #include <FL/platform.H>
 #include "Fl_Font.H"
 
@@ -423,7 +424,7 @@ Fl_Font Fl_Xlib_Graphics_Driver::set_fonts(const char* pattern_name)
       }
       else
       { // The listed name has been modified
-        full_list[j] = strdup(first);
+        full_list[j] = fl_strdup(first);
         // Free the font name storage
         free (font);
       }
@@ -451,7 +452,7 @@ Fl_Font Fl_Xlib_Graphics_Driver::set_fonts(const char* pattern_name)
         make_raw_name(xft_name, full_list[j]);
         // NOTE: This just adds on AFTER the default fonts - no attempt is made
         // to identify already loaded fonts. Is this bad?
-        stored_name = strdup(xft_name);
+        stored_name = fl_strdup(xft_name);
         Fl::set_font((Fl_Font)(j + FL_FREE_FONT), stored_name);
         fl_free_font ++;
 
@@ -552,7 +553,7 @@ static XftFont* fontopen(const char* name, /*Fl_Fontsize*/double size, bool core
     }
 
     if(comma_count) { // multiple comma-separated names were passed
-      char *local_name = strdup(name); // duplicate the full name so we can edit the copy
+      char *local_name = fl_strdup(name); // duplicate the full name so we can edit the copy
       char *curr = local_name; // points to first name in string
       char *nxt; // next name in string
       do {
@@ -681,7 +682,7 @@ static XftFont* fontopen(const char* name, /*Fl_Fontsize*/double size, bool core
      * XLFD's to construct a "super-pattern" that incorporates attributes from all
      * XLFD's and use that to perform a XftFontMatch(). Maybe...
      */
-    char *local_name = strdup(name);
+    char *local_name = fl_strdup(name);
     if(comma_count) { // This means we were passed multiple XLFD's
       char *pc = strchr(local_name, ',');
       *pc = 0; // terminate the XLFD at the first comma
@@ -1087,7 +1088,7 @@ static XFontStruct* load_xfont_for_xft2(Fl_Graphics_Driver *driver) {
   const char *weight = wt_med; // no specifc weight requested - accept any
   char slant = 'r';   // regular non-italic by default
   char xlfd[128];     // we will put our synthetic XLFD in here
-  char *pc = strdup(fl_fonts[fnum].name); // what font were we asked for?
+  char *pc = fl_strdup(fl_fonts[fnum].name); // what font were we asked for?
 #if USE_PANGO
   char *p = pc + 1;
   while (*p) { *p = tolower(*p); p++; }
diff --git src/filename_absolute.cxx src/filename_absolute.cxx
index 67beb50..e39da32 100644
--- src/filename_absolute.cxx
+++ src/filename_absolute.cxx
@@ -22,6 +22,7 @@
 
 #include <FL/filename.H>
 #include <FL/Fl.H>
+#include <FL/fl_string.h>
 #include "Fl_System_Driver.H"
 #include <stdlib.h>
 #include "flstring.h"
@@ -162,7 +163,7 @@ Fl_System_Driver::filename_relative(char *to,   // O - Relative filename
   char          *newslash;              // Directory separator
   const char    *slash;                 // Directory separator
   char          *cwd = 0L, *cwd_buf = 0L;
-  if (base) cwd = cwd_buf = strdup(base);
+  if (base) cwd = cwd_buf = fl_strdup(base);
 
   // return if "from" is not an absolute path
   if (from[0] == '\0' || !isdirsep(*from)) {
diff --git src/fl_ask.cxx src/fl_ask.cxx
index ecd853b..f711a9f 100644
--- src/fl_ask.cxx
+++ src/fl_ask.cxx
@@ -29,6 +29,7 @@
 #include "flstring.h"
 
 #include <FL/Fl.H>
+#include <FL/fl_string.h>
 
 #include <FL/fl_ask.H>
 
@@ -664,7 +665,7 @@ void fl_message_title_default(const char *title) {
     message_title_default = 0;
   }
   if (title)
-    message_title_default = strdup(title);
+    message_title_default = fl_strdup(title);
 }
 
 /** @} */
diff --git src/fl_string.cxx src/fl_string.cxx
new file mode 100644
index 0000000..c53c0e2
--- /dev/null
+++ src/fl_string.cxx
@@ -0,0 +1,34 @@
+/*
+ * Platform agnostic string portability functions for the Fast Light Tool Kit (FLTK).
+ *
+ * Copyright 2020 by Bill Spitzak and others.
+ *
+ * This library is free software. Distribution and use rights are outlined in
+ * the file "COPYING" which should have been included with this file.  If this
+ * file is missing or damaged, see the license at:
+ *
+ *     https://www.fltk.org/COPYING.php
+ *
+ * Please see the following page on how to report bugs and issues:
+ *
+ *     https://www.fltk.org/bugs.php
+ */
+
+#include <FL/fl_string.h>
+#include <string.h>  // strdup/_strdup
+#include "Fl_System_Driver.H"
+
+/**
+  Cross platform interface to POSIX function strdup().
+
+  The fl_strdup() function returns a pointer to a new string which is
+  a duplicate of the string 's'. Memory for the new string is obtained
+  with malloc(3), and can be freed with free(3).
+
+  Implementation:
+    - POSIX: strdup()
+    - WinAPI: _strdup()
+ */
+char *fl_strdup(const char *s) {
+  return Fl::system_driver()->strdup(s);
+}
diff --git src/flstring.h src/flstring.h
index fa31112..d902c0a 100644
--- src/flstring.h
+++ src/flstring.h
@@ -52,10 +52,6 @@
  * Some of these functions are also defined in ISO C99...
  */
 
-#  if defined(_MSC_VER)
-#    define strdup _strdup
-#  endif /* _MSC_VER */
-
 #  if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
 #    define strcasecmp(s,t)     _stricmp((s), (t))
 #    define strncasecmp(s,t,n)  _strnicmp((s), (t), (n))
diff --git src/print_panel.cxx src/print_panel.cxx
index 617b993..7b29991 100644
--- src/print_panel.cxx
+++ src/print_panel.cxx
@@ -36,6 +36,7 @@
 #include "../src/flstring.h"
 #include <FL/Fl_Preferences.H>
 #include <FL/Fl_Int_Input.H>
+#include <FL/fl_string.h>
 
 static Fl_Double_Window *print_panel=(Fl_Double_Window *)0;
 static Fl_Group *print_panel_controls=(Fl_Group *)0;
@@ -541,7 +542,7 @@ printing_style print_load() { // return whether SystemV or BSD printing style is
         }
         *qptr = '\0';
 
-        print_choice->add(qname, 0, 0, (void *)strdup(name), 0);
+        print_choice->add(qname, 0, 0, (void *)fl_strdup(name), 0);
       } else if (!strncmp(line, "system default destination: ", 28)) {
         if (sscanf(line + 28, "%s", defname) != 1) defname[0] = '\0';
       }
@@ -553,7 +554,7 @@ printing_style print_load() { // return whether SystemV or BSD printing style is
     while (fgets(line, sizeof(line),lpstat)) { // get names of all known printers
       if (*line == '#' || (p = strchr(line, '|')) == NULL) continue;
       *p = 0;
-      print_choice->add(line, 0, 0, (void *)strdup(line), 0);
+      print_choice->add(line, 0, 0, (void *)fl_strdup(line), 0);
       style = BSD;
       *p = '|';
       while (1) {
diff --git src/xutf8/utf8Wrap.c src/xutf8/utf8Wrap.c
index e26aef1..4a2bbc9 100644
--- src/xutf8/utf8Wrap.c
+++ src/xutf8/utf8Wrap.c
@@ -21,6 +21,7 @@
 
 #include "../Xutf8.h"
 #include <X11/Xlib.h>
+#include <FL/fl_string.h>  // fl_strdup()
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
@@ -215,7 +216,7 @@ find_best_font(Display  *dpy,
   list = XListFonts(dpy, *name, 1, &cnt);
   if (cnt && list) {
     free(*name);
-    *name = strdup(list[0]);
+    *name = fl_strdup(list[0]);
     s = XLoadQueryFont(dpy, *name);
     XFreeFontNames(list);
     return s;
diff --git test/menubar.cxx test/menubar.cxx
index 856aa72..43e4961 100644
--- test/menubar.cxx
+++ test/menubar.cxx
@@ -30,6 +30,7 @@
 #include <FL/fl_draw.H>
 #include <FL/Fl_Simple_Terminal.H>
 #include <FL/fl_ask.H>
+#include <FL/fl_string.h>
 
 #define TERMINAL_HEIGHT 120
 
@@ -225,7 +226,7 @@ int main(int argc, char **argv) {
   for (int i=0; i<99; i++) {
     char buf[100];
     sprintf(buf,"item %d",i);
-    hugemenu[i].text = strdup(buf);
+    hugemenu[i].text = fl_strdup(buf);
   }
   Fl_Double_Window window(WIDTH,400+TERMINAL_HEIGHT);
   G_tty = new Fl_Simple_Terminal(0,400,WIDTH,TERMINAL_HEIGHT);
diff --git test/unittests.cxx test/unittests.cxx
index 12b65fe..ca04aac 100644
--- test/unittests.cxx
+++ test/unittests.cxx
@@ -28,6 +28,7 @@
 #include <FL/Fl_Group.H>
 #include <FL/Fl_Box.H>
 #include <FL/fl_draw.H>         // fl_text_extents()
+#include <FL/fl_string.h>       // fl_strdup()
 
 // WINDOW/WIDGET SIZES
 #define MAINWIN_W       700                             // main window w()
@@ -53,7 +54,7 @@ public:
   UnitTest(const char *label, Fl_Widget* (*create)()) :
     fWidget(0L)
   {
-    fLabel = strdup(label);
+    fLabel = fl_strdup(label);
     fCreate = create;
     add(this);
   }
diff --git test/utf8.cxx test/utf8.cxx
index ed1dd10..9151264 100644
--- test/utf8.cxx
+++ test/utf8.cxx
@@ -28,6 +28,7 @@
 #include <FL/Fl_Output.H>
 #include <FL/fl_draw.H>
 #include <FL/fl_utf8.h>
+#include <FL/fl_string.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -620,10 +621,10 @@ int main(int argc, char** argv)
     sprintf(bu, "0x%06lX", y * 16);
     Fl_Input *b = new Fl_Input(200,(y-off)*25,80,25);
     b->textfont(FL_COURIER);
-    b->value(strdup(bu));
+    b->value(fl_strdup(bu));
     b = new Fl_Input(280,(y-off)*25,380,25);
     b->textfont(extra_font);
-    b->value(strdup(buf));
+    b->value(fl_strdup(buf));
   }
   scroll.end();
   main_win->resizable(scroll);
Direct Link to Message ]
 
     
Previous Message ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.