7b4bb371da6813455b4b5a53906d5cd59457240b tdreszer Fri Aug 3 16:40:44 2012 -0700 By redefining printf, puts and putc in the header file and including that header in select c files, hgTrackUi can decide to add a box around the cfg dialog after it is written. This is useful since it is not clear whether a cfg will be written until it is tried. Openning the box beforehand can leave an empty box. This minor check-in does not include changes to any cgis, only the ability to do so. diff --git src/lib/dsPrint.c src/lib/dsPrint.c index 05d51fe..33ebcc6 100644 --- src/lib/dsPrint.c +++ src/lib/dsPrint.c @@ -1,328 +1,328 @@ // dsPrint - Dynamic string Stack based Printing. // // This module relies upon a dyString based stack of buffers which accumulate output // for later printing. As a stack, only the top buffer can be filled and flushed out // (dsPrintFlush). When flushing, the top buffer's content is appended to the next // lower buffer, unless explicitly requested otherwise (dsPrintDirectly). // If the stack is empty, dsPrintf will be equivalent to printf. // // Output goes to STDOUT unless a single alternative out file is registered. #include "common.h" #include "dsPrint.h" // The stack of dyString buffers is only accessible locally static struct dyString *dsStack = NULL; #define dsAssertToken(token) assert((int)(long long)dsStack == token) // This module defaults to STDOUT but an alternative can be registered static FILE *dsOut = NULL; #define dsInitializeOut() {if (dsOut == NULL) dsOut = stdout;} #define dsAssertUnregisteredOut() assert(dsOut == stdout || dsOut == NULL) #define dsAssertRegisteredOut(out) assert(dsOut == out) int dsPrintOpen(int initialBufSize) // Allocate dynamic string and puts at top of stack // returns token to be used for later stack accounting asserts { if (initialBufSize <= 0) initialBufSize = 2048; // presume large struct dyString *ds = dyStringNew(initialBufSize); slAddHead(&dsStack,ds); return (int)(long long)ds; } int dsPrintf(char *format, ...) // Prints into end of the top ds buffer, and return resulting string length // If there is no current buffer, this acts like a simple printf and returns -1 { int len = -1; // caller could assert returned length > 0 to ensure dsPrint is open! va_list args; va_start(args, format); if (dsStack != NULL) { dyStringVaPrintf(dsStack, format, args); len = dyStringLen(dsStack); } else { dsInitializeOut() vfprintf(dsOut,format, args); } va_end(args); return len; } int dsPrintDirectly(int token,FILE *file) // Prints the contents of the top buffer directly to a file. // Will leave the filled buffer at top of stack // Returns the length printed. { dsAssertToken(token); int len = dyStringLen(dsStack); if (len != 0) fprintf(file,"%s",dyStringContents(dsStack)); fflush(file); return len; } int dsPrintFlush(int token) // Flushes the top buffer to the next lower one and empties top buffer. // If there is no lower buffer then the content is printed to STDOUT (or registered out). // Returns the length flushed. { dsAssertToken(token); int len = dyStringLen(dsStack); if (len != 0) { if (dsStack->next == NULL) { dsInitializeOut(); fprintf(dsOut,"%s",dyStringContents(dsStack)); fflush(dsOut); } else dyStringAppend(dsStack->next,dyStringContents(dsStack)); dyStringClear(dsStack); } return len; } int dsPrintClose(int token) // Abandons the top buffer and its content, freeing memory. // Returns the length abandoned. { dsAssertToken(token); int len = dyStringLen(dsStack); struct dyString *ds = slPopHead(&dsStack); dyStringFree(&ds); return len; } int dsPrintFlushAndClose(int token) // Flushes the top buffer to the next lower one and frees the top buffer. // If there is no lower buffer then the content is printed to STDOUT (or registered out). // Returns the length flushed. { int len = dsPrintFlush(token); dsPrintClose(token); return len; } char * dsPrintContent(int token) // returns the content of the current buffer as a string, but does not flush or free it // NOTE: returned pointer is not cloned memory and will be changed by successive dsPrint calls { dsAssertToken(token); return dyStringContents(dsStack); } int dsPrintEmpty(int token) // Empties the top buffer in stack (abandoning content), but leave buffer in place // Returns the length abandoned. { dsAssertToken(token); int len = dyStringLen(dsStack); dyStringClear(dsStack); return len; } static int dsPrintStackIxFromToken(int token) // Return the stack member corresponding to the token. // This ix can be used to walk up the stack from a given point { struct dyString *ds = dsStack; int ix = 0; for (; ds != NULL; ds = ds->next, ++ix) { if ((int)(long long)ds == token) return ix; } return -1; } static struct dyString *dsPrintStackMemberFromIx(int ix) // Return the stack member corresponding to the ix. // By walking stack ix's, you can walk up or down the stack { if (ix < 0) return NULL; return slElementFromIx(dsStack,ix); } int dsPrintSize(int token) // Returns the curent length of the buffer starting at the level corresponding to token. // Unlike other cases, the token does not have to correspond to the top of the stack! { //dsAssertToken(token); //return dyStringLen(dsStack); int ix = dsPrintStackIxFromToken(token); assert(ix >= 0); int len = 0; struct dyString *ds = NULL; for (;ix>0;ix--) { ds = dsPrintStackMemberFromIx(ix); assert(ds != NULL); len += dyStringLen(ds); } len += dyStringLen(dsStack); return len; } int dsPrintStackDepth() // Returns the current dsPrint buffer stack depth { return slCount(dsStack); } void dsPrintRegisterOut(FILE *out) // Registers an alternative to STDOUT. After registering, all dsPrint out goes to this file. // NOTE: There is no stack. Register/Unregister serially. { dsAssertUnregisteredOut(); dsOut = out; } void dsPrintUnregisterOut(FILE *out) // Unregisters the alternative to STDOUT. After unregistering all dsPrint out goes to STDOUT. // NOTE: There is no stack. Register/Unregister serially. { dsAssertRegisteredOut(out); dsOut = stdout; } int dsPrintSizeAll() // returns combined current size of all buffers { int len = 0; if (dsStack != NULL) { struct dyString *ds = dsStack; for (;ds != NULL; ds = ds->next) len += dyStringLen(ds); } return len; } int dsPrintFlushAndCloseAll() // flushes, frees and closes all stacked buffers // returns length flushed { int len = 0; if (dsStack != NULL) { while (dsStack != NULL) { int token = (int)(long long)dsStack; len = dsPrintFlushAndClose(token); // Only the last length is needed! } } return len; } char *dsPrintCannibalizeAndClose(int token) // Closes the top stack buffer returning content. Returned string should be freed. { dsAssertToken(token); struct dyString *ds = slPopHead(&dsStack); return dyStringCannibalize(&ds); } char *dsPrintCannibalizeAndCloseAll() // Closes all stack buffers and returns a single string that is the full content. // Returned string should be freed. { while (dsStack != NULL && dsStack->next != NULL) { int token = (int)(long long)dsStack; dsPrintFlushAndClose(token); // Flushes each to the next lower buffer } if (dsStack == NULL) return NULL; else return dyStringCannibalize(&dsStack); } /* void dsPrintTest() // Tests of dsPrint functions { printf("Plain printf\n"); dsPrintf("1 dsPrintf unopened\n"); int token1 = dsPrintOpen(0); dsPrintf("2 dsOpen:1\n"); dsPrintFlush(token1); dsPrintf("3^10 1:%d after flush\n",dsPrintStackDepth()); int token2 = dsPrintOpen(256); dsPrintf("4 dsOpen:2 len1:%d len2:%d lenAll:%d\n", dsPrintSize(token1),dsPrintSize(token2),dsPrintSizeAll()); dsPrintRegisterOut(stderr); dsPrintFlush(token2); dsPrintUnregisterOut(stderr); dsPrintf("5 2:%d After flush len1:%d len2:%d lenAll:%d\n", dsPrintStackDepth(),dsPrintSize(token1),dsPrintSize(token2),dsPrintSizeAll()); dsPrintFlushAndClose(token2); dsPrintf("6 1:%d After flushAndClose:2 len1:%d\n",dsPrintStackDepth(),dsPrintSize(token1)); token2 = dsPrintOpen(256); dsPrintf("7 dsOpen:2 reopen:2 WILL ABANDON CONTENT\n"); char *content = cloneString(dsPrintContent(token2)); dsPrintAbandonContent(token2); dsPrintf("8x7 2:%d len1:%d len2:%d lenAll:%d isEmpty2:%s\n", dsPrintStackDepth(),dsPrintSize(token1),dsPrintSize(token2),dsPrintSizeAll(), (dsPrintIsEmpty(token2) ? "EMPTY":"NOT_EMPTY")); strSwapChar(content,'\n','~'); // Replace newline before printing. dsPrintf("9 2:%d No flush yet len1:%d len2:%d lenAll:%d prev7:[%s]\n", dsPrintStackDepth(),dsPrintSize(token1),dsPrintSize(token2),dsPrintSizeAll(),content); freez(&content); int token3 = dsPrintOpen(256); -dsPrintPuts("10 Open:3 Line doubled and out of turn due to dsPrintDirectly()"); +dsPuts("10 Open:3 Line doubled and out of turn due to dsPrintDirectly()"); dsPrintDirectly(token3,stdout); dsPrintf("11 3:%d Just prior to closing all. len1:%d len2:%d len3:%d lenAll:%d", dsPrintStackDepth(), dsPrintSize(token1),dsPrintSize(token2),dsPrintSize(token3),dsPrintSizeAll()); int token4 = dsPrintOpen(256); dsPrintf("12 Open:4 Opened stack:%d WILL ABANDON\n",dsPrintStackDepth()); dsPrintAbandon(token4); -dsPrintPutc('\n'); -dsPrintPuts("13 Puts: Added last '\\n' with dsPrintPutc(), this with dsPrintPuts()."); +dsPutc('\n'); +dsPuts("13 Puts: Added last '\\n' with dsPutc(), this with dsPuts()."); dsPrintf("14 3:%d Last line! Expect 7 & 12 missing, 10 dupped. lenAll:%d Bye.\n", dsPrintStackDepth(),dsPrintSizeAll()); dsPrintFlushAndCloseAll(); assert(dsStack == NULL); int ix = 0; for (;ix<20;ix++) // tested to 1000 { dsPrintOpen(32); // Don't even care about tokens! if (ix == 0) dsPrintf("CannibalizeAndCloseAll():"); dsPrintf(" %d",dsPrintStackDepth()); } content = dsPrintCannibalizeAndCloseAll(); printf("\n[%s]\n",content); freez(&content); } */