diff --git a/doc/src/dump_modify.txt b/doc/src/dump_modify.txt
index 6de6de545e720d518316ea9d31c82fb825fd8c9c..3230507dc3eaebc8bce634acf6a7ac2e3c2c7707 100644
--- a/doc/src/dump_modify.txt
+++ b/doc/src/dump_modify.txt
@@ -15,7 +15,7 @@ dump_modify dump-ID keyword values ... :pre
 dump-ID = ID of dump to modify :ulb,l
 one or more keyword/value pairs may be appended :l
 these keywords apply to various dump styles :l
-keyword = {append} or {at} or {buffer} or {delay} or {element} or {every} or {fileper} or {first} or {flush} or {format} or {image} or {label} or {nfile} or {pad} or {precision} or {region} or {scale} or {sort} or {thresh} or {unwrap} :l
+keyword = {append} or {at} or {buffer} or {delay} or {element} or {every} or {fileper} or {first} or {flush} or {format} or {image} or {label} or {maxfiles} or {nfile} or {pad} or {precision} or {region} or {scale} or {sort} or {thresh} or {unwrap} :l
   {append} arg = {yes} or {no}
   {at} arg = N
     N = index of frame written upon first dump
@@ -37,6 +37,8 @@ keyword = {append} or {at} or {buffer} or {delay} or {element} or {every} or {fi
   {image} arg = {yes} or {no}
   {label} arg = string
     string = character string (e.g. BONDS) to use in header of dump local file
+  {maxfiles} arg = Fmax
+    Fmax = keep only the most recent {Fmax} snapshots (one snapshot per file)
   {nfile} arg = Nf
     Nf = write this many files, one from each of Nf processors
   {pad} arg = Nchar = # of characters to convert timestep to
@@ -364,6 +366,20 @@ e.g. BONDS or ANGLES.
 
 :line
 
+The {maxfiles} keyword can only be used when a '*' wildcard is
+included in the dump file name, i.e. when writing a new file(s) for
+each snapshot.  The specified {Fmax} is how many snapshots will be
+kept.  Once this number is reached, the file(s) containing the oldest
+snapshot is deleted before a new dump file is written.  If the
+specified {Fmax} <= 0, then all files are retained.
+
+This can be useful for debugging, especially if you don't know on what
+timestep something bad will happen, e.g. when LAMMPS will exit with an
+error.  You can dump every timestep, and limit the number of dump
+files produced, even if you run for 1000s of steps.
+
+:line
+
 The {nfile} or {fileper} keywords can be used in conjunction with the
 "%" wildcard character in the specified dump file name, for all dump
 styles except the {dcd}, {image}, {movie}, {xtc}, and {xyz} styles
@@ -901,6 +917,7 @@ flush = yes
 format = %d and %g for each integer or floating point value
 image = no
 label = ENTRIES
+maxifiles = -1
 nfile = 1
 pad = 0
 pbc = no
diff --git a/lib/atc/Function.cpp b/lib/atc/Function.cpp
index fb615e7befa05a59f7723f844e56e893a37818b9..6004937a018ffe58fcc6f4c0ace6cf916b881f83 100644
--- a/lib/atc/Function.cpp
+++ b/lib/atc/Function.cpp
@@ -1,4 +1,6 @@
+#ifndef _WIN32
 #include <alloca.h>
+#endif
 #include "Function.h"
 #include "ATC_Error.h"
 #include "LammpsInterface.h"
@@ -59,7 +61,11 @@ namespace ATC {
   {
     string type = args[0];
     int narg = nargs -1;
+#ifdef _WIN32
+    double *dargs = (double *) _alloca(sizeof(double) * narg);
+#endif
     double *dargs = (double *) alloca(sizeof(double) * narg);
+#endif
     for (int i = 0; i < narg; ++i) dargs[i] = atof(args[i+1]);
   
     return function(type, narg, dargs);
@@ -193,7 +199,11 @@ XT_Function_Mgr * XT_Function_Mgr::myInstance_ = NULL;
   {
     string type = args[0];
     int narg = nargs -1;
+#ifdef _WIN32
+    double *dargs = (double *) _alloca(sizeof(double) * narg);
+#else
     double *dargs = (double *) alloca(sizeof(double) * narg);
+#endif
     for (int i = 0; i < narg; ++i) dargs[i] = atof(args[i+1]);
   
     return function(type, narg, dargs);
diff --git a/src/COMPRESS/dump_atom_gz.cpp b/src/COMPRESS/dump_atom_gz.cpp
index fb605b74cee56bae62e53ab4f0251f7e612d3aa1..ef7e6583be5e28d1af258aa636fa6c509816bc47 100644
--- a/src/COMPRESS/dump_atom_gz.cpp
+++ b/src/COMPRESS/dump_atom_gz.cpp
@@ -71,6 +71,19 @@ void DumpAtomGZ::openfile()
       sprintf(filecurrent,pad,filestar,update->ntimestep,ptr+1);
     }
     *ptr = '*';
+    if (maxfiles > 0) {
+      if (numfiles < maxfiles) {
+        nameslist[numfiles] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[numfiles],filecurrent);
+        ++numfiles;
+      } else {
+        remove(nameslist[fileidx]);
+        delete[] nameslist[fileidx];
+        nameslist[fileidx] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[fileidx],filecurrent);
+        fileidx = (fileidx + 1) % maxfiles;
+      }
+    }
   }
 
   // each proc with filewriter = 1 opens a file
diff --git a/src/COMPRESS/dump_cfg_gz.cpp b/src/COMPRESS/dump_cfg_gz.cpp
index a1ffa92ec859958c616a310c7705c088f35114c0..aaeb878584b0cca77110b1a7bbef58d8de6f6cab 100644
--- a/src/COMPRESS/dump_cfg_gz.cpp
+++ b/src/COMPRESS/dump_cfg_gz.cpp
@@ -75,6 +75,19 @@ void DumpCFGGZ::openfile()
       sprintf(filecurrent,pad,filestar,update->ntimestep,ptr+1);
     }
     *ptr = '*';
+    if (maxfiles > 0) {
+      if (numfiles < maxfiles) {
+        nameslist[numfiles] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[numfiles],filecurrent);
+        ++numfiles;
+      } else {
+        remove(nameslist[fileidx]);
+        delete[] nameslist[fileidx];
+        nameslist[fileidx] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[fileidx],filecurrent);
+        fileidx = (fileidx + 1) % maxfiles;
+      }
+    }
   }
 
   // each proc with filewriter = 1 opens a file
diff --git a/src/COMPRESS/dump_custom_gz.cpp b/src/COMPRESS/dump_custom_gz.cpp
index 52d67445be0ca940fdafc3b08ef8ba9bb93c51ab..9c30f4742f92de2dcf92c2c4c2e22f28b9c1ca02 100644
--- a/src/COMPRESS/dump_custom_gz.cpp
+++ b/src/COMPRESS/dump_custom_gz.cpp
@@ -73,6 +73,19 @@ void DumpCustomGZ::openfile()
       sprintf(filecurrent,pad,filestar,update->ntimestep,ptr+1);
     }
     *ptr = '*';
+    if (maxfiles > 0) {
+      if (numfiles < maxfiles) {
+        nameslist[numfiles] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[numfiles],filecurrent);
+        ++numfiles;
+      } else {
+        remove(nameslist[fileidx]);
+        delete[] nameslist[fileidx];
+        nameslist[fileidx] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[fileidx],filecurrent);
+        fileidx = (fileidx + 1) % maxfiles;
+      }
+    }
   }
 
   // each proc with filewriter = 1 opens a file
diff --git a/src/COMPRESS/dump_xyz_gz.cpp b/src/COMPRESS/dump_xyz_gz.cpp
index 047ad8652f9587bdba8d306be030a357711ccc78..7be1a10fe2b15b19daa5f3b93d0659d75959922f 100644
--- a/src/COMPRESS/dump_xyz_gz.cpp
+++ b/src/COMPRESS/dump_xyz_gz.cpp
@@ -73,6 +73,19 @@ void DumpXYZGZ::openfile()
       sprintf(filecurrent,pad,filestar,update->ntimestep,ptr+1);
     }
     *ptr = '*';
+    if (maxfiles > 0) {
+      if (numfiles < maxfiles) {
+        nameslist[numfiles] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[numfiles],filecurrent);
+        ++numfiles;
+      } else {
+        remove(nameslist[fileidx]);
+        delete[] nameslist[fileidx];
+        nameslist[fileidx] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[fileidx],filecurrent);
+        fileidx = (fileidx + 1) % maxfiles;
+      }
+    }
   }
 
   // each proc with filewriter = 1 opens a file
diff --git a/src/MPIIO/dump_atom_mpiio.cpp b/src/MPIIO/dump_atom_mpiio.cpp
index 4422ef1cdfb5c16df75cdd8ff745d67a212d889d..f2f299144261d9d6035e49db8e1f30dedeea38ac 100644
--- a/src/MPIIO/dump_atom_mpiio.cpp
+++ b/src/MPIIO/dump_atom_mpiio.cpp
@@ -77,6 +77,19 @@ void DumpAtomMPIIO::openfile()
       sprintf(filecurrent,pad,filestar,update->ntimestep,ptr+1);
     }
     *ptr = '*';
+    if (maxfiles > 0) {
+      if (numfiles < maxfiles) {
+        nameslist[numfiles] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[numfiles],filecurrent);
+        ++numfiles;
+      } else {
+        remove(nameslist[fileidx]);
+        delete[] nameslist[fileidx];
+        nameslist[fileidx] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[fileidx],filecurrent);
+        fileidx = (fileidx + 1) % maxfiles;
+      }
+    }
   }
 
   if (append_flag) { // append open
diff --git a/src/MPIIO/dump_cfg_mpiio.cpp b/src/MPIIO/dump_cfg_mpiio.cpp
index a367a25525d2876fac9a0736cce212e5c8bd524a..c580d2e7af71cdb1b7ca037392e0e0656b6ac5b0 100644
--- a/src/MPIIO/dump_cfg_mpiio.cpp
+++ b/src/MPIIO/dump_cfg_mpiio.cpp
@@ -94,6 +94,19 @@ void DumpCFGMPIIO::openfile()
       sprintf(filecurrent,pad,filestar,update->ntimestep,ptr+1);
     }
     *ptr = '*';
+    if (maxfiles > 0) {
+      if (numfiles < maxfiles) {
+        nameslist[numfiles] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[numfiles],filecurrent);
+        ++numfiles;
+      } else {
+        remove(nameslist[fileidx]);
+        delete[] nameslist[fileidx];
+        nameslist[fileidx] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[fileidx],filecurrent);
+        fileidx = (fileidx + 1) % maxfiles;
+      }
+    }
   }
 
   if (append_flag) { // append open
diff --git a/src/MPIIO/dump_custom_mpiio.cpp b/src/MPIIO/dump_custom_mpiio.cpp
index 1ef2c0a9d08e09bb209b8e739bb28f7137cd6bc7..3650ca994e4d519d319ae0d182cb9b2011afd764 100644
--- a/src/MPIIO/dump_custom_mpiio.cpp
+++ b/src/MPIIO/dump_custom_mpiio.cpp
@@ -97,6 +97,19 @@ void DumpCustomMPIIO::openfile()
       sprintf(filecurrent,pad,filestar,update->ntimestep,ptr+1);
     }
     *ptr = '*';
+    if (maxfiles > 0) {
+      if (numfiles < maxfiles) {
+        nameslist[numfiles] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[numfiles],filecurrent);
+        ++numfiles;
+      } else {
+        remove(nameslist[fileidx]);
+        delete[] nameslist[fileidx];
+        nameslist[fileidx] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[fileidx],filecurrent);
+        fileidx = (fileidx + 1) % maxfiles;
+      }
+    }
   }
 
   if (append_flag) { // append open
diff --git a/src/MPIIO/dump_xyz_mpiio.cpp b/src/MPIIO/dump_xyz_mpiio.cpp
index 267f4fa900e3a48aa24f32118044dc2904bc13a6..f15d340cd14f3f470ac981e80d29c7428c2f6e09 100644
--- a/src/MPIIO/dump_xyz_mpiio.cpp
+++ b/src/MPIIO/dump_xyz_mpiio.cpp
@@ -97,6 +97,19 @@ void DumpXYZMPIIO::openfile()
       sprintf(filecurrent,pad,filestar,update->ntimestep,ptr+1);
     }
     *ptr = '*';
+    if (maxfiles > 0) {
+      if (numfiles < maxfiles) {
+        nameslist[numfiles] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[numfiles],filecurrent);
+        ++numfiles;
+      } else {
+        remove(nameslist[fileidx]);
+        delete[] nameslist[fileidx];
+        nameslist[fileidx] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[fileidx],filecurrent);
+        fileidx = (fileidx + 1) % maxfiles;
+      }
+    }
   }
 
   if (append_flag) { // append open
diff --git a/src/dump.cpp b/src/dump.cpp
index 46e556600a8473ffa80feca8bc90a28e08a788f1..7c171015bb4e201f8a8602294ad53c2c9937fbf6 100644
--- a/src/dump.cpp
+++ b/src/dump.cpp
@@ -91,6 +91,11 @@ Dump::Dump(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp)
   pbcflag = 0;
   delay_flag = 0;
 
+  maxfiles = -1;
+  numfiles = 0;
+  fileidx = 0;
+  nameslist = NULL;
+
   maxbuf = maxids = maxsort = maxproc = 0;
   buf = bufsort = NULL;
   ids = idsort = NULL;
@@ -187,6 +192,14 @@ Dump::~Dump()
 
   if (multiproc) MPI_Comm_free(&clustercomm);
 
+  // delete storage for caching file names
+
+  if (maxfiles > 0) {
+    for (int idx=0; idx < numfiles; ++idx)
+      delete[] nameslist[idx];
+    delete[] nameslist;
+  }
+
   // XTC style sets fp to NULL since it closes file in its destructor
 
   if (multifile == 0 && fp != NULL) {
@@ -549,6 +562,19 @@ void Dump::openfile()
       sprintf(filecurrent,pad,filestar,update->ntimestep,ptr+1);
     }
     *ptr = '*';
+    if (maxfiles > 0) {
+      if (numfiles < maxfiles) {
+        nameslist[numfiles] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[numfiles],filecurrent);
+        ++numfiles;
+      } else {
+        remove(nameslist[fileidx]);
+        delete[] nameslist[fileidx];
+        nameslist[fileidx] = new char[strlen(filecurrent)+1];
+        strcpy(nameslist[fileidx],filecurrent);
+        fileidx = (fileidx + 1) % maxfiles;
+      }
+    }
   }
 
   // each proc with filewriter = 1 opens a file
@@ -1003,6 +1029,27 @@ void Dump::modify_params(int narg, char **arg)
         iarg += n;
       }
 
+    } else if (strcmp(arg[iarg],"maxfiles") == 0) {
+      if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
+      if (!multifile)
+        error->all(FLERR,"Cannot use dump_modify maxfiles "
+                   "without * in dump file name");
+      // wipe out existing storage
+      if (maxfiles > 0) {
+        for (int idx=0; idx < numfiles; ++idx)
+          delete[] nameslist[idx];
+        delete[] nameslist;
+      }
+      maxfiles = force->inumeric(FLERR,arg[iarg+1]);
+      if (maxfiles == 0) error->all(FLERR,"Illegal dump_modify command");
+      if (maxfiles > 0) {
+        nameslist = new char*[maxfiles];
+        numfiles = 0;
+        for (int idx=0; idx < maxfiles; ++idx)
+          nameslist[idx] = NULL;
+        fileidx = 0;
+      }
+      iarg += 2;
     } else if (strcmp(arg[iarg],"nfile") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
       if (!multiproc)
diff --git a/src/dump.h b/src/dump.h
index cb4b71e45d65420d94b8d995aae7d38f8fcc9587..1c6a131f76088e060cf5cb697e7ef744d660d95e 100644
--- a/src/dump.h
+++ b/src/dump.h
@@ -106,6 +106,11 @@ class Dump : protected Pointers {
   double boxzlo,boxzhi;
   double boxxy,boxxz,boxyz;
 
+  int maxfiles;              // max number of files created, -1 == infinite
+  int numfiles;              // number of files in names list
+  int fileidx;               // index of file in names list
+  char **nameslist;          // list of history file names
+
   bigint ntotal;             // total # of per-atom lines in snapshot
   int reorderflag;           // 1 if OK to reorder instead of sort
   int ntotal_reorder;        // # of atoms that must be in snapshot
diff --git a/src/dump_custom.cpp b/src/dump_custom.cpp
index f2ec7f36dca3bf6035e110e92d0bfb69aa4cbffa..40d74a1d746837209696e13f6aecfd9ea6deaf54 100644
--- a/src/dump_custom.cpp
+++ b/src/dump_custom.cpp
@@ -59,7 +59,7 @@ DumpCustom::DumpCustom(LAMMPS *lmp, int narg, char **arg) :
   earg(NULL), vtype(NULL), vformat(NULL), columns(NULL), choose(NULL),
   dchoose(NULL), clist(NULL), field2index(NULL), argindex(NULL), id_compute(NULL),
   compute(NULL), id_fix(NULL), fix(NULL), id_variable(NULL), variable(NULL),
-  vbuf(NULL), id_custom(NULL), flag_custom(NULL), typenames(NULL), 
+  vbuf(NULL), id_custom(NULL), flag_custom(NULL), typenames(NULL),
   pack_choice(NULL)
 {
   if (narg == 5) error->all(FLERR,"No dump custom arguments specified");
@@ -1675,7 +1675,7 @@ int DumpCustom::modify_param(int narg, char **arg)
 
   if (strcmp(arg[0],"refresh") == 0) {
     if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
-    if (strncmp(arg[1],"c_",2) != 0) 
+    if (strncmp(arg[1],"c_",2) != 0)
       error->all(FLERR,"Illegal dump_modify command");
     if (refreshflag) error->all(FLERR,"Dump modify can only have one refresh");