home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / HATCH / WWIVNEWS.ZIP / 9304_3.NWS < prev    next >
Text File  |  1993-04-10  |  13KB  |  262 lines

  1. ───────────────┬─────────────────────────────────────────────┬───────────────
  2.                │       "Box Mods" - Threat or Menace?        │
  3.                │     By Starship Trooper (1@2750/12754)      │
  4.                └─────────────────────────────────────────────┘
  5.  
  6. Many people ask for or write mods to colorize and draw boxes around
  7. the "Last few callers" listing, sub lists, and similar items. This is
  8. actually a very simple procedure, which can be done by anyone without
  9. working from a published mod file. In this article, I will demonstrate
  10. how this should be done.
  11.  
  12. As an example, consider the function to list the chains available.
  13. Unmodified, it appears in BBSUTL1.C as:
  14.  
  15. void show_chains(int *mapp, int *map)                       //  1
  16. {                                                           //  2
  17.   int abort,i,i1;                                           //  3
  18.   char s[81];                                               //  4
  19.                                                             //  5
  20.   abort=0;                                                  //  6
  21.   nl();                                                     //  7
  22.   for (i=0; (i<*mapp) && (!abort) && (!hangup); i++) {      //  8
  23.     sprintf(s,"%d. %s",i+1, chains[map[i]].description);    //  9
  24.     pla(s,&abort);                                          // 10
  25.   }                                                         // 11
  26.   nl();                                                     // 12
  27. }                                                           // 13
  28.  
  29. Obviously, lines 8 through 11 do the actual printing. Line 9 writes the
  30. number and name of the chain into string s (such as "1. Tradewars") and
  31. line 9 sends it to the screen and modem, followed by a new line. sprintf()
  32. format strings (like "%d. %s") work exactly like those used by printf() and
  33. npr(). The '%' instructs the function to grab the next argument, and the 'd'
  34. or 's' tells how to interpret it. These format specifies are very
  35. powerful; you can specify how wide a certain item should be as well as
  36. several other options. This is essential for arranging the data in columns.
  37.  
  38. How wide should they be?  There's no simple answer. You have to take into
  39. account the actual length of an item, how much space to leave between them,
  40. and the width of a screen (80 columns).
  41.  
  42. Something like this is needed:
  43.  
  44. "║ xx │ description │"        (xx is the number of the chain).
  45.  
  46.  1234567???????????+2      Length= 7 + length(description) + 2
  47.  
  48. How long should the description be?  VARDEC.H says 81 characters, but that
  49. won't fit. Let's trim it to sixty. Sixty characters for the description
  50. plus nine (7+2) is well under our limit of 80. These numbers are placed
  51. within a sprintf() format specifier. First comes the '%', then the amount
  52. of space used, then the item type. If you want the item to be against the
  53. left side of the field, rather than the right, place a '-' before the width.
  54. This should be done in almost all cases, except with numbers.
  55.  
  56.     sprintf(s,"%2d %-60s",i+1, chains[map[i]].description);    //  9
  57.                 ^   ^^^
  58.  
  59. In the above line, the number will be printed within a two-space field,
  60. against the right edge, while the description will be printed within a
  61. 60-space field, against the left edge. There is an error, though:  if
  62. a description is greater than sixty characters, it will overflow the
  63. space. This can be corrected by adding a "precision" specifier. These
  64. tell sprintf() to only use a certain number of characters, and ignore
  65. those that would normally cause "overflow". This is done by placing a
  66. decimal point after the field width, and then the MAXIMUM number of
  67. characters allowed:
  68.  
  69.     sprintf(s,"%2d %-60.60s",i+1, chains[map[i]].description);    //  9
  70.                        ^^^
  71.  
  72. Everything is now in orderly columns. We can place them within a box
  73. by adding vertical line characters. The single bar (│) can be produced by
  74. holding down ALT and typing 179 on the numeric keypad, and the double
  75. bar (║) with ALT-186. Place these characters within the sprintf()
  76. format string, between the data items:
  77.  
  78.     sprintf(s,"║ %2d │ %-60.60s ║",i+1, etc.);    //  9
  79.                ^     ^          ^
  80. Next, add color codes. These are produced by embedding a control-C in the
  81. string, followed by a digit. If you're using the Borland editor or Qedit
  82. or the DOS 5.0 editor, this is done by typing a control-P and then a
  83. control-C. A heart symbol will appear. All the line characters
  84. should be the same color, as they will be joined together eventually.
  85.  
  86.     sprintf(s,"1║2 %2d 1│5 %-60.60s 1║",i+1, etc.);    //  9
  87.  
  88. (If you read this from within WWIV you will see colors, otherwise you will
  89. see hearts and digits.)
  90.  
  91. Your box will need a top and bottom also. Use your block-copy command to
  92. make a copy of the sprintf line you've been working on. Cut out everything
  93. but the string itself, and wrap a pl() (or pla()) around it:
  94.  
  95. pl("1║2 %2d 1│5 %-60.60s 1║");
  96.  
  97. Next, remove the colors:
  98. pl("║ %2d │ %-60.60s ║");
  99.  
  100. Replace vertical bars with corner pieces or T-shaped bars:
  101.  
  102. pl("╔ %2d ╤ %-60.60s ╗");
  103.  
  104. Next replace each of the format specifies with the proper number of
  105. horizontal lines. (in this example, two and sixty)
  106.  
  107. pl("╔ ══ ╤ ════════════════════════════════════════════════════════════ ╗");
  108.  
  109. (block-copy commands work well here for making long horizontal lines)
  110.  
  111. Finally, replace the blank spaces with horizontal lines. Then clone this
  112. line, and make the second copy look like the bottom of a box (replace the
  113. corners), and put a color code at the beginning:
  114.  
  115.  
  116. pl("1╔════╤══════════════════════════════════════════════════════════════╗");
  117.  
  118. pl("1╚════╧══════════════════════════════════════════════════════════════╝");
  119.  
  120. Insert these lines into the function just before and after the loop. You
  121. can, if you want, put a title on the upper bar:
  122.  
  123. pl("1╔════╤═══Online Programs Available══════════════════════════════════╗");
  124.  
  125. Your finished function might look like:
  126.  
  127. void show_chains(int *mapp, int *map)                       //  1
  128. {                                                           //  2
  129.   int abort,i,i1;                                           //  3
  130.   char s[81];                                               //  4
  131.                                                             //  5
  132.   abort=0;                                                  //  6
  133.   nl();                                                     //  7
  134.   pl("1╔════╤═══Online Programs Available══════════════════════════════════╗");
  135.   for (i=0; (i<*mapp) && (!abort) && (!hangup); i++) {      //  8
  136.     sprintf(s,"1║2 %2d 1│5 %-60.60s 1║",               //  9
  137.         i+1,chains[map[i]].description);                    /* Continued */
  138.     pla(s,&abort);                                          // 10
  139.   }                                                         // 11
  140.   pl("1╚════╧══════════════════════════════════════════════════════════════╝");
  141.   nl();                                                     // 12
  142. }                                                           // 13
  143.  
  144. Not all listing commands are easy to change. Some use multiple strcpy(), 
  145. strcat(), ansic(), outstr(), and similar non-sprintf() functions. (The function
  146. to print file information, for example). It is necessary to convert these to 
  147. use sprintf(), which I will demonstrate here. I encourage all mod writers to 
  148. use this information... not only is it useful for "box mods", but many other 
  149. mods use the older, cumbersome methods to output several pieces of data, when
  150. a single sprintf() is easier.
  151.  
  152. The first thing to do is locate a string variable that is not used in that part
  153. of the code. s, s1, s2, etc., often hold things only temporarily, and can be 
  154. safely reused. If you're unsure about it, simply declare a new string of 
  155. length 81 or more.
  156.  
  157. The functions to be replaced perform these actions:
  158.  
  159. Original function     sprintf code     result
  160. ──────────────────────────────────────────────────────────────────────────────
  161. strcpy(dest, src)       %s or constant   copy _src_ string into _dest_.
  162. strcat(dest, src)       %s or constant   append _src_ string to end of _dest_
  163. itoa(num, dest, rad)    %d               converts _num_ to string _dest_
  164. ansic(num)              ctrl-C digit     send ANSI codes to change color
  165. nl()                    \n               send CR and LF
  166.  
  167. When these functions are used, there will often be several of them in 
  168. succession. The first will be a strcpy(), to begin the string to be sent out, 
  169. followed by strcat()'s and possibly itoa()'s, which add successive items to 
  170. the output string, which will eventually be sent with outstr() or pl(). 
  171. Sometimes, small strings are composed and sent with outstr(), with ansic() 
  172. between them (see printinfo() in xfer.c).
  173.  
  174. The format for sprintf() is:
  175.     sprintf(buffer, "format string with %d %s etc.", var, var,...);
  176.  
  177. The first argument tells the program where to place the result. The second
  178. tells what it should look like, with % meaning "fetch something and put it 
  179. here", and the other arguments being the items that are "fetched". Standard 
  180. WWIV source makes use of sprintf() in most instances where a box mod would be 
  181. desired. The only exception is printinfo(), which prints the information for a 
  182. file. Although it's not too difficult to convert it, the function is very long,
  183. too long for this article. Let's try something simpler, a (hypothetical) mod 
  184. that does something fairly interesting, but in a clumsy way:
  185.  
  186.        ┌────────────────────────────────────────────────────┐
  187.        │ WK-001.MOD by Joe Sysop #1@xxxx. This prints a     │
  188.        │ Way-K00L message to your callers:                  │
  189.        └────────────────────────────────────────────────────┘
  190.   <magenta>Welcome to Way-K00L BBS, <fl. red> John Smith!
  191.   <green>You are user #95, and you've called <cyan>17<green> times!
  192.  
  193. OK, put this somewhere in LILO.C:
  194.  
  195.   ansic(3); /* magenta */
  196.   strcpy(s, "Welcome to ");
  197.   strcat(s, syscfg.systemname);
  198.   strcat(s, ", ");
  199.   outstr(s);                       /* Welcome to Way-K00L BBS, */
  200.   ansic(6); /* fl. red */
  201.   outstr(thisuser.name);           /* John Smith */
  202.   outchr('!');  nl();              /* ! \n*/
  203.   ansic(5); /* green */
  204.   strcpy(s, "You are user #");
  205.   itoa(usernum, s1, 10);  /* convert num to string (base 10), store in s1 */
  206.   strcat(s,s1);
  207.   strcat(s,", and you've called ");
  208.   outstr(s);             /* You are user #95, and you've called */
  209.   ansic(1); /* cyan */
  210.   itoa(thisuser.timeson, s1, 10);
  211.   outstr(s1);            
  212.   ansic(5); /* green */
  213.   pl("times!");                                     /* End WK-001.MOD */
  214.  
  215. Obviously, there has to be a better way... let's take each item to be printed,
  216. and put it in a sprintf(). I'll reproduce the desired result here:
  217.  
  218.   <magenta>Welcome to Way-K00L BBS, <fl. red> John Smith!
  219.   <green>You are user #95, and you've called <cyan>17<green> times!
  220.  
  221. The first item is a change to color #3. This is done with ^C3.
  222.   sprintf(s,"3          /* equivalent to ansic(3) */
  223.  
  224. Next comes a constant string, "Welcome to ":
  225.   sprintf(s,"3Welcome to       /* we used strcpy in the badly-done example */
  226.  
  227. Then the system name, which is a string. Use "%s" to tell sprintf() to
  228. fetch it, and pass the variable as a parameter:
  229.   sprintf(s,"3Welcome to %s", syscfg.systemname); /* instead of strcat() */
  230.  
  231. Comma, space, then color #6:
  232.   sprintf(s,"3Welcome to %s, 6", syscfg.systemname);
  233.  
  234. And the user's name, then a '!', and print it:
  235.   sprintf(s,"3Welcome to %s, 6%s!", syscfg.systemname, thisuser.name);
  236.   pl(s);    /* print the above, then a linefeed */
  237.  
  238. The first line has been sent, so we'll do the next line now:
  239.   sprintf(s,"5You are user #
  240.  
  241. A number can be printed by placing "%d" in the string and the variable in
  242. the argument list. sprintf() will do an itoa() conversion:
  243.   sprintf(s,"5You are user #%d, ",usernum);
  244.  
  245. Another string constant follows, a color change, a number, a color change,
  246. and finally the last word:
  247.   sprintf(s,"5You are user #%d, and you've called 1%d5 times!",usernum,
  248.          thisuser.timeson);          /* ^C1%d^C5 ^^^ */ 
  249.   pl(s);
  250.  
  251. As you can see, the 19 lines of code in the original have been replaced by two 
  252. sprintf() and two pl() calls. You could even use npr() to integrate the 
  253. sprintf() and pl() sets into one line each (if you choose to do this, remember 
  254. to add a \r\n to the end). sprintf() produces more compact code and allows easy
  255. "Box Mods" using the procedure I detailed previously.
  256.  
  257. ──────────────────────────────────────────────────────────────────────────────
  258. Now you know how to make box mods - and so does almost everyone else. So please
  259. do not flood the mod subs with mods created using the guidelines here! If 
  260. someone asks how to box a listing, send them this file.
  261.  
  262.