home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_09_05 / 9n05072a < prev    next >
Text File  |  1991-03-04  |  7KB  |  259 lines

  1. /* soffset and related routines.  C/C++.  Author: Stephen D. Williams */
  2. /* Structure packing and unpacking routines, with alignment compensation. */
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <ctype.h>
  7. #include <limits.h>     /* used to set ints to max/min on over/under flow */
  8. #define yr_of_date(d)   ((int)((d)/10000L))
  9. #define mo_of_date(d)   ((int)(((d)%10000L)/100L))
  10. #define dy_of_date(d)   ((int)(((d)%10000L)%100L))
  11. #define date_of_yrmody(y,m,d)   ((y)*10000L+(m)*100L+(d))
  12. extern long us_date_to_long(char *dates, char **endptr);//in date.cxx
  13. int *chkalign(void)
  14. {
  15.  /* char, short, int, long, float, double, not used: enum, long double */
  16. static int alignarry[8]= {0,0,0,0,0,0,0,0};
  17.    /* if you really have a long double, doubles below should change */
  18. struct { double a; char b; char c; } c;
  19. struct { double a; char b; short s; } s;
  20. struct { double a; char b; int i; } i;
  21. struct { double a; char b; long l; } l;
  22. struct { double a; char b; float f; } f;
  23. struct { double a; char b; double d; } d;
  24.  
  25.    /* sets number of pad chars to get to boundary */
  26. alignarry[0]=((char *)&c.c-(char *)&c.b)-1;
  27. alignarry[1]=((char *)&s.s-(char *)&s.b)-1;
  28. alignarry[2]=((char *)&i.i-(char *)&i.b)-1;
  29. alignarry[3]=((char *)&l.l-(char *)&l.b)-1;
  30. alignarry[4]=((char *)&f.f-(char *)&f.b)-1;
  31. alignarry[5]=((char *)&d.d-(char *)&d.b)-1;
  32.  
  33. return(alignarry);
  34. }
  35. int num_fields(const char *str)    /* count non digits/spaces */
  36. {
  37.  int nf = 0;
  38.  while(*str)
  39.    {
  40.    if(isdigit(*str++))
  41.        continue;
  42. //      if(!isspace(*(str-1)))  // assume any non digit is valid now
  43.                            // watch for 2 digit lengths to use this
  44.        nf++;
  45.    }
  46.  return(nf);
  47.  }
  48. /* gets the offset of the nth item from 0 */
  49. int soffset(const char *str, int n, char *t, int *numitems, int dat_align)
  50. {    // type/size is "c20"
  51. char *endptr;
  52. int num, size = 0;
  53. int ind;
  54. static int *al = NULL;               // only call once
  55.  
  56. if(!al)
  57.   al = chkalign();
  58. while(n--)
  59.  { 
  60.  char cc;
  61.  cc = *str++;
  62.  num = (int)strtol(str, &endptr, 10);
  63.  str = endptr;
  64.  num = num ? num : 1;
  65.  switch(cc)
  66.     {        /* skip char */
  67.     case 'c':
  68.     case 's':
  69.        break;
  70.     case 'i':
  71.     case 'u':
  72.        num *= sizeof(int);
  73.        break;
  74.     case 'D':   /* long date */
  75.     case 'l':
  76.     case 'm':   /* unsigned long */
  77.        num *= sizeof(long);
  78.        break;
  79.     case 'f':
  80.        num *= sizeof(float);
  81.        break;
  82.     case 'd':
  83.        num *= sizeof(double);
  84.        break;
  85.     default:
  86.         return(0);        /* bad format code */
  87.      }
  88.  switch(*str)
  89.     {  /* look at next char */
  90.     case 's':
  91.     case 'c':
  92.         ind = 0;
  93.         break;
  94.     case 'i':
  95.     case 'u':
  96.         ind = 2;
  97.         break;
  98.     case 'D':   /* long date */
  99.     case 'l':
  100.     case 'm':
  101.         ind = 3;
  102.         break;   /* unsigned long */
  103.     case 'f':
  104.         ind = 4;
  105.         break;
  106.     case 'd':
  107.         ind = 5;
  108.         break;
  109.     default:
  110.         ind = 0;     /* either bad format code, or end of string */
  111.     }
  112.  size += num;      /* add size of current element */
  113.    /* this should align to next boundary, if on */
  114.  if (dat_align)
  115.     size += ((al[ind] + 1 - (al[ind] & size)) & al[ind]);
  116.   }
  117. if(t)
  118.   *t = *str;     /* return type */
  119. str++;
  120. num = (int)strtol(str, &endptr, 10);
  121. str = endptr;
  122. num = num ? num : 1;
  123. if(numitems)
  124.   *numitems = num; /* if passed a pointer, return len */
  125. return(size);
  126. }
  127.  /* converts the data to str */
  128. // fmt is null or "" for not used
  129. void ttos(char *dest, void *src, int offs, char t, int numitems, char *fmt)
  130.  {       /* doesn't check for sprintf overflow */
  131.  int fmtp = (fmt && *fmt);
  132.  switch(t & 0xff)
  133.    {
  134.    case 'c':       /* this adds a null to end of all strings */
  135.      if(fmtp)
  136.          {
  137.          sprintf(dest, fmt, ((char *)src+offs));
  138.          }
  139.      else
  140.         {
  141.          strncpy(dest,((char *)src+offs),numitems);
  142. //            dest[numitems] = 0;   /* delimit string */
  143.          }
  144.     break;
  145.  case 'i':
  146.     sprintf(dest,fmtp ? fmt : "%d",*((int *)((char *)src+offs)));
  147.     break;
  148.  case 'u':
  149.     sprintf(dest,fmtp ? fmt : "%u",*((unsigned *)((char *)src+offs)));
  150.     break;
  151.  case 'l':
  152.     sprintf(dest,fmtp ? fmt : "%ld",*((long *)((char *)src+offs)));
  153.     break;
  154.  case 'm':       /* unsigned long */
  155.     sprintf(dest,fmtp ? fmt : "%lu",*((unsigned long *)((char *)src+offs)));
  156.     break;
  157.  case 'D':       /* long date */
  158.     { 
  159.     long t;
  160.     t = *((long *)((char *)src+offs));
  161.     if((t == 0) || (t == -1))
  162.         strcpy(dest, "  /  /  ");
  163.     else
  164.        {
  165.        sprintf(dest,fmtp ? fmt : "%02.2d/%02.2d/%02.2d",
  166.        mo_of_date(t), dy_of_date(t), yr_of_date(t));
  167.        }
  168.     }
  169.     break;
  170.  case 'f':       /* note: prints ieee max significant */
  171.     sprintf(dest,fmtp ? fmt : "%.7g", *((float *) ((char *)src+offs)));
  172.     break;
  173.  case 'd':
  174.     sprintf(dest,fmtp ? fmt : "%.15g", *((double *) ((char *)src+offs)));
  175.     break;
  176.  }
  177. }
  178.  /* converts the str to data, returns success: only for special data types */
  179. int stot(void *dest, char *src, int offs, char t, int numitems)
  180. {       /* doesn't check for sprintf overflow */
  181. long ttmp;
  182. char *p;
  183.  
  184. p = (char *)dest + offs;
  185. switch(t & 0xff)
  186.  {
  187.  case 'c':
  188.     strncpy(p,src,numitems);
  189.     break;
  190.  case 'i':
  191.     *((int *)(p)) = (int)(ttmp = strtol(src, (char **)NULL, 10));
  192.     if(ttmp > INT_MAX)
  193.         *((int *)p) = INT_MAX;
  194.     else
  195.        if(ttmp < INT_MIN)
  196.            *((int *)p) = INT_MIN;
  197.     break;
  198.  case 'u':
  199.     *((unsigned *)(p)) = (int)(ttmp = strtoul(src, (char **)NULL, 10));
  200.     if(ttmp > UINT_MAX)
  201.         *((unsigned *)p) = UINT_MAX;
  202.     break;
  203.  case 'l':
  204.     *((long *)(p)) = strtol(src, (char **)NULL, 10);
  205.     break;
  206.  case 'm':       /* unsigned long */
  207.     *((unsigned long *)(p)) = strtoul(src, (char **)NULL, 10);
  208.     break;
  209.  case 'D':       /* long date */
  210.     *((long *)(p)) = us_date_to_long(src, (char **) 0);
  211.     if (*(long *)p == -1l)
  212.         return(-1);  /* bad date */
  213.     break;
  214.  case 'f':
  215.     *((float *)(p)) = (float)strtod(src, (char **)NULL);
  216.     break;
  217.  case 'd':
  218.     *((double *)(p)) = strtod(src, (char **)NULL);
  219.     break;
  220.  }
  221. return(0);          /* good conversion */
  222. }
  223. int num_chars_display(char type, int numitems)
  224. {
  225.  int num = 1;
  226.  switch(type & 0xff)
  227.    {        /* skip char */
  228.    case 'c':
  229.    case 's':
  230.        num = numitems;
  231.        break;
  232.    case 'i':
  233.        num = 6;
  234.        break;
  235.    case 'u':
  236.        num = 5;
  237.        break;
  238.    case 'D':   /* long date */
  239.        num = 8;
  240.        break;
  241.    case 'l':
  242.        num = 11;
  243.        break;
  244.    case 'm':   /* unsigned long */
  245.        num = 10;
  246.        break;
  247.    case 'f':
  248.        num = 16;
  249.        break;
  250.    case 'd':
  251.        num = 24;
  252.        break;
  253.    default:
  254.         num = 8;        /* bad format code */
  255.    }
  256. return(num);
  257. }
  258.  
  259.