7495791f0d935716eb5a6231e11ba833ef327aed
angie
  Thu Apr 6 10:21:25 2017 -0700
Oops, forgot to implement maxOutRows for annoStreamTab!  Thx Chris Lee.  refs #12216

diff --git src/lib/annoStreamTab.c src/lib/annoStreamTab.c
index 0888834..02f9a9a 100644
--- src/lib/annoStreamTab.c
+++ src/lib/annoStreamTab.c
@@ -9,30 +9,32 @@
 #include "sqlNum.h"
 
 struct annoStreamTab
     {
     struct annoStreamer streamer;	// Parent class members & methods
     // Private members
     char *fileOrUrl;			// File name or URL
     struct lineFile *lf;		// file handle
     char **asWords;			// Most recent row's words
     int chromIx;			// Index of chrom-ish col in autoSql or bin-less table
     int startIx;			// Index of chromStart-ish col in autoSql or bin-less table
     int endIx;				// Index of chromEnd-ish col in autoSql or bin-less table
     int fileWordCount;			// Number of columns in file including bin
     boolean eof;			// Set when we have reached end of file.
     boolean omitBin;			// 1 if file has bin and autoSql doesn't have bin
+    boolean useMaxOutRows;		// TRUE if maxOutRows passed to annoStreamTabNew is > 0
+    int maxOutRows;			// Maximum number of rows we can output.
     };
 
 static struct lineFile *astLFOpen(char *fileOrUrl)
 /* Figure out if fileOrUrl is file or URL and open an lf accordingly. */
 {
 if (startsWith("http://", fileOrUrl) || startsWith("https://", fileOrUrl) ||
     startsWith("ftp://", fileOrUrl))
     return netLineFileOpen(fileOrUrl);
 else
     return lineFileOpen(fileOrUrl, TRUE);
 }
 
 static void unChop(char **words, int wordCount)
 /* Trust that words were chopped from a contiguous line and add back tabs for '\0's. */
 {
@@ -187,66 +189,76 @@
 {
 struct annoStreamTab *self = (struct annoStreamTab *)vSelf;
 char **words = nextRowUnfiltered(self, minChrom, minEnd);
 if (words == NULL)
     return NULL;
 // Skip past any left-join failures until we get a right-join failure, a passing row, or EOF.
 boolean rightFail = FALSE;
 while (annoFilterRowFails(vSelf->filters, words, vSelf->numCols, &rightFail))
     {
     if (rightFail)
 	break;
     words = nextRowUnfiltered(self, minChrom, minEnd);
     if (words == NULL)
 	return NULL;
     }
+if (self->useMaxOutRows)
+    {
+    self->maxOutRows--;
+    if (self->maxOutRows <= 0)
+        self->eof = TRUE;
+    }
 char *chrom = words[self->chromIx];
 uint chromStart = sqlUnsigned(words[self->startIx]);
 uint chromEnd = sqlUnsigned(words[self->endIx]);
 return annoRowFromStringArray(chrom, chromStart, chromEnd, rightFail, words, vSelf->numCols,
 			      callerLm);
 }
 
 static boolean astInitBed3Fields(struct annoStreamTab *self)
 /* Use autoSql to figure out which table fields correspond to {chrom, chromStart, chromEnd}. */
 {
 struct annoStreamer *vSelf = &(self->streamer);
 return annoStreamerFindBed3Columns(vSelf, &(self->chromIx), &(self->startIx), &(self->endIx),
 				   NULL, NULL, NULL);
 }
 
 static void astClose(struct annoStreamer **pVSelf)
 /* Close file and free self. */
 {
 if (pVSelf == NULL)
     return;
 struct annoStreamTab *self = *(struct annoStreamTab **)pVSelf;
 lineFileClose(&(self->lf));
 freeMem(self->asWords);
 freeMem(self->fileOrUrl);
 annoStreamerFree(pVSelf);
 }
 
 struct annoStreamer *annoStreamTabNew(char *fileOrUrl, struct annoAssembly *aa,
-				      struct asObject *asObj)
+				      struct asObject *asObj, int maxOutRows)
 /* Create an annoStreamer (subclass) object from a tab-separated text file/URL
- * whose columns are described by asObj (possibly excepting bin column at beginning). */
+ * whose columns are described by asObj (possibly excepting bin column at beginning).
+ * If maxOutRows is greater than 0 then it is an upper limit on the number of rows
+ * that the streamer will produce. */
 {
 struct lineFile *lf = astLFOpen(fileOrUrl);
 struct annoStreamTab *self = NULL;
 AllocVar(self);
 struct annoStreamer *streamer = &(self->streamer);
 annoStreamerInit(streamer, aa, asObj, fileOrUrl);
 streamer->rowType = arWords;
 streamer->setRegion = astSetRegion;
 streamer->nextRow = astNextRow;
 streamer->close = astClose;
 AllocArray(self->asWords, streamer->numCols);
 self->lf = lf;
 self->eof = FALSE;
 self->fileOrUrl = cloneString(fileOrUrl);
+self->maxOutRows = maxOutRows;
+self->useMaxOutRows = (maxOutRows > 0);
 if (!astInitBed3Fields(self))
     errAbort("annoStreamTabNew: can't figure out which fields of %s to use as "
 	     "{chrom, chromStart, chromEnd}.", fileOrUrl);
 return (struct annoStreamer *)self;
 
 }