home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bsd / src / printf / printf-amiga / printf.c < prev   
C/C++ Source or Header  |  1993-09-23  |  7KB  |  308 lines

  1. /*
  2.  * Copyright (c) 1989 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)printf.c    5.9 (Berkeley) 6/1/90";
  42. #endif /* not lint */
  43.  
  44. #include <sys/types.h>
  45. #include <stdio.h>
  46.  
  47. #define PF(f, func) { \
  48.     if (fieldwidth) \
  49.         if (precision) \
  50.             (void)printf(f, fieldwidth, precision, func); \
  51.         else \
  52.             (void)printf(f, fieldwidth, func); \
  53.     else if (precision) \
  54.         (void)printf(f, precision, func); \
  55.     else \
  56.         (void)printf(f, func); \
  57. }
  58.  
  59. char **gargv;
  60.  
  61. main(argc, argv)
  62.     int argc;
  63.     char **argv;
  64. {
  65.     static char *skip1, *skip2;
  66.     register char *format, *fmt, *start;
  67.     register int end, fieldwidth, precision;
  68.     char convch, nextch, *getstr(), *index(), *mklong();
  69.     double getdouble();
  70.     long getlong();
  71.  
  72.     if (argc < 2) {
  73.         fprintf(stderr, "usage: printf format [arg ...]\n");
  74.         exit(1);
  75.     }
  76.  
  77.     /*
  78.      * Basic algorithm is to scan the format string for conversion
  79.      * specifications -- once one is found, find out if the field
  80.      * width or precision is a '*'; if it is, gather up value.  Note,
  81.      * format strings are reused as necessary to use up the provided
  82.      * arguments, arguments of zero/null string are provided to use
  83.      * up the format string.
  84.      */
  85.     skip1 = "#-+ 0";
  86.     skip2 = "*0123456789";
  87.  
  88.     escape(fmt = format = *++argv);        /* backslash interpretation */
  89.     gargv = ++argv;
  90.     for (;;) {
  91.         end = 0;
  92.         /* find next format specification */
  93. next:        for (start = fmt;; ++fmt) {
  94.             if (!*fmt) {
  95.                 /* avoid infinite loop */
  96.                 if (end == 1) {
  97.                     fprintf(stderr,
  98.                         "printf: missing format character.\n");
  99.                     exit(1);
  100.                 }
  101.                 end = 1;
  102.                 if (fmt > start)
  103.                     (void)printf("%s", start);
  104.                 if (!*gargv)
  105.                     exit(0);
  106.                 fmt = format;
  107.                 goto next;
  108.             }
  109.             /* %% prints a % */
  110.             if (*fmt == '%') {
  111.                 if (*++fmt != '%')
  112.                     break;
  113.                 *fmt++ = '\0';
  114.                 (void)printf("%s", start);
  115.                 goto next;
  116.             }
  117.         }
  118.  
  119.         /* skip to field width */
  120.         for (; index(skip1, *fmt); ++fmt);
  121.         fieldwidth = *fmt == '*' ? getint() : 0;
  122.  
  123.         /* skip to possible '.', get following precision */
  124.         for (; index(skip2, *fmt); ++fmt);
  125.         if (*fmt == '.')
  126.             ++fmt;
  127.         precision = *fmt == '*' ? getint() : 0;
  128.  
  129.         /* skip to conversion char */
  130.         for (; index(skip2, *fmt); ++fmt);
  131.         if (!*fmt) {
  132.             fprintf(stderr, "printf: missing format character.\n");
  133.             exit(1);
  134.         }
  135.  
  136.         convch = *fmt;
  137.         nextch = *++fmt;
  138.         *fmt = '\0';
  139.         switch(convch) {
  140.         case 'c': {
  141.             char p = getchr();
  142.             PF(start, p);
  143.             break;
  144.         }
  145.         case 's': {
  146.             char *p = getstr();
  147.             PF(start, p);
  148.             break;
  149.         }
  150.         case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
  151.             char *f = mklong(start, convch);
  152.             long p = getlong();
  153.             PF(f, p);
  154.             break;
  155.         }
  156.         case 'e': case 'E': case 'f': case 'g': case 'G': {
  157.             double p = getdouble();
  158.             PF(start, p);
  159.             break;
  160.         }
  161.         default:
  162.             fprintf(stderr, "printf: illegal format character.\n");
  163.             exit(1);
  164.         }
  165.         *fmt = nextch;
  166.     }
  167.     /* NOTREACHED */
  168. }
  169.  
  170. char *
  171. mklong(str, ch)
  172.     char *str, ch;
  173. {
  174.     int len;
  175.     char *copy, *malloc();
  176.  
  177.     len = strlen(str) + 2;
  178.     if (!(copy = malloc((u_int)len))) {    /* never freed; XXX */
  179.         fprintf(stderr, "printf: out of memory.\n");
  180.         exit(1);
  181.     }
  182.     bcopy(str, copy, len - 3);
  183.     copy[len - 3] = 'l';
  184.     copy[len - 2] = ch;
  185.     copy[len - 1] = '\0';
  186.     return(copy);
  187. }
  188.  
  189. escape(fmt)
  190.     register char *fmt;
  191. {
  192.     register char *store;
  193.     register int value, c;
  194.  
  195.     for (store = fmt; c = *fmt; ++fmt, ++store) {
  196.         if (c != '\\') {
  197.             *store = c;
  198.             continue;
  199.         }
  200.         switch (*++fmt) {
  201.         case '\0':        /* EOS, user error */
  202.             *store = '\\';
  203.             *++store = '\0';
  204.             return;
  205.         case '\\':        /* backslash */
  206.         case '\'':        /* single quote */
  207.             *store = *fmt;
  208.             break;
  209.         case 'a':        /* bell/alert */
  210.             *store = '\7';
  211.             break;
  212.         case 'b':        /* backspace */
  213.             *store = '\b';
  214.             break;
  215.         case 'f':        /* form-feed */
  216.             *store = '\f';
  217.             break;
  218.         case 'n':        /* newline */
  219.             *store = '\n';
  220.             break;
  221.         case 'r':        /* carriage-return */
  222.             *store = '\r';
  223.             break;
  224.         case 't':        /* horizontal tab */
  225.             *store = '\t';
  226.             break;
  227.         case 'v':        /* vertical tab */
  228.             *store = '\13';
  229.             break;
  230.                     /* octal constant */
  231.         case '0': case '1': case '2': case '3':
  232.         case '4': case '5': case '6': case '7':
  233.             for (c = 3, value = 0;
  234.                 c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) {
  235.                 value <<= 3;
  236.                 value += *fmt - '0';
  237.             }
  238.             --fmt;
  239.             *store = value;
  240.             break;
  241.         default:
  242.             *store = *fmt;
  243.             break;
  244.         }
  245.     }
  246.     *store = '\0';
  247. }
  248.  
  249. getchr()
  250. {
  251.     if (!*gargv)
  252.         return((int)'\0');
  253.     return((int)**gargv++);
  254. }
  255.  
  256. char *
  257. getstr()
  258. {
  259.     if (!*gargv)
  260.         return("");
  261.     return(*gargv++);
  262. }
  263.  
  264. static char *number = "+-.0123456789";
  265. getint()
  266. {
  267.     if (!*gargv)
  268.         return(0);
  269.     if (index(number, **gargv))
  270.         return(atoi(*gargv++));
  271.     return(asciicode());
  272. }
  273.  
  274. long
  275. getlong()
  276. {
  277.     long atol();
  278.  
  279.     if (!*gargv)
  280.         return((long)0);
  281.     if (index(number, **gargv))
  282.         return(strtol(*gargv++, (char **)NULL, 0));
  283.     return((long)asciicode());
  284. }
  285.  
  286. double
  287. getdouble()
  288. {
  289.     double atof();
  290.  
  291.     if (!*gargv)
  292.         return((double)0);
  293.     if (index(number, **gargv))
  294.         return(atof(*gargv++));
  295.     return((double)asciicode());
  296. }
  297.  
  298. asciicode()
  299. {
  300.     register char ch;
  301.  
  302.     ch = **gargv;
  303.     if (ch == '\'' || ch == '"')
  304.         ch = (*gargv)[1];
  305.     ++gargv;
  306.     return(ch);
  307. }
  308.