#! /bin/sh # This is a shell archive. Type 'sh ' to unpack. echo x - README.1st cat >README.1st <<'MKSHAR_EOF' Date: January 6, 2003 Utility: on_to_unload.c Synopsis: This utility, was written to deblock and extract records from the output of arcunload. It will also read onunload output for a single table and the arcunload feature of archecker. Currently on_to_unload is formatted to read an onunload format file and write out a dbload compatible delimited data file. Data decoding is based on a list of data types, with length for char fields, as generated by sql2fmt.awk from a dbschema or myschema listing of the single table. This utility was written as a companion for the arcunload utility available from IIUG Software Repository (Special Programs section) which extracts a table's data from a level 0 ontape archive and writes the data pages to a file suitable for reloading using onload. However, since it is not always convenient to restore that way and since such emergency extractions are normally done to recover a subset of the data lost due to fumble fingers, I wrote this utility to read an onunload file, such as that produced by arcunload, and output a delimited file suitable for editing and manual extraction and for loading using dbload or the dbaccess load command. The purpose of this is to be able to edit and extract selected rows from the arcunload output without having to load the data into a table first. It also makes it possible to arcunload records from one server's archive and restore them to another server. Datatype support is not complete and may never be as arcunload is no longer supported though the arcunload feature of archecker still exists. Author(s): Art S. Kagel, kagelfamily@netscape.net Revision: 1.4 Version(s) supported: 7.2x+ File(s): on_to_unload.c, sql2fmt.awk Comments: requires arcunload, though it can be used with a true onunload output file or tape containing a single table (testing was performed using both arcunload and onunload output). Release Notes: Ver 1.2-1.4 implement additional datatypes including DATE, DATETIME, DECIMAL, INTERVAL, and VARCHAR. Ver 1.01 fixed bug outputting rows with misaligned data (ie binary row image contains columns that are not properly aligned for the hardware). This initial release only contains rudimentary data type and table support. Tables containing BLOBS, UDTs, etc and rows larger than a single page are not supported. Supported data types so far: serial, integer, smallint, float, smallfloat, char (fixed length). Also GLS support is not included. It should not be difficult to add support for the other fixed length data types. Support for variable length data types requires that the slot table parsing understand about slot forwarding when a row outgrows its home page. Also support for rows that do not fit on a single page will require complex record caching techniques as will BLOB support. Usage instructions: Pipe the output of dbschema or myschema to awk -f sql2fmt.awk and save the output, ie: myschema -d mydatabase -t table_to_unload | awk -f sql2fmt.awk >typefile Edit the output file to remove any lines that DO NOT begin with a data type. Now run the on_to_unload executable as: on_to_unload typefile arcunload_output_file on_to_unload_output_file.unl If you get any messages about unknown types you will have to update on_to_unload.c to handle them. Please send any update back to me for distribution. MKSHAR_EOF echo x - sql2fmt.awk cat >sql2fmt.awk <<'MKSHAR_EOF' BEGIN{ start=0; intable = 0; } /create table/ { intable = 1; next; } /CREATE TABLE/ { intable = 1; start = 1; next; } intable == 1 && $1 == "(" { start = 1; next; } start == 1 && $1 == ");" { start = 0; intable = 0; next; } start == 1 && $1 == ")" && $2 == "IN" {start = 0; intable = 0; next; } start == 1 { # print $0; split ($2, b, "," ); n=split( b[1], a, "[,()]" ); if (n>2) { printf "%s %d %d\n", a[1], a[2], a[3]; }else if (n>1) { printf "%s %d\n", a[1], a[2]; } else { printf "%s\n", a[1]; } n=split($0, c ); if (c[n] == ");") { start = 0; intable = 0; } } { next; } MKSHAR_EOF echo x - on_to_unload.c cat >on_to_unload.c <<'MKSHAR_EOF' /* on_to_unload.c - Program to deblock and extract records from Informix data pages. Currently formatted to read an onunload format file. Formatting based on a list of data types, with length for char fields, and variable length fields, as generated by sql2fmt.awk. This utility was written as a companion for the arcunload utility available from IIUG Software Repository (Special Programs section) which extracts a table's data from a level 0 ontape archive and writes the data pages to a file suitable for reloading using onload. However, since it is not always convenient to restore that way and since such emergency extractions are normally done to recover a subset of the data lost due to fumble fingers, I wrote this utility to read an onunload file, such as that produced by arcunload, and output a delimited file suitable for editing and manual extraction and for loading using dbload or the dbaccess load command. Output records use quoted HEX codes for non-printable characters including newline characters embedded in character columns. This means that files containing such data are best loaded using dbload -X. Author: Art S. Kagel Created: October 20, 1998 This source is released for public use. All rights of commercial exploitation retained. Copyright 1998, Art S. Kagel. */ /* RCS Header: ----------- $Header: /home/kagel/utils/RCS/on_to_unload.c,v 1.4 2001/01/17 16:22:29 kagel Exp kagel $ RCS Log: -------- $Log: on_to_unload.c,v $ Revision 1.4 2001/01/17 16:22:29 kagel Updated to handle DECIMALS. Revision 1.3 1999/03/15 17:36:33 kagel *** empty log message *** * Revision 1.2 1998/11/05 20:30:22 kagel * Added RCS headers, added support for new datatypes. Completed: * varchar(for full rows on a page only), date, datetime. Working on: * interval. Also fixed bugs affected misaligned data, can now recognize * format files in upper or lower case (support for dbschema & myschema). * Vers 1.1: Updated through Nov. 3, 1998 before initial checkin. */ static char RCSHeader[] = "$Header: /home/kagel/utils/RCS/on_to_unload.c,v 1.4 2001/01/17 16:22:29 kagel Exp kagel $"; static char RCSWhat[] = "$What: <@(#) on_to_unload.c,v 1.4 > $ $Date: 2001/01/17 16:22:29 $"; static char RCSCompile[] = "$cc: " __FILE__ " " __DATE__ " " __TIME__ " $"; #include #include #include #include #include #include #include #include typedef struct s_types { union { struct { short length, scale; } dec; struct { short max, incr; } vchar; struct { short start, end; } dtim; struct { char len, start, end; } intv; } optn; long length; short type; char type_str[19]; } t_types; typedef struct s_packdec { char exp_sgn:1, exponent:7; char digits[16]; } t_packdec; typedef struct pagehdr_s { long pagenum; long timestmp; short numslts; short flagbits; short freeoffs; short freebytes; long nextnode; long prevnode; } pagehdr_t; typedef struct partn_s { pagehdr_t hdr; long partnum; /* partition number */ short flags; /* flags */ short pctfree; /* percentage free space */ short rowsize; /* uncompressed row size */ short ncols; /* number columns in table */ short nkeys; /* number keys for table */ short nextns; /* number extents in partition */ long created; /* date/time created */ long serial; /* current serial value */ long fextsize; /* first extent size */ long nxtsize; /* subsequent extents size */ long nptotal; /* number pages total */ long npused; /* number pages ever used */ long npdata; /* number pages of data */ long octptnm; /* partnum of the optical cluster table */ long lockid; /* lock id to use */ long nrows; /* number rows in table */ } partn_t; long ncols, counter = 0, pages = 0, dpages = 0, totslots = 0; t_types ttypes[1000]; enum types {CHAR, SHORT, LONG32, LONG64, FLOAT, DOUBLE, DECIMAL, DTIME, INTVL, DATE, VCHAR }; void printrec( FILE *out, char *rec ); void gettypes( FILE *file ); char *nextrec( char *page, short *slot ); void strlower( char *str ); void date_to_ymd( long date, short *year, short *month, short *day ); void rdec_to_str( char *str, t_types *t, char *p ); void rdt_to_str( char *str, t_types *t, char *p ); void rint_to_str( char *str, t_types *t, char *p ); int main( int argc, char **argv ) { FILE *typefile, *inpfile, *outpfile; char page[2048], *rec; short slot; pagehdr_t *hdr = (pagehdr_t *)page; partn_t *phdr = (partn_t *)page; long datapages = 0; if (argc < 4) { fprintf( stderr, "Usage: %s typefile inputfile outputfile\n\n", argv[0] ); fprintf( stderr, "\ttypefile - file containing one datatype per line, " "second column \n\t\t is length for character columns.\n" ); fprintf( stderr, "\tinputfile - the file containing output from arcunload.\n" ); fprintf( stderr, "\toutputfile - the file into which to write delimited output.\n\n" ); exit( 1 ); } typefile = fopen( argv[1], "r" ); inpfile = fopen( argv[2], "r" ); outpfile = fopen( argv[3], "w" ); gettypes( typefile ); fclose( typefile ); for (;;) { if (fread( page, 2048, 1, inpfile ) == 0) break; if (hdr->pagenum == 0xfffffffd) { pages++; continue; } else if (hdr->pagenum == -1) { pages++; fprintf( stderr, "\nHeader page(%d):\n\tBlocksize = %d\n\ttapelen = %d.\n", pages, hdr->freeoffs, hdr->nextnode ); continue; } else if (hdr->pagenum == -2) { pages++; fprintf( stderr, "Separator page(%d).\n", pages ); continue; } else if (hdr->pagenum == -3) { pages++; fprintf( stderr, "Trailer page (%d)!\n\n", pages ); break; } else if (hdr->flagbits == 2) { /* Partition page. */ pages++; fprintf( stderr, "Partition page(%d) reports %d data pages.\n", pages, phdr->npdata ); datapages = phdr->npdata; continue; } else if (hdr->flagbits == 1) { /* Data/index page. */ pages++; slot = 0; while ((rec = nextrec( page, &slot ))) { printrec( outpfile, rec ); counter++; if (counter % 1000 == 0) { printf( "Wrote: %d\r", counter ); fflush( stdout ); } } } else pages++; if (dpages >= datapages) { fprintf( stderr, "Found all data pages. Exiting.\n" ); break; } } fflush( outpfile ); printf( "\nRead %d pages, %d data pages.\nDecoded %d slots.\nWrote %d records.\n", pages, dpages, totslots, counter ); fflush( stdout ); fclose( outpfile ); fclose( inpfile ); } /* Copy a string converting all to printables, quoting special chars. Returns a pointer to the end of the output string. */ char *intellicpy( char *to, char *from, short l ) { short i = 0; int h; unsigned char *t = (unsigned char *)to, *f = (unsigned char *)from; char *e; while (i < l && *f) { if (*f < ' ' || *f > '~') { h = *f; t += sprintf( t, "\\%02.2x", h ) - 1; } else if (*f == '\\' || *f == '|') { *t = '\\'; t++; *t = *f; } else *t = *f; t++; f++; i++; } e = (char *)(t - 1); for (;i <= l; i++, t++) *t = (char)0; return e; } void strip( char *to, char *from, short l ) { char *p; p = intellicpy( to, from, l ); while (p > to && *(p) == ' ') { *p = (char)0; p--; }; if (to[0] == (char)0) to[0] = ' '; } void printrec( FILE *out, char *rec ) { char *p = rec; static char holder[32768]; int field; short yr, mo, dy; static union u_data { double a_double; long a_long; short a_short; float a_float; long nullchk[2]; } data; for (field=0; field < ncols; field++) { switch (ttypes[field].type) { case LONG32: memcpy( &data.a_long, p, sizeof (long) ); if (data.a_long == LONG_MIN) fprintf( out, "|" ); else { fprintf( out, "%ld|", data.a_long ); } break; case SHORT: memcpy(&data.a_short, p, sizeof (short) ); if (data.a_short == SHRT_MIN) fprintf( out, "|" ); else { fprintf( out, "%hd|", data.a_short ); } break; case FLOAT: memcpy( &data.a_float, p, sizeof (float) ); if (data.nullchk[0] == 0xffffffff) fprintf( out, "|" ); else { fprintf( out, "%hf|", data.a_float ); } break; case DOUBLE: memcpy( &data.a_double, p, sizeof (double) ); if (data.nullchk[0] == 0xffffffff && data.nullchk[1] == 0xffffffff) fprintf( out, "|" ); else { fprintf( out, "%f|", data.a_double ); } break; case CHAR: if (*p == (char)0) fprintf( out, "|" ); else { strip( holder, p, ttypes[field].length ); fprintf( out, "%0.*s|", ttypes[field].length * -1, holder ); } break; case VCHAR: /* Column length is encoded in first byte, text follows. */ if (*p < 0) fprintf( out, "|" ); else if (*p == 0) fprintf( out, " |" ); else { strip( holder, (char *)(p+1), *p ); fprintf( out, "%s|", holder ); } break; case DATE: memcpy( &data.a_long, p, sizeof (long) ); date_to_ymd( data.a_long, &yr, &mo, &dy ); fprintf( out, "%d/%d/%d|", mo, dy, yr ); break; case DECIMAL: holder[0] = (char)0; rdec_to_str( holder, &ttypes[field], p ); fprintf( out, "%s|", holder ); break; case DTIME: holder[0] = (char)0; rdt_to_str( holder, &ttypes[field], p ); fprintf( out, "%s|", holder ); break; case INTVL: holder[0] = (char)0; rint_to_str( holder, &ttypes[field], p ); fprintf( out, "%s|", holder ); break; } p += ttypes[field].length; } fprintf( out, "\n" ); fflush( out ); } char *nextrec( char *page, short *slot ) { short nslots, offs; char *rec; pagehdr_t *hdr = (pagehdr_t *)page; if (hdr->flagbits != (short)1) /* Not a data page, skip it. */ return (char *)NULL; if (*slot == 0) { totslots += hdr->numslts; dpages++; } nslots = hdr->numslts; rehash: (*slot)++; if (*slot > nslots) return (char *)NULL; offs = (*(short *)(page + 2044 - (*slot * 4))); if (!offs) goto rehash; rec = (page + offs); return rec; } void gettypes( FILE *file ) { char buff[1025], *p; int digits, scale; ncols = 0; for (;;) { if (fgets( buff, 1025, file ) == (char *)NULL) break; p = strtok( buff, " \n" ); strlower( p ); strcpy( ttypes[ncols].type_str, p ); if (strcmp( p, "integer" ) == 0) { ttypes[ncols].length = 4; ttypes[ncols].type = LONG32; } else if (strcmp( p, "serial" ) == 0) { ttypes[ncols].length = 4; ttypes[ncols].type = LONG32; } else if (strcmp( p, "smallint" ) == 0) { ttypes[ncols].length = 2; ttypes[ncols].type = SHORT; } else if (strcmp( p, "float" ) == 0) { ttypes[ncols].length = 8; ttypes[ncols].type = DOUBLE; } else if (strcmp( p, "smallfloat" ) == 0) { ttypes[ncols].length = 4; ttypes[ncols].type = FLOAT; } else if (strcmp( p, "char" ) == 0) { p = strtok( NULL, " " ); ttypes[ncols].length = atol( p ); ttypes[ncols].type = CHAR; } else if (strcmp( p, "date" ) == 0) { ttypes[ncols].length = 4; ttypes[ncols].type = DATE; } else if (strcmp( p, "varchar" ) == 0) { p = strtok( NULL, " " ); ttypes[ncols].optn.vchar.max = atoi( p ); p = strtok( NULL, " " ); if (p) ttypes[ncols].optn.vchar.incr = atoi( p ); else ttypes[ncols].optn.vchar.incr = 1; ttypes[ncols].type = DATE; } else if (strcmp( p, "decimal" ) == 0 || strcmp( p, "money" ) == 0) { p = strtok( NULL, " " ); if (p) { ttypes[ncols].optn.dec.length = atoi( p ); p = strtok( NULL, " " ); if (p) ttypes[ncols].optn.dec.scale = atoi( p ); else ttypes[ncols].optn.dec.scale = -1; /* Float pt. */ } else { ttypes[ncols].optn.dec.length = 16; ttypes[ncols].optn.dec.scale = -1; /* Float pt. */ } ttypes[ncols].type = DECIMAL; ttypes[ncols].length = ((ttypes[ncols].optn.dec.length + 1) / 2) + 1; } else if (strcmp( p, "datetime" ) == 0) { p = strtok( NULL, " " ); strlower( p ); if (strcmp( p, "year" ) == 0) ttypes[ncols].optn.dtim.start = TU_YEAR; else if (strcmp( p, "month" ) == 0) ttypes[ncols].optn.dtim.start = TU_MONTH; else if (strcmp( p, "day" ) == 0) ttypes[ncols].optn.dtim.start = TU_DAY; else if (strcmp( p, "hour" ) == 0) ttypes[ncols].optn.dtim.start = TU_HOUR; else if (strcmp( p, "minute" ) == 0) ttypes[ncols].optn.dtim.start = TU_MINUTE; else if (strcmp( p, "second" ) == 0) ttypes[ncols].optn.dtim.start = TU_SECOND; else if (strcmp( p, "fraction" ) == 0) ttypes[ncols].optn.dtim.start = TU_FRAC; p = strtok( NULL, " " ); strlower( p ); if (strcmp( p, "year" ) == 0) ttypes[ncols].optn.dtim.end = TU_YEAR; else if (strcmp( p, "month" ) == 0) ttypes[ncols].optn.dtim.end = TU_MONTH; else if (strcmp( p, "day" ) == 0) ttypes[ncols].optn.dtim.end = TU_DAY; else if (strcmp( p, "hour" ) == 0) ttypes[ncols].optn.dtim.end = TU_HOUR; else if (strcmp( p, "minute" ) == 0) ttypes[ncols].optn.dtim.end = TU_MINUTE; else if (strcmp( p, "second" ) == 0) ttypes[ncols].optn.dtim.end = TU_SECOND; else if (strcmp( p, "fraction" ) == 0) { p = strtok( NULL, " " ); ttypes[ncols].optn.dtim.end = 10 + atoi( p ); } ttypes[ncols].type = DTIME; ttypes[ncols].length = 1 + (((ttypes[ncols].optn.dtim.end - ttypes[ncols].optn.dtim.start) + (ttypes[ncols].optn.dtim.start == TU_YEAR ? 4 : 2) + 1) / 2); } else if (strcmp( p, "interval" ) == 0) { p = strtok( NULL, " " ); strlower( p ); if (strcmp( p, "year" ) == 0) ttypes[ncols].optn.intv.start = TU_YEAR; else if (strcmp( p, "month" ) == 0) ttypes[ncols].optn.intv.start = TU_MONTH; else if (strcmp( p, "day" ) == 0) ttypes[ncols].optn.intv.start = TU_DAY; else if (strcmp( p, "hour" ) == 0) ttypes[ncols].optn.intv.start = TU_HOUR; else if (strcmp( p, "minute" ) == 0) ttypes[ncols].optn.intv.start = TU_MINUTE; else if (strcmp( p, "second" ) == 0) ttypes[ncols].optn.intv.start = TU_SECOND; else if (strcmp( p, "fraction" ) == 0) ttypes[ncols].optn.intv.start = TU_FRAC; p = strtok( NULL, " " ); strlower( p ); if ((ttypes[ncols].optn.intv.len = atoi( p )) == 0) if (ttypes[ncols].optn.intv.start == TU_YEAR) ttypes[ncols].optn.intv.len = 4; else ttypes[ncols].optn.intv.len = 2; else { p = strtok( NULL, " " ); strlower( p ); } if (strcmp( p, "year" ) == 0) ttypes[ncols].optn.intv.end = TU_YEAR; else if (strcmp( p, "month" ) == 0) ttypes[ncols].optn.intv.end = TU_MONTH; else if (strcmp( p, "day" ) == 0) ttypes[ncols].optn.intv.end = TU_DAY; else if (strcmp( p, "hour" ) == 0) ttypes[ncols].optn.intv.end = TU_HOUR; else if (strcmp( p, "minute" ) == 0) ttypes[ncols].optn.intv.end = TU_MINUTE; else if (strcmp( p, "second" ) == 0) ttypes[ncols].optn.intv.end = TU_SECOND; else if (strcmp( p, "fraction" ) == 0) { p = strtok( NULL, " " ); ttypes[ncols].optn.intv.end = 10 + atoi( p ); } ttypes[ncols].type = INTVL; ttypes[ncols].length = 1 + ((ttypes[ncols].optn.intv.end - ttypes[ncols].optn.intv.start + ttypes[ncols].optn.intv.len + 1) / 2); } else { fprintf( stderr, "Unknown type: %s on line %d\n", p, ncols+1 ); continue; } ncols++; } } void strlower( char *str ) { while (*str) { if (isupper( *str )) *str = _tolower( *str ); str++; } } void date_to_ymd( long date, short *year, short *month, short *day ) { int idx; long ydays, yr; long days_in_mo[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; long days_in_lp[12] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; /* # Days between leap years. 365 * 3 + 366 == 1461 */ yr = (date - (date / 1461)) / 365; ydays = date - ((yr - 1) / 4 + yr * 365); if (((date - (date / 1461)) % 365) == 0 && (ydays == 0 || ydays > 364)) { *year = 1900 + yr - 1; *month = 12; *day = 31; } else { *year = 1900 + yr; if (((*year % 4) == 0 && (*year % 100) != 0) || ((*year % 400) == 0)) { /* In a leap year use adjusted table. */ for (idx = 11; idx > 0; idx--) if (ydays > days_in_lp[idx]) break; *day = ydays - days_in_lp[idx]; } else { for (idx = 11; idx > 0; idx--) if (ydays > days_in_mo[idx]) break; *day = ydays - days_in_mo[idx]; } *month = idx + 1; } } void rdec_to_str( char *str, t_types *t, char *p ) { int placeholder = 1; t_packdec *d = (t_packdec *)p; int d1, d2, ix, ndigs = 0; double value, factor; value = 0.0d; factor = 1.0; for (ix=15; ix >= 0; ix--) { d1 = d->digits[ix] % 256; if (d1) { if (lastnull) { ndigs += lastnull; lastnull = 0; } value = value + ((double)d1 * factor); factor *= 100.0; ndigs++; } else { if (d2) factor *= 100.0; lastnull++; } if (d2) { if (lastnull) { ndigs += lastnull; lastnull = 0; } d2 = d->digits[ix] / 256; value = value + ((double)d2 * factor); factor *= 100.0; ndigs++; lastnull = 0; } else lastnull++; } if (d->exp_sgn == (char)-1) value = ((value / (d->exponent * 100.0)) / ((double)ndigs * 100.0)); else value = ((value * (d->exponent * 100.0)) / ((double)ndigs * 100.0)); return; } void rdt_to_str( char *str, t_types *t, char *p ) { int strt, end, ndigs, len, ddigs; int year, month, day, hour, minute, second, fraction, multi; int index = 1 /* 0 is exponent */, tmp, i, parts[9], part = 0; time_t tim; char fmt[100]; strt = t->optn.dtim.start; end = t->optn.dtim.end; ndigs = end - strt + (strt == TU_YEAR?4:2); fmt[0] = (char)0; if (strt == TU_YEAR) { year = 0; for (i=0; i<2; i++) year = year * 100 + (long)p[index++]; if (end > TU_YEAR) strcat( fmt, "%0.4d-" ); else strcat( fmt, "%0.4d" ); parts[part++] = year; } else { year = 0; } if (strt <= TU_MONTH && end >= TU_MONTH) { month = ((long)p[index++]); if (end > TU_MONTH) strcat( fmt, "%0.2d-" ); else strcat( fmt, "%0.2d" ); parts[part++] = month; } else { month = 0; } if (strt <= TU_DAY && end >= TU_DAY) { day = ((long)p[index++]); if (end > TU_DAY) strcat( fmt, "%0.2d " ); else strcat( fmt, "%0.2d" ); parts[part++] = day; } else { day = 0; } if (strt <= TU_HOUR && end >= TU_HOUR) { hour = ((long)p[index++]); if (end > TU_HOUR) strcat( fmt, "%0.2d:" ); else strcat( fmt, "%0.2d" ); parts[part++] = hour; } else { hour = 0; } if (strt <= TU_MINUTE && end >= TU_MINUTE) { minute = ((long)p[index++]); if (end > TU_MINUTE) strcat( fmt, "%0.2d:" ); else strcat( fmt, "%0.2d" ); parts[part++] = minute; } else { minute = 0; } if (strt <= TU_SECOND && end >= TU_SECOND) { second = ((long)p[index++]); if (end > TU_SECOND) strcat( fmt, "%0.2d." ); else strcat( fmt, "%0.2d" ); parts[part++] = second; } else { second = 0; } ddigs = 0; if (end >= TU_F1) { switch (end) { case TU_F5: fraction = (long)p[index++]; fraction = fraction * 100 + (long)p[index++]; fraction = fraction * 100 + (long)p[index++]; multi = 1; ddigs = 5; break; case TU_F4: ddigs = 4; case TU_F3: fraction = (long)p[index++]; fraction = fraction * 100 + (long)p[index++]; multi = 100; if (!ddigs) ddigs = 3; break; case TU_F2: ddigs = 2; case TU_F1: fraction = (long)p[index++]; multi = 10000; if (!ddigs) ddigs = 1; break; } parts[part++] = ddigs; parts[part++] = fraction; strcat( fmt, "%0.*d" ); } else fraction = 0; sprintf( str, fmt, parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8] ); } void rint_to_str( char *str, t_types *t, char *p ) { int strt, end, ndigs, len, ddigs, scale; int year, month, day, hour, minute, second, fraction, multi; int index = 1, tmp, i, parts[10], part = 0; time_t tim; char fmt[100]; strt = t->optn.intv.start; end = t->optn.intv.end; scale = ((long)p[0] & 0x7F) - 64; ndigs = (t->optn.intv.len + 1) / 2; fmt[0] = (char)0; if (strt == TU_YEAR) { year = 0; while (ndigs-- && scale--) year = year * 100 + (long)p[index++]; if (end > TU_YEAR) strcat( fmt, "%1.*d-" ); else strcat( fmt, "%1.*d" ); parts[part++] = ndigs; parts[part++] = year; } else { year = 0; } if (strt == TU_MONTH) { month = 0; while (ndigs-- && scale--) month = month * 100 + (long)p[index++]; parts[part++] = month; if (end > TU_MONTH) strcat( fmt, "%0.*d-" ); else strcat( fmt, "%0.*d" ); } else if (strt < TU_MONTH && end >= TU_MONTH) { month = ((long)p[index++]); if (end > TU_MONTH) strcat( fmt, "%0.*d-" ); else strcat( fmt, "%0.*d" ); parts[part++] = month; } else { month = 0; } if (strt == TU_DAY) { day = 0; while (ndigs-- && scale--) day = day * 100 + (long)p[index++]; if (end > TU_DAY) strcat( fmt, "%0.*d " ); else strcat( fmt, "%0.*d" ); parts[part++] = day; } else if (strt < TU_DAY && end >= TU_DAY) { day = ((long)p[index++]); if (end > TU_DAY) strcat( fmt, "%0.*d " ); else strcat( fmt, "%0.*d" ); parts[part++] = day; } else { day = 0; } if (strt == TU_HOUR) { hour = 0; while (ndigs-- && scale--) hour = hour * 100 + (long)p[index++]; if (end > TU_HOUR) strcat( fmt, "%0.*d:" ); else strcat( fmt, "%0.*d" ); parts[part++] = hour; } else if (strt < TU_HOUR && end >= TU_HOUR) { hour = ((long)p[index++]); if (end > TU_HOUR) strcat( fmt, "%0.*d:" ); else strcat( fmt, "%0.*d" ); parts[part++] = hour; } else { hour = 0; } if (strt == TU_MINUTE) { minute = 0; while (ndigs-- && scale--) minute = minute * 100 + (long)p[index++]; if (end > TU_MINUTE) strcat( fmt, "%0.*d:" ); else strcat( fmt, "%0.*d" ); parts[part++] = minute; } else if (strt < TU_MINUTE && end >= TU_MINUTE) { minute = ((long)p[index++]); if (end > TU_MINUTE) strcat( fmt, "%0.*d:" ); else strcat( fmt, "%0.*d" ); parts[part++] = minute; } else { minute = 0; } if (strt == TU_SECOND) { second = 0; while (ndigs-- && scale--) second = second * 100 + (long)p[index++]; if (end > TU_SECOND) strcat( fmt, "%0.*d." ); else strcat( fmt, "%0.*d" ); parts[part++] = second; } else if (strt < TU_SECOND && end >= TU_SECOND) { second = ((long)p[index++]); if (end > TU_SECOND) strcat( fmt, "%0.*d." ); else strcat( fmt, "%0.*d" ); parts[part++] = second; } else { second = 0; } ddigs = 0; if (end >= TU_F1) { switch (end) { case TU_F5: fraction = (long)p[index++]; fraction = fraction * 100 + (long)p[index++]; fraction = fraction * 100 + (long)p[index++]; multi = 1; ddigs = 5; break; case TU_F4: ddigs = 4; case TU_F3: fraction = (long)p[index++]; fraction = fraction * 100 + (long)p[index++]; multi = 100; if (!ddigs) ddigs = 3; break; case TU_F2: ddigs = 2; case TU_F1: fraction = (long)p[index++]; multi = 10000; if (!ddigs) ddigs = 1; break; } parts[part++] = fraction; parts[part++] = ddigs; strcat( fmt, "%0.*d" ); } else fraction = 0; sprintf( str, fmt, parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9] ); } MKSHAR_EOF