home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / suntar1.cpt / printf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-13  |  9.6 KB  |  401 lines

  1. /*******************************************************************************\
  2.  
  3. printf module
  4.  
  5. part of suntar, ⌐1991 Sauro & Gabriele Speranza
  6.  
  7. This program is public domain, feel free to use it or part of it for anything
  8.  
  9. \*******************************************************************************/
  10.  
  11. /* it's a not 100% standard version of printf: it does not support field
  12. length (%5d is NOT allowed) and has a new descriptor %p for Pascal strings
  13.  
  14. I found no interest in supporting windows other then window 0, but
  15. if you place the buffer and some flags in the window struct it would be
  16. easy to adapt it to write to any window
  17. */
  18.  
  19. #include "windows.h"
  20. #include "suntar.h"
  21.  
  22. static Boolean first_time=true;
  23. static Boolean no_flush = false;
  24. static char last_char=CR;
  25.  
  26. void my_flush(void);
  27. void printdec(long);
  28. void print_oct(long);
  29. void printhex(long,Boolean);
  30.  
  31.  
  32. void disable_autoflush()
  33. {
  34. /* the printf routine updates the screen, adjusts the scroll bars and
  35. scrolls the window so that the cursor is in sight, but
  36. a) that takes a lot of time
  37. b) if the printed lines are larger than the window, that may yield a lot of 
  38.     silly horizontal scrolling
  39. Hence, in the most critical sections of suntar updates are delayed and 
  40. scrolls are disabled.
  41. */
  42. if(first_time){
  43.     GrafPtr savePort;
  44.     GetPort( &savePort );
  45.     last_char=CR;
  46.     new_window();
  47.     first_time=false;
  48.     SetPort( &my_windows[0] );
  49.     TEAutoView (true,my_windows[0].TEH);
  50.     SetPort( savePort );
  51.     }
  52. no_flush=true;
  53. }
  54.  
  55. void enable_autoflush()
  56. {
  57.     GrafPtr savePort;
  58.     GetPort( &savePort );
  59.     SetPort( &my_windows[0] );
  60.     my_flush();
  61.  
  62.     if( last_char==CR||last_char==LF){
  63.         update_console();
  64.  
  65.         TESelView( my_windows[0].TEH);
  66.         }
  67.     if(curr_window==&my_windows[0]){
  68.         SCR_BAR_AND_TEXT_IN_SYNC
  69.         }
  70. /* else 
  71.     per ora la scrollbar Å comunque bianca, non importa aggiornarla, poi ci pensa 
  72.     MainEvent al momento dell'evento di attivazione
  73.     -- the scrollbar is currently white, it will be updated by MainEvent at the
  74.     activate event */
  75.  
  76.     SetPort( savePort );
  77.     no_flush=false;
  78. }
  79.  
  80.  
  81. #ifndef SUNTAR
  82. /* suntar does not use it, preferring the more powerful prompt(), but it was
  83. tested and debugged, so you may use it if you need it: it's a full implementation
  84. ot the standard gets function, allowing all Mac-style editing tools on the
  85. line which is being typed */
  86. char * gets(buf)
  87. char*buf;
  88. {
  89. short io_start;
  90.  
  91. /* The window was read-only: now, it' broken in two parts, the bottom
  92. becomes read/write, but any existing text, up to the prompt which
  93. probably you printf-ed just before calling gets, remains read-only;
  94. furthermore, the read-only portion is one line (even Paste is altered
  95. so that you can't paste a newline character) */
  96. io_start=my_windows[0].lastPrompt=(**my_windows[0].TEH).selEnd;
  97.  
  98. /* wait until the user types a return or enter */
  99. do{
  100.     MainEvent();
  101.     }
  102. while(my_windows[0].lastPrompt!=32767);
  103. /* set the window as read-only again, and copy what appears after the prompt 
  104. in the output string */
  105. {register char *p= buf;
  106. register char *q= *((**my_windows[0].TEH).hText) +io_start;
  107. register int i=(**my_windows[0].TEH).teLength-io_start;
  108. while(i--)
  109.     *p++=*q++;
  110. *--p='\0';    /* il '\n' non va ritornato... */
  111. }
  112. return buf;LF
  113. }
  114. #endif
  115.  
  116. void start_of_line()
  117. {
  118. /* guarantees that the last character in the window is a carriage return */
  119. if(last_char!=CR&&last_char!=LF)
  120.     put_char(CR);
  121. }
  122.  
  123. void one_empty_line()
  124. /* guarantees that the last two characters in the window are carriage returns */
  125. {
  126. if(last_char!=CR){
  127.     put_char(CR);
  128.     if(last_char!=CR)        /* could be LF now... */
  129.         put_char(CR);
  130.     }
  131. }
  132.  
  133.  
  134. void prompt(buf,nbytes)
  135. /* come gets, ma ha un controllo di overflow e un valore iniziale
  136. -- similar to gets, but it has a buffer size parameter and the
  137. text input line has an initial value, which is selected so that one
  138. may delete it by typing any character
  139.  */
  140. char*buf;
  141. {
  142. short io_start;
  143. GrafPtr savePort;
  144.  
  145. io_start=(**my_windows[0].TEH).selEnd;
  146. if(buf[0]) printf("%s ",buf);    /* the space seems superfluous, but without it the whole
  147.             line appears selected, and that's not very pretty to be seen */
  148. GetPort( &savePort );
  149. SetPort(&my_windows[0]);
  150. TESetSelect((long)io_start,(**my_windows[0].TEH).selEnd-(buf[0]!=0),my_windows[0].TEH);
  151. update_console();
  152. TESelView( my_windows[0].TEH);
  153. SetPort(savePort);
  154. if(curr_window != &my_windows[0])    /* potrebbe esserci un desk accessory */
  155.     SelectWindow(&my_windows[0]);
  156.  
  157. my_windows[0].lastPrompt=io_start;
  158.  
  159. do{
  160.     MainEvent();
  161.     if(is_abort_command()){
  162.         GetPort( &savePort );
  163.         SetPort(&my_windows[0]);
  164.         TESetSelect((long)io_start,(long)32767,my_windows[0].TEH);
  165.         TEDelete(TEH);
  166.         my_windows[0].lastPrompt=32767;        /* rimettilo readonly */
  167.         SetPort(savePort);
  168.         accept_abort_command();
  169.         }
  170.     }
  171. while(my_windows[0].lastPrompt!=32767);
  172.  
  173. {register char *p= buf;
  174. register char *q= *((**my_windows[0].TEH).hText) +io_start;
  175. register int i=(**my_windows[0].TEH).teLength-io_start;
  176. if(i>nbytes) i=nbytes;
  177. while(i--)
  178.     *p++=*q++;
  179. *--p='\0';    /* il '\n' non va ritornato... */
  180. }
  181. }
  182.  
  183. #include <varargs.h>
  184.  
  185. void printf(fmt,va_alist)
  186. char*fmt;
  187. va_dcl
  188. {
  189. va_list ap;
  190. register char*format=fmt;
  191. long val;
  192. register char*string;
  193. int longform;
  194.  
  195.  
  196.     if(!no_flush){
  197.         if(first_time){
  198.             GrafPtr savePort;
  199.             GetPort( &savePort );
  200.             last_char=CR;
  201.             new_window();
  202.             first_time=false;
  203.             SetPort( &my_windows[0] );
  204.             TEAutoView (true,my_windows[0].TEH);
  205.             SetPort( savePort );
  206.             }
  207.         }
  208.  
  209.     va_start(ap);
  210.     while(*format!='\0'){
  211.         if(*format!='%')
  212.             put_char(*format);
  213.         else{
  214.             format++;
  215.             if(longform = *format=='l')
  216.                 format++;
  217.             switch(*format){
  218.             case '%':
  219.                 put_char('%');
  220.                 break;
  221.             case 'D':
  222.                 longform=1; /* e prosegui...*/
  223.             case 'd':
  224.                 if(!longform)
  225.                     val= (long) va_arg(ap,int);
  226.                 else
  227.                     val= va_arg(ap,long);
  228.                 printdec(val);
  229.                 break;
  230.             case 'u':
  231.                 val= (long) va_arg(ap,unsigned int);    /* never used %lu... */
  232.                 printdec(val);
  233.                 break;
  234.             case 'X':
  235.                 longform=1; /* e prosegui...*/
  236.             case 'x':
  237.                 if(!longform)
  238.                     val= (long) va_arg(ap,int);
  239.                 else
  240.                     val= va_arg(ap,long);
  241.                 printhex(val,longform);
  242.                 break;
  243.             case 'o':
  244.                 if(!longform)
  245.                     val= (long) va_arg(ap,int);
  246.                 else
  247.                     val= va_arg(ap,long);
  248.                 print_oct(val);
  249.                 break;
  250.             case 'c':
  251.                 put_char( va_arg(ap,int) );
  252.                 break;
  253.             case 's':
  254.                 string= va_arg(ap,char*);
  255.                 while(*string)
  256.                     put_char(*string++);
  257.                 break;
  258.             case 'p':
  259. /* Å un formato non standard C, ma mi fa molto comodo: una stringa formato Pascal */
  260.                 string= va_arg(ap,char*);
  261.                 val= *string++;
  262.                 while(--val>=0)
  263.                     put_char(*string++);
  264.                 break;
  265.             }
  266.             }
  267.             format++;
  268.         }
  269.     va_end(ap);
  270.     if(!no_flush)
  271.         enable_autoflush();
  272. }
  273.  
  274. static void printdec(val)
  275. register long val;
  276. {
  277. char buf[14];
  278. register int i=-1;
  279. if(val<0){
  280.     val= -val;
  281.     put_char('-');
  282.     }
  283. do{
  284.     buf[++i]='0'+(int)(val%10);
  285.     val /= 10;
  286.     }
  287. while(val>0);
  288. while(i>=0) put_char(buf[i--]);
  289.  
  290. }
  291.  
  292. static void print_oct(val)
  293. register long val;
  294. {
  295. char buf[14];
  296. register int i=-1;
  297. do{
  298.     buf[++i]='0'+(int)(val&7);
  299.     val >>=3;
  300.     }
  301. while(val>0);
  302. while(i>=0) put_char(buf[i--]);
  303. }
  304.  
  305. static void printhex(val,longform)
  306. register long val;
  307. Boolean longform;
  308. {
  309. int digit,i=longform?28:12;
  310. short non_in_testa=0;
  311. while(i>=0){
  312.     if(!i) non_in_testa=1;
  313.     digit= (val>>i) & 0xF;
  314.     if(digit!=0 || non_in_testa){
  315.         put_char (digit<=9 ? '0'+digit : 'A'-10+digit );
  316.         non_in_testa=1;
  317.         }
  318.     i-=4;
  319.     }
  320. }
  321.  
  322. void print_chars(p,n)
  323. char* p;
  324. int n;
  325. {
  326. if(!n) return;
  327. while(--n)
  328.     put_char(*p++);
  329. printf("%c",*p);    /* to flush the buffer and update the scrollbars */
  330. }
  331.  
  332.  
  333.  
  334. #define BUFSIZE 80
  335.  
  336. static char io_buf[BUFSIZE];
  337. static short chars_in_buffer=0;
  338.  
  339. void put_char(c)
  340. char c;
  341. {
  342. if(c==LF) c=CR;
  343. if(chars_in_buffer>=BUFSIZE){
  344.     GrafPtr savePort;
  345.     GetPort( &savePort );
  346.     SetPort( &my_windows[0]);
  347.     my_flush();
  348.     SetPort( savePort );
  349.     }
  350. if(c!= CR || last_char==LF || last_char==CR )
  351.     last_char=c;
  352. else
  353.     last_char=LF;        /* meaning one carriage return but not two, CR means
  354.                         at least two carriage returns */
  355. io_buf[chars_in_buffer]=c;
  356. chars_in_buffer++;
  357. }
  358.  
  359. void update_console()
  360. {
  361. /* per uno stupido bug: il TextEdit non Å pensato per scrivere su una finestra
  362. che sta in background e lo scroll (almeno quello automatico) non provvede a scrollare
  363. anche l'update region, col che l'update successivo Å sulla posizione vecchia,
  364. non scrollata, del buco bianco. Unica soluzione, fare un update subito... ovviamente,
  365. per essere sicuri bisognerebbe chiamarla in continuazione, io mi limito a chiamarla
  366. quando chiudo una finestra di dialogo, quando ci sono forti probabilitê di
  367. provocare un update
  368. -- TextEdit has a bad bug: the TESelView routine does scroll the text,
  369. but the update region is not scrolled (that is, OffsetRgn is not called) to 
  370. remember that the "white hole" left by an old window now closed was moved. 
  371. Hence, when the update event arrives it updates part of the window which needn't 
  372. an update and leaves part of the white hole. 
  373.  Only solution by now: don't call TeSelView when the update region is not empty:
  374. that is, either don't use TextEdit to implement the printf function (as a text
  375. editor it's still good, unless you type so quickly that a KeyDown event arrives 
  376. between the window closing and the update) or do your own implementation of TESelView 
  377. or call this function just before calling TESelView
  378. */
  379. if(!my_windows[0].used)
  380.     return;
  381. else{
  382.     RgnHandle h=((WindowPeek)&my_windows[0])->updateRgn;
  383.     RgnPtr p;
  384.     if(h && (p= *h) && p->rgnSize>=10)
  385.         if( *((long*)&p->rgnBBox) != *((long*)&p->rgnBBox.bottom) ) /* this test
  386.                 is redundant, but it may avoid a relatively expensive toolbox call */
  387.             if(!EmptyRgn (h)) UpdateWindow(&my_windows[0]);
  388.     }    
  389. }
  390.  
  391.  
  392. static void my_flush()
  393. {
  394. if(chars_in_buffer){
  395.     TEAutoView (false,my_windows[0].TEH);    /* otherwise, a lot of horizontal scrolling...*/
  396.     TESetSelect((long)32767,(long)32767,my_windows[0].TEH);
  397.     TEInsert(io_buf,(long)chars_in_buffer,my_windows[0].TEH);
  398.     TEAutoView (true,my_windows[0].TEH);
  399.     chars_in_buffer=0;
  400.     }
  401. }