home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / xp / xp_mesg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  7.2 KB  |  283 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19.  
  20. #include "xp_mesg.h"
  21. #include "xp_mesgp.h"
  22. #include "xpassert.h"
  23. #include "xp_trace.h"
  24. #include <stddef.h>
  25. #include <stdarg.h>
  26.  
  27. #ifdef DEBUG
  28. int DebugMessages = 1;
  29. #endif
  30.  
  31. /*-----------------------------------------------------------------------------
  32.     stdarg random access
  33.     
  34.     The stdarg interface requires you to access the argument in order and
  35.     specifying the types. We thus build an array first so that when we later
  36.     want random access to an argument, we know the types of all the ones 
  37.     before it.
  38. -----------------------------------------------------------------------------*/
  39.  
  40. INLINE xpm_Integer
  41. integer_argument (xpm_Args * args, int arg)
  42. {
  43.     va_list stack;
  44.     xpm_Integer value;
  45.     int i;
  46.     
  47. #ifdef VA_START_UGLINESS
  48.     stack = args->stack;
  49. #else
  50.     va_start (stack, (*(args->start)));
  51. #endif
  52. #ifdef DEBUG
  53.     XP_ASSERT (stack == args->stack);
  54. #endif
  55.     for (i = 0; i <= arg; i++) {
  56.         if (args->types[i] == matInteger)
  57.             value = va_arg (stack, xpm_Integer);
  58.         else
  59.             va_arg (stack, char*);
  60.     }
  61.     va_end (stack);
  62.     
  63.     XP_LTRACE(DebugMessages,1,("message: integer %i is %i\n", arg, value));
  64.     return value;
  65. }
  66.  
  67. INLINE char *
  68. stack_string (xpm_Args * args, int arg)
  69. {
  70.     va_list stack;
  71.     char * value;
  72.     int i;
  73.     
  74. #ifdef VA_START_UGLINESS
  75.     stack = args->stack;
  76. #else
  77.     va_start (stack, (*(args->start)));
  78. #endif
  79. #ifdef DEBUG
  80.     XP_ASSERT (stack == args->stack);
  81. #endif
  82.     for (i = 0; i <= arg; i++) {
  83.         if (args->types[i] == matInteger)
  84.             va_arg (stack, xpm_Integer);
  85.         else
  86.             value = va_arg (stack, char*);
  87.     }
  88.     va_end (stack);
  89.     
  90.     XP_LTRACE(DebugMessages,1,("message: string %i is %s\n", arg, value));
  91.     return value;
  92. }
  93.  
  94. /*-----------------------------------------------------------------------------
  95.     flow of control
  96.     
  97.     process_message runs through the format string (such as "open %1s with %2s"
  98.     and sends normal characters through the "literal" output function and
  99.     string and integer arguments though the "argument" function.
  100. -----------------------------------------------------------------------------*/
  101.  
  102. static void
  103. process_message (const char * format, OutputStream * o)
  104. {
  105.     const char * current = format;
  106.     char c = *current;
  107.     
  108.     while (c) {
  109.         if (c == '%') {
  110.             c = *++current;
  111.             XP_ASSERT (c);
  112.             if (c == '%') {
  113.                 (o->writeLiteral) (o, '%');
  114.                 c = *++current;
  115.             }
  116.             else {
  117.                 int i = (c - '1');
  118.                 XP_ASSERT (0 <= i && i < MessageArgsMax);
  119.                 c = *++current;
  120.                 XP_ASSERT (c);
  121.                 (o->writeArgument) (o, c, i);
  122.                 c = *++current;
  123.             }
  124.         }
  125.         else {
  126.             (o->writeLiteral) (o, c);
  127.             c = *++current;
  128.         }
  129.     }
  130. }
  131.  
  132. /*-----------------------------------------------------------------------------
  133.     ScanStream runs through the format string and builds the stdarg random
  134.     access table.
  135. -----------------------------------------------------------------------------*/
  136.  
  137. typedef struct ScanStream_ {
  138.     OutputStream    o;
  139. } ScanStream;
  140.  
  141. static void 
  142. xpm_scan_literal (OutputStream * o, char c)
  143. {
  144.     ScanStream * s = (ScanStream *) o;
  145. }
  146.  
  147. static void
  148. xpm_scan_argument (OutputStream * o, char c, int i)
  149. {
  150.     ScanStream * s = (ScanStream *) o;
  151.     if (c == 's') {
  152.         s->o.args->sizes[i] = sizeof (char*);
  153.         s->o.args->types[i] = matString;
  154.     }
  155.     else if (c == 'i') {
  156.         s->o.args->sizes[i] = sizeof (xpm_Integer);
  157.         s->o.args->types[i] = matInteger;
  158.     }
  159.     else
  160.         XP_ABORT(("message: invalid specifier `%c'\n", c));
  161. }
  162.  
  163. static void
  164. xpm_ScanStack (const char * format, xpm_Args * args)
  165. {
  166.     ScanStream s;
  167.     s.o.writeLiteral = & xpm_scan_literal;
  168.     s.o.writeArgument = & xpm_scan_argument;
  169.     s.o.args = args;
  170.     
  171.     process_message (format, & s.o);
  172. }
  173.  
  174. /*-----------------------------------------------------------------------------
  175.     CountStream counts the total number of characters in the message.
  176. -----------------------------------------------------------------------------*/
  177.  
  178. typedef struct CountStream_ {
  179.     OutputStream    o;
  180.     int                total;
  181. } CountStream;
  182.  
  183. static void 
  184. xpm_count_literal (OutputStream * o, char c)
  185. {
  186.     CountStream * s = (CountStream *) o;
  187.     s->total ++;
  188. }
  189.  
  190. static void
  191. xpm_count_argument (OutputStream * o, char c, int i)
  192. {
  193.     CountStream * s = (CountStream *) o;
  194.     if (c == 's') {
  195.         char * value = stack_string (o->args, i);
  196.         int len = value? strlen (value): 0;
  197.         s->total += len;
  198.     }
  199.     else if (c == 'i') {
  200.         s->total += 10;
  201.     }
  202. }
  203.  
  204. static int
  205. xpm_MessageLen (const char * format, xpm_Args * args)
  206. {
  207.     CountStream s;
  208.     s.o.writeLiteral = & xpm_count_literal;
  209.     s.o.writeArgument = & xpm_count_argument;
  210.     s.o.args = args;
  211.     s.total = 0;
  212.     
  213.     xpm_ScanStack (format, args);
  214.     process_message (format, & s.o);
  215.     
  216.     return s.total + 1 /* NULL */;
  217. }
  218.  
  219. /*-----------------------------------------------------------------------------
  220.     Public API
  221.     These just build stdarg structures and call the internal functions.
  222. -----------------------------------------------------------------------------*/
  223.  
  224. int
  225. XP_MessageLen (const char * format, ...)
  226. {
  227.     xpm_Args args;
  228.     int len;
  229.     
  230. #ifdef VA_START_UGLINESS
  231.     va_start (args.stack, format);
  232. #endif
  233.     args.start = &format;
  234.     len = xpm_MessageLen (format, &args);
  235. #ifdef VA_START_UGLINESS
  236.     va_end (args.stack);
  237. #endif
  238.     
  239.     return len;
  240. }
  241.  
  242. void
  243. XP_Message (char * buffer, int bufferLen, const char * format, ...)
  244. {
  245. /*
  246.     This is a positional format string function. It's almost like
  247.     sprintf, except that sprintf takes the format arguments in the
  248.     order they are pushed on the stack. This won't work for
  249.     il8n purposes. In other languages the arguments may have to be
  250.     used in a different order. Therefore we need a format string
  251.     which specifies the argument explicitly (say by number).
  252.     
  253.     sprintf fails us here:
  254.         English: format = "open %1s with %2s"
  255.         Japanese: format = "with %2s open %1s"
  256.     printf (format, "foo.gif", "LView") ->
  257.         English: "open foo.gif with LView"
  258.         Japanese: "with foo.gif open LView" (wrong)
  259.     
  260.     XP_Message will work like this:
  261.         English: format = "open %1s with %2s"
  262.         Japanese: format = "with %2s open %1s"
  263.     XP_Message (format, "foo.gif", "LView") ->
  264.         English: "open foo.gif with LView"
  265.         Japanese: "with LView open foo.gif" (arguments in correct positions)
  266.     
  267.     The syntax is: %NT, N = number of argument, T = type (only s and i
  268.     supported). So %1s is the first argument as a string, %2i is the second 
  269.     argument as a number. No other printf modifiers (field widths, etc) are 
  270.     supported. It is legal to reference the same argument multiple times.
  271.     
  272.     %% outputs %.
  273.     There is a maximum of 9 arguments.
  274. */
  275. }
  276.  
  277. const char *
  278. XP_StaticMessage (const char * format, ...)
  279. {
  280.     return NULL;
  281. }
  282.  
  283.