int main(int argc, char *argv[]) { DistillerStatus st; UINT32 len; Argument args[12]; int nargs = 0; gm_Bool bool; int i; char *k; FILE *f; char nextfile[255]; DistillerInput in; DistillerOutput out; C_DistillerType distType; sprintf(distType.string, "test image/gif"); if ((argc < 2) || (argc >= 2 && strncmp(argv[1], "-h", 2) == 0)) { usage(); exit(1); } if ((f = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "Can't open input file %s\n", argv[1]); exit(1); } for (i=2; i<argc-1; i += 2, nargs++) { SET_ARG_ID(args[nargs], strtoul(argv[i], (char**)NULL, 0)); if (isdigit(*argv[i+1])) { SET_ARG_INT(args[nargs], strtol(argv[i+1], (char**)NULL, 0)); fprintf(stderr, "Arg id %lu is %ld\n", ARG_ID(args[nargs]), ARG_INT(args[nargs])); } else { SET_ARG_STRING(args[nargs], argv[i+1]); fprintf(stderr, "Arg id %lu is \"%s\"\n", ARG_ID(args[nargs]), ARG_STRING(args[nargs])); } } if ((st = DistillerInit(distType)) != distOk) { fprintf(stderr, "DistillerInit failed: error %d\n", (int)st); exit(1); } strcpy(in.mimeType, "image/gif"); while (fgets(nextfile, 254, f) != NULL) { char nextfile2[255]; int fd; int count; nextfile[strlen(nextfile)-1] = 0; fd = open(nextfile, O_RDONLY); if (fd == -1) { fprintf(stderr, "Can't read %s, skipping\n", nextfile); continue; } for (len = 0; (count = read(fd, (void*)(buf+len), (sizeof(buf)-len))) > 0; len += count) ; fprintf(stderr, "Read %lu bytes from %s\n", len, nextfile); in.data = (void *)buf; in.length = len; fprintf(stderr,"Calling distiller main\n"); st = DistillerMain(args,nargs,&in,&out,&bool); if (st != distOk) { fprintf(stderr, "DistillerMain failed: error %d\n", (int)st); } close(fd); strcpy(nextfile2, argv[argc-1]); if (nextfile2[strlen(nextfile2)-1] != '/') strcat(nextfile2,"/"); k = strrchr(nextfile, '/'); if (k) strcat(nextfile2, k+1); else strcat(nextfile2, nextfile); strcat(nextfile2, ".OUT"); fd = open(nextfile2, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (fd == -1) { fprintf(stderr, "Can't write %s, using stdout\n", nextfile2); fd = fileno(stdout); } len = write(fd, (const void *)out.data, (size_t)out.length); if (fd != fileno(stdout)) close(fd); fprintf(stderr, "Wrote %lu of %lu bytes to %s\n", len, out.length, nextfile2); if (bool) DistillerFree(out.data); } }
void * http_go_proc(task_t *t) { int index = TASK_THRINDEX(t); Request h; ArgumentList prefs; userkey k; HTTP_Status result; DistillerStatus dist_result; const char *content_type; Argument *arg; int thresh; gm_Bool no_distill = gm_False; gm_Bool is_text_html = gm_False; #ifdef LOGGING struct loginfo lo; char logmsg[MAX_LOGMSG_LEN]; #endif /* LOGGING */ /* * New task data should be the request structure. */ init_Request(&h); h.cli_fd = (int)TASK_DATA(t); /* socket FD of client */ SET_TASK_DATA(t,&h); INST_begin_timestamp(index); INST_set_size(index,0); INST_set_thread_state(index, THR_ACCEPTED); INST_timestamp(index, m_arrival); #ifdef LOGGING LOGGING_init_loginfo(&lo); h.lo = &lo; #endif /* LOGGING */ /* * this should read all the headers. */ if (TASK_METADATA(t) == NULL) { int result; assert( DistillerBufferAlloc(&h.cli_hdrs, PERF_HTTP_TOTAL_HEADERLEN) == gm_True); result = readline_or_timeout(&h, READ_ALL_HEADERS, NULL); INST_timestamp(index, m_headersdone); if (result == -1) { /* client request timed out, or error reading hdrs */ /* TC::1 client timeout, or request doesn't sanity check */ goto HTTPGO_FINISH; /* NOTREACHED */ } } else { #ifdef NEWFE /* * This task is a child of a previous */ strncpy(h.cli_hdrs.mime_headers, TASK_METADATA(t), PERF_HTTP_TOTAL_HEADERLEN-1); FREE(TASK_METADATA(t)); #endif /* NEWFE */ } /* parse the headers and request line, filling them in to the loginfo */ result = parse_status_and_headers(&h); if (result != HTTP_NO_ERR) { /* BUG:: last arg of http_error_return should be a substitution arg */ /* TC::2 parse_status_and_headers returns an error */ http_error_return(&h, result); printf("Error occured here!\n"); goto HTTPGO_FINISH; } /* * We have a reasonable looking request. Get prefs for this user. */ k = userkey_from_sock_ipaddr(h.cli_fd); #ifdef LOGGING lo.ipaddr = k; #endif /* LOGGING */ (void)get_userprefs(k, &prefs); /* * Extract any arguments embedded in the URL itself, and add them * to the arg list. * TC::3 url is magic vs nonmagic */ if (is_magic ((char *) h.url)) { /* demagifying a url will never lengthen it so this is a good * upper bounds on the length of the non magical url */ char *demagicURL = ALLOCA(strlen(h.url)+1); assert(demagicURL); strcpy(demagicURL, h.url); from_magic((char *) demagicURL, h.url, &prefs); } /* determine the threshold for bypassing */ arg = getArgumentFromIdInList(&prefs, FRONT_MTU); thresh = (arg == NULL ? PERF_FRONT_MTU : ARG_INT(*arg)); /* determine if distillation is turned off for this * request. EXCEPTION: Force distillation for Prefs html form. */ arg = getArgumentFromIdInList(&prefs, FRONT_NO_DISTILL); if (arg != NULL && ARG_INT(*arg) && strcasecmp(fe_get_prefs_url, h.url) != 0) { /* TC::4 no_distill is set */ no_distill = gm_True; } else { no_distill = gm_False; } /* Short-circuit the following special URL's: * - "set my prefs as follows" (e.g. form submission) */ if (is_setpref_url(h.url)) { /* * handle what send user prefs form sends back. * TC::5 is_setpref_url returns true */ result = parse_and_change_prefs(h.url, k, h.errmsg); if (result == HTTP_NO_ERR) { /* TC::5.1 setpref url succeeds in setting prefs */ correct_write(h.cli_fd, "HTTP/1.0 200\r\nContent-type: text/html\r\n\r\n", -1); correct_write(h.cli_fd, "<html><head><title>Preferences Set</title></head>" "<body><center><h1>Preferences set</h1>" "Your new preferences have been set. Press the back " "button twice to resume browsing." "<p></center></body></html>", -1); } else { /* TC::5.2 setpref url fails in setting prefs */ http_error_return(&h, result); } } else if (is_getpref_url(h.url)) { /* TC::6 gimme my prefs*/ send_prefs(&prefs, h.cli_fd); } else if (is_server_url(h.url)==gm_False && strcasecmp(h.method, "get") != 0 && strcasecmp(h.method, "post") != 0) { /* * Doesn't appear to be an HTTP GET or POST request; so act as a * "dumb tunnel" for passing the request to the server (actually, via * the cache) and relaying the result to the client. */ /* TC::7 tunnel */ proxy_debug_3(DBG_HTTP, "Tunneling '%s'", DistillerBufferData(&h.cli_hdrs)); INST_set_thread_state(index, THR_DISTILLERSEND); tunnel(&h); } else { /* * It's not a special URL, and the request appears to be a GET/POST. * Add in the client's IP address as an INT32 argument so that * the distiller driver can get at it. */ SET_ARG_INT(prefs.arg[prefs.nargs], (INT32) k); SET_ARG_ID(prefs.arg[prefs.nargs], FRONT_CLIENT_IP); prefs.nargs++; result = server_dispatch(&prefs, t); /* * If we get a transport-level error (i.e. fetch from cache failed * due to an internal cache error), wrap the error in HTML (if * needed) and return error to user. * Otherwise, if the transaction succeeded but the server return * code indicates failure (i.e. != 200), **OR** if the server data * is smaller than a threshold size, bypass the server data * directly to the client. * Otherwise, attempt to distill. */ if (result != HTTP_NO_ERR) { /* transport level error: wrap in HTML for delivery to user */ /* TC::8 server_dispatch returns transport level error */ http_error_return(&h, result); goto HTTPGO_FINISH; } content_type = get_header_value(&h.svr_hdrs, "content-type", NULL, NULL, NULL); if (content_type == NULL) { /* TC::9 content-type can't be deduced */ content_type = "application/octet-stream"; } is_text_html = ( ((strncasecmp(content_type, "text/html", 9) == 0) || (strncasecmp(content_type, "text/plain", 10) == 0)) ? gm_True : gm_False); /*if ( (*h.url != '/' && strncasecmp(h.url, fe_agg_string, strlen(fe_agg_string)) != 0) &&*/ /* bypass ONLY if it is not a server-type URL */ /* TC::10.1 bypass because non-200s status */ /* TC::10.2 bypass because not text/html and too small to distill */ /* TC::4 bypass because no_distill is set */ /* bypass server data directly to user */ if ( is_server_url(h.url)==gm_False) { char *bypass_reason = NULL; if (h.svr_http_status != 200) { bypass_reason = "201 Non-OK server status"; } else if (is_text_html == gm_False && DistillerBufferLength(&h.svr_data) <= thresh) { bypass_reason = "202 content-type not text/html and content-length too short"; } else if (no_distill == gm_True) { bypass_reason = "203 distillation not indicated"; } if (bypass_reason) { INST_set_thread_state(index, THR_WRITEBACK); /* * Set return headers to indicate why the bypass occurred. */ insert_header(&h.svr_hdrs, TRANSEND_STATUS_HEADER, bypass_reason, 0); complete_bypass(&h); goto HTTPGO_FINISH; } } /* all is well: continue by dispatching to a worker for distillation */ dist_result = proxy_dispatch(&prefs, t); switch(dist_result) { case distOk: /* TC::11 distillation succeeded */ INST_timestamp(index, m_wbstart); insert_header(&h.pxy_hdrs, TRANSEND_STATUS_HEADER, "200 distillation OK", 0); correct_write(h.cli_fd, (char *)DistillerBufferData(&h.pxy_hdrs), (int)DistillerBufferLength(&h.pxy_hdrs)); /* -1 to avoid NULL term gunk */ correct_write(h.cli_fd, (char *)DistillerBufferData(&h.pxy_data), (int)DistillerBufferLength(&h.pxy_data)); INST_timestamp(thrindex, m_wbdone); break; case distDistillerNotFound: case distLaunchTimeout: case distBadInput: case distConnectionBroken: /* forward original if distiller for this type not found, connection repeatedly broken, or couldn't be launched */ /* TC::12 bypass because distillation failed */ insert_header(&h.svr_hdrs, (dist_result == distBadInput ? TRANSEND_STATUS_HEADER : TRANSEND_ERROR_HEADER), FE_getDistillerStatusString(dist_result), 0); if ((arg = getArgumentFromIdInList(&prefs, FRONT_DEVELOPER)) && ARG_INT(*arg)) { /* return explicit error message */ int tmp_len = snprintf(h.errmsg, HTTP_ERRMSG_MAX, "<i>[set arg <tt>i%d</tt> to 0 to suppress " "this diagnostic]</i><br>", FRONT_DEVELOPER); strncat(h.errmsg, FE_getDistillerStatusString(dist_result), HTTP_ERRMSG_MAX - tmp_len - 1); http_error_return(&h, HTTP_ERR_UNSPECIFIED); } else { /*if (*h.url == '/' || strncasecmp(h.url, fe_agg_string, strlen(fe_agg_string)) == 0) {*/ if (is_server_url(h.url)==gm_True) { /* this is a URL in the frontend's namespace, or an aggregator URL */ strcpy(h.errmsg, h.url); http_error_return(&h, HTTP_ERR_AGGREGATOR_ERROR); } else { complete_bypass(&h); } } break; case distRedispatch: /* * Redispatch count expired: too many redispatches (probably indicates * infinite loop in redispatch route.) */ snprintf(h.errmsg, HTTP_ERRMSG_MAX, "%d", PERF_REQUEST_TTL); http_error_return(&h, HTTP_ERR_ROUTING_ERROR); break; default: /* TC::13 some other distillation error */ insert_header(&h.svr_hdrs, TRANSEND_STATUS_HEADER, FE_getDistillerStatusString(dist_result), 0); http_error_return(&h, HTTP_ERR_UNSPECIFIED); break; } /* switch(dist_result) */ } /* if...else...else...endif */ /* all cases exit through this single exit point */ HTTPGO_FINISH: free_Request(&h); INST_timestamp(index, m_wbdone); INST_end_timestamp(index); if (TASK_PARENT(t) == 0 && TASK_CHILD_INDEX(t) == 0) { /* this is a "root task" */ close(h.cli_fd); } #ifdef LOGGING /* log the request info */ /* BUG::relies on formatting of the userkey */ /* I compare the IP address to 127.0.0.1 so that I don't log connections from localhost, namely the fe_check script. I also MD5 the IP address. */ k = lo.ipaddr; if (((UINT32) k) != ((UINT32) htonl(0x7F000001))) { /* MD5_CTX theHash; UINT32 res; MD5Init(&theHash); MD5Update(&theHash, magicKey, sizeof(magicKey)); MD5Update(&theHash, &k, sizeof(UINT32)); MD5Final(&theHash); memcpy(&res, theHash.digest, sizeof(UINT32)); res = ntohl(res); snprintf(logmsg, MAX_LOGMSG_LEN-1, "(HTTP) %lu %lu \"%s\" %d %ld %ld\n", res, lo.date, lo.url, lo.http_response, lo.size_before, lo.size_after);*/ snprintf(logmsg, MAX_LOGMSG_LEN-1, "(HTTP) %08x %08x \"%s\" %d %ld %ld\n", (UINT32) k, lo.date, lo.url, lo.http_response, lo.size_before, lo.size_after); gm_log(logmsg); } #endif /* LOGGING */ return (void *)0; }
void format (struct obstack *obs, int argc, token_data **argv) { #ifdef HAVE_EFGCVT const char *fmt; /* format control string */ int c; /* a simple character */ char fc; /* format code */ /* Flags. */ char flags; /* 1 iff treating flags */ char ljust; /* left justification */ char mandsign; /* mandatory sign */ char noplus; /* use space if no sign */ char alternate; /* use alternate form */ char zeropad; /* do zero padding */ char plus; /* plus-sign, according to mandatory and noplus */ /* Precision specifiers. */ int width; /* minimum field width */ int prec; /* precision */ int maxch; /* maximum no. of chars to print */ char lflag; /* long flag */ char hflag; /* short flag */ /* Different parts of each specification. */ char sign; /* wanted sign, iff any */ int ppad; /* pre-prefix zero padding */ const char *prefix; /* value prefix */ int lpad; /* zero padding on the left */ register char *s; /* ptr to formatted text */ int rpad; /* zero padding on the rigth*/ const char *suffix; /* value suffix */ /* Buffer and stuff. */ char str[MAXFIELD]; /* buffer for formatted text */ int length; /* length of str */ int padding; /* padding at the left or rigth */ register int i; /* an index */ /* Length of trailing string in str. */ #define LENGTH(s) (&str[MAXFIELD-1] - (s)) #define HAS_SIGN (sign != '\0') fmt = ARG_STR (argc, argv); for (;;) { while ((c = *fmt++) != '%') { if (c == 0) return; obstack_1grow (obs, c); } if (*fmt == '%') { obstack_1grow (obs, '%'); fmt++; continue; } /* Parse flags. */ flags = 1; ljust = mandsign = noplus = alternate = zeropad = 0; do { switch (*fmt) { case '-': /* left justification */ ljust = 1; break; case '+': /* mandatory sign */ mandsign = 1; break; case ' ': /* space instead of positive sign */ noplus = 1; break; case '0': /* zero padding */ zeropad = 1; break; case '#': /* alternate output */ alternate = 1; break; default: flags = 0; break; } } while (flags && fmt++); plus = '\0'; /* what to use as a plus ??? */ if (mandsign) plus = '+'; else if (noplus) plus = ' '; if (ljust) zeropad = 0; /* Minimum field width. */ width = -1; if (*fmt == '*') { width = ARG_INT (argc, argv); fmt++; } else if (isdigit (*fmt)) { width = 0; do { width = width * 10 + *fmt++ - '0'; } while (isdigit (*fmt)); } /* Maximum precision. */ prec = -1; if (*fmt == '.') { if (*(++fmt) == '*') { prec = ARG_INT (argc, argv); ++fmt; } else if (isdigit (*fmt)) { prec = 0; do { prec = prec * 10 + *fmt++ - '0'; } while (isdigit (*fmt)) ; } } /* Length modifiers. */ lflag = (*fmt == 'l'); hflag = (*fmt == 'h'); if (lflag || hflag) fmt++; sign = '\0'; ppad = lpad = rpad = 0; maxch = -1; prefix = suffix = ""; switch (fc = *fmt++) { case '\0': return; case 'c': c = ARG_INT (argc, argv); str[0] = (unsigned char) c; str[1] = '\0'; s = str; break; case 's': s = ARG_STR (argc, argv); maxch = prec; break; case 'd': case 'i': if (lflag) { long val = ARG_LONG (argc, argv); if (val < 0) { val = -val; /* does not work for MINLONG */ sign = '-'; } else sign = plus; s = ulong_to_str ((unsigned long) val, str, 10, digits); } else { int val = ARG_INT (argc, argv); if (hflag) val = (short) val; if (val < 0) { val = -val; /* does not work for MININT */ sign = '-'; } else sign = plus; s = ulong_to_str ((unsigned long) val, str, 10, digits); } if (zeropad) lpad = width - LENGTH (s) - HAS_SIGN; break; case 'o': if (lflag) { unsigned long val = ARG_ULONG (argc, argv); s = ulong_to_str ((unsigned long) val, str, 8, digits); } else { unsigned int val = ARG_UINT (argc, argv); if (hflag) val = (unsigned short) val; s = ulong_to_str ((unsigned long) val, str, 8, digits); } if (alternate) prefix = "0"; if (zeropad) lpad = width - LENGTH (s) - alternate; break; case 'x': case 'X': if (lflag) { unsigned long val = ARG_ULONG (argc, argv); s = ulong_to_str ((unsigned long) val, str, 16, (fc == 'x') ? digits : Digits); } else { unsigned int val = ARG_UINT (argc, argv); if (hflag) val = (unsigned short) val; s = ulong_to_str ((unsigned long) val, str, 16, (fc == 'x') ? digits : Digits); } if (alternate) prefix = (fc == 'X') ? "0X" : "0x"; if (zeropad) lpad = width - LENGTH (s) - 2*alternate; break; case 'u': if (lflag) { unsigned long val = ARG_ULONG (argc, argv); s = ulong_to_str ((unsigned long) val, str, 10, digits); } else { unsigned int val = ARG_UINT (argc, argv); if (hflag) val = (unsigned short) val; s = ulong_to_str ((unsigned long) val, str, 10, digits); } if (zeropad) lpad = width - LENGTH (s); break; case 'e': case 'E': { char *t; int sgn, decpt, exp, n; double val = ARG_DOUBLE (argc, argv); if (prec < 0) prec = 6; t = clr0 (ecvt (val, min (prec + 1, ECVTMAX), &decpt, &sgn)); sign = sgn ? '-' : plus; n = prec; s = str; exp = (t[0] == '0' && t[1] == '\0') ? 0 : decpt - 1; *s++ = *t++; if (n > 0 || alternate) *s++ = '.'; while (*t != '\0' && --n >= 0) *s++ = *t++; *s = '\0'; rpad = n; sgn = 0; if (exp < 0) { exp = -exp; sgn = 1; } t = ulong_to_str ((unsigned long) exp, str, 10, digits); if (exp < 10) *--t = '0'; /* always at least two digits */ *--t = sgn ? '-' : '+'; *--t = fc; if (zeropad) { lpad = width - HAS_SIGN - (s - str) - LENGTH (t); if (rpad > 0) lpad -= rpad; } suffix = t; s = str; } break; case 'f': { const char *t; int sgn, decpt, n; double val = ARG_DOUBLE (argc, argv); if (prec < 0) prec = 6; /* FIXME: For the following line, Dave Anglin reports ``warning: passing arg 1 of `clr0' discards `const' from pointer target type''. I suspect fcvt might be declared as returning const on some systems. Pouah! I should revise this whole module, one of these days... */ t = clr0 (fcvt (val, min (prec, FCVTMAX), &decpt, &sgn)); sign = sgn ? '-' : plus; n = prec; s = str; if (decpt <= 0) { prefix = (n > 0 || alternate) ? "0." : "0"; lpad = min (-decpt, prec); n -= lpad; } else { while (--decpt >= 0) *s++ = *t++; if (n > 0 || alternate) *s++ = '.'; } while (*t && --n >= 0) *s++ = *t++; *s = '\0'; rpad = n; if (zeropad) ppad = width - HAS_SIGN - (prefix[1] ? 2 : 1) - lpad - (s - str) - rpad; s = str; } break; default: continue; } if (lpad < 0) lpad = 0; if (rpad < 0) rpad = 0; if (width < 0) width = 0; i = strlen (s); if (maxch <= 0 || maxch > i) maxch = i; length = (HAS_SIGN + ppad + strlen (prefix) + lpad + maxch + rpad + strlen (suffix)); padding = 0; if (width != 0) { padding = width - length; } if (ljust == 0) /* left padding */ for (i = padding; --i >= 0;) obstack_1grow (obs, ' '); if (HAS_SIGN) /* sign */ obstack_1grow (obs, sign); for (i = ppad; --i >= 0;) /* pre-prefix zero padding */ obstack_1grow (obs, '0'); for (; *prefix; ++prefix) /* prefix */ obstack_1grow (obs, *prefix); for (i = lpad; --i >= 0;) /* left zero padding */ obstack_1grow (obs, '0'); for (i = maxch; --i >= 0; ++s) /* actual text */ obstack_1grow (obs, *s); for (i = rpad; --i >= 0;) /* right zero padding */ obstack_1grow (obs, '0'); for (; *suffix; ++suffix) /* suffix */ obstack_1grow (obs, *suffix); if (ljust != 0) /* right padding */ for (i = padding; --i >= 0;) obstack_1grow (obs, ' '); } #else /* not HAVE_EFGCVT */ char *fmt; /* format control string */ const char *fstart; /* beginning of current format spec */ int c; /* a simple character */ /* Flags. */ char flags; /* 1 iff treating flags */ /* Precision specifiers. */ int width; /* minimum field width */ int prec; /* precision */ char lflag; /* long flag */ char hflag; /* short flag */ /* Buffer and stuff. */ char str[256]; /* buffer for formatted text */ enum {INT, UINT, LONG, ULONG, DOUBLE, STR} datatype; fmt = ARG_STR (argc, argv); for (;;) { while ((c = *fmt++) != '%') { if (c == 0) return; obstack_1grow (obs, c); } fstart = fmt - 1; if (*fmt == '%') { obstack_1grow (obs, '%'); fmt++; continue; } /* Parse flags. */ flags = 1; do { switch (*fmt) { case '-': /* left justification */ case '+': /* mandatory sign */ case ' ': /* space instead of positive sign */ case '0': /* zero padding */ case '#': /* alternate output */ break; default: flags = 0; break; } } while (flags && fmt++); /* Minimum field width. */ width = -1; if (*fmt == '*') { width = ARG_INT (argc, argv); fmt++; } else if (isdigit (*fmt)) { do { fmt++; } while (isdigit (*fmt)); } /* Maximum precision. */ prec = -1; if (*fmt == '.') { if (*(++fmt) == '*') { prec = ARG_INT (argc, argv); ++fmt; } else if (isdigit (*fmt)) { do { fmt++; } while (isdigit (*fmt)); } } /* Length modifiers. */ lflag = (*fmt == 'l'); hflag = (*fmt == 'h'); if (lflag || hflag) fmt++; switch (*fmt++) { case '\0': return; case 'c': datatype = INT; break; case 's': datatype = STR; break; case 'd': case 'i': if (lflag) { datatype = LONG; } else { datatype = INT; } break; case 'o': case 'x': case 'X': case 'u': if (lflag) { datatype = ULONG; } else { datatype = UINT; } break; case 'e': case 'E': case 'f': datatype = DOUBLE; break; default: continue; } c = *fmt; *fmt = '\0'; switch(datatype) { case INT: if (width != -1 && prec != -1) sprintf (str, fstart, width, prec, ARG_INT(argc, argv)); else if (width != -1) sprintf (str, fstart, width, ARG_INT(argc, argv)); else if (prec != -1) sprintf (str, fstart, prec, ARG_INT(argc, argv)); else sprintf (str, fstart, ARG_INT(argc, argv)); break; case UINT: if (width != -1 && prec != -1) sprintf (str, fstart, width, prec, ARG_UINT(argc, argv)); else if (width != -1) sprintf (str, fstart, width, ARG_UINT(argc, argv)); else if (prec != -1) sprintf (str, fstart, prec, ARG_UINT(argc, argv)); else sprintf (str, fstart, ARG_UINT(argc, argv)); break; case LONG: if (width != -1 && prec != -1) sprintf (str, fstart, width, prec, ARG_LONG(argc, argv)); else if (width != -1) sprintf (str, fstart, width, ARG_LONG(argc, argv)); else if (prec != -1) sprintf (str, fstart, prec, ARG_LONG(argc, argv)); else sprintf (str, fstart, ARG_LONG(argc, argv)); break; case ULONG: if (width != -1 && prec != -1) sprintf (str, fstart, width, prec, ARG_ULONG(argc, argv)); else if (width != -1) sprintf (str, fstart, width, ARG_ULONG(argc, argv)); else if (prec != -1) sprintf (str, fstart, prec, ARG_ULONG(argc, argv)); else sprintf (str, fstart, ARG_ULONG(argc, argv)); break; case DOUBLE: if (width != -1 && prec != -1) sprintf (str, fstart, width, prec, ARG_DOUBLE(argc, argv)); else if (width != -1) sprintf (str, fstart, width, ARG_DOUBLE(argc, argv)); else if (prec != -1) sprintf (str, fstart, prec, ARG_DOUBLE(argc, argv)); else sprintf (str, fstart, ARG_DOUBLE(argc, argv)); break; case STR: if (width != -1 && prec != -1) sprintf (str, fstart, width, prec, ARG_STR(argc, argv)); else if (width != -1) sprintf (str, fstart, width, ARG_STR(argc, argv)); else if (prec != -1) sprintf (str, fstart, prec, ARG_STR(argc, argv)); else sprintf (str, fstart, ARG_STR(argc, argv)); break; } *fmt = c; obstack_grow (obs, str, strlen (str)); } #endif /* not HAVE_EFGCVT */ }
int main(int argc, char *argv[]) { DistillerStatus st; UINT32 len; Argument args[12]; int nargs = 0; int i; char *k; FILE *f; char nextfile[255]; DistillerInput in; DistillerOutput out; C_DistillerType distType; sprintf(distType.string, "test " INPUT_MIME_TYPE); if ((argc < 2) || (argc >= 2 && strncmp(argv[1], "-h", 2) == 0)) { usage(); exit(1); } if ((f = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "Can't open input file %s\n", argv[1]); exit(1); } for (i=2; i<argc-1; i += 2, nargs++) { SET_ARG_ID(args[nargs], strtoul(&argv[i][1], (char**)NULL, 0)); switch (argv[i][0]) { case 'i': SET_ARG_INT(args[nargs], strtol(argv[i+1], (char**)NULL, 0)); fprintf(stderr, "Arg id %lu is %ld\n", ARG_ID(args[nargs]), ARG_INT(args[nargs])); break; case 'f': SET_ARG_DOUBLE(args[nargs], strtod(argv[i+1], (char**)NULL)); fprintf(stderr, "Arg id %lu is %f\n", ARG_ID(args[nargs]), (float)ARG_DOUBLE(args[nargs])); break; case 's': default: SET_ARG_STRING(args[nargs], argv[i+1]); fprintf(stderr, "Arg id %lu is \"%s\"\n", ARG_ID(args[nargs]), ARG_STRING(args[nargs])); } } if ((st = DistillerInit(distType, 0, NULL)) != distOk) { fprintf(stderr, "DistillerInit failed: error %d\n", (int)st); exit(1); } SetMimeType(&in, INPUT_MIME_TYPE); while (fgets(nextfile, 254, f) != NULL) { char nextfile2[255]; int fd; int count; int ii; nextfile[strlen(nextfile)-1] = 0; fd = open(nextfile, O_RDONLY); if (fd == -1) { fprintf(stderr, "Can't read %s, skipping\n", nextfile); continue; } for (len = 0; (count = read(fd, (void*)(buf+len), (sizeof(buf)-len))) > 0; len += count) ; fprintf(stderr, "Read %lu bytes from %s\n", len, nextfile); SetData(&in, (void *)buf); SetDataLength(&in, len); SetMetadata(&in, NULL); SetMetadataLength(&in, 0); for (ii= 0; ii<REPEAT_COUNT; ii++) { fprintf(stderr,"Calling distiller main\n"); st = DistillerMain(args,nargs,&in,&out); if (st != distOk) { fprintf(stderr, "DistillerMain failed: error %d\n", (int)st); } close(fd); strcpy(nextfile2, argv[argc-1]); if (nextfile2[strlen(nextfile2)-1] != '/') strcat(nextfile2,"/"); k = strrchr(nextfile, '/'); if (k) strcat(nextfile2, k+1); else strcat(nextfile2, nextfile); strcat(nextfile2, ".OUT"); fd = open(nextfile2, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (fd == -1) { fprintf(stderr, "Can't write %s, using stdout\n", nextfile2); fd = fileno(stdout); } len = write(fd, (const void *)DataPtr(&out), (size_t)(DataLength(&out))); if (fd != fileno(stdout)) close(fd); fprintf(stderr, "Wrote %lu of %lu bytes to %s\n", len, DataLength(&out), nextfile2); if (out.data.freeMe == gm_True) DistillerFree(DataPtr(&out)); if (out.metadata.freeMe == gm_True) DistillerFree(MetadataPtr(&out)); } } return(1); }
DistillerStatus proxy_dispatch(ArgumentList *al, task_t *t) { DistillerStatus status; /* result of this pipe stage distillation */ DistillerInput din; DistillerOutput dout; Request *hp = (Request *)TASK_DATA(t); C_DistillerType dtype; int thrindex = TASK_THRINDEX(t); DistillerStatus retcode; int redispatch = 0; char *static_route = NULL; int static_route_initialized = 0; #ifdef LOGGING struct loginfo *lo = hp->lo; #endif /* * Initialize for *first* pipe stage. */ DistillerBufferClone(&din.data, &hp->svr_data); DistillerBufferFreeMe(&din.data, gm_True); /* * Make a **copy** of the server headers, because they may get * overwritten when preparing headers to send to a distiller. */ DistillerBufferClone(&din.metadata, &hp->svr_hdrs); DistillerBufferFreeMe(&din.metadata, gm_True); do { const char *char_tmp; char content_type[MIME_TYPE_MAX+1]; int content_type_len; Argument *arg; int num_tries_left; /* * Initialize for next pipe stage. */ status = distFatalError; #ifdef LOGGING /* * Log original content-length */ char_tmp = get_header_value(&din.metadata, "content-length", &content_type_len, NULL, NULL); if (char_tmp != NULL) lo->size_before = strtoul(char_tmp, NULL, 0); else lo->size_before = -1; #endif /* LOGGING */ char_tmp = get_header_value(&din.metadata, "content-type", &content_type_len, NULL, NULL); if (char_tmp != NULL) { strncpy(content_type, char_tmp, MIN(content_type_len+1, MIME_TYPE_MAX)); content_type[MIN(content_type_len,MIME_TYPE_MAX)] = '\0'; } else { content_type[0] = '\0'; } /* if there are attributes after the content-type, remove them. */ if ((char_tmp = strchr((const char *)content_type, ';')) != NULL) *(char *)char_tmp = '\0'; /* chop any trailing spaces. */ if ((char_tmp = strchr((const char *)content_type, ' ')) != NULL) *(char *)char_tmp = '\0'; /* * Distillation is definitely needed, so go do it. In case of * distConnectionBroken error, (re)try at most N * times, where N is the value of the FRONT_RETRY_DISTILL argument, * or PERF_HTTP_RETRY_DISTILL by default. In case of any other * error, or if all retries fail, bypass the original content. In * case of distOk (success), return the distilled content. */ arg = getArgumentFromIdInList(al, FRONT_RETRY_DISTILL); num_tries_left = (arg ? ARG_INT(*arg) : PERF_HTTP_RETRY_DISTILL); INST_timestamp(thrindex, m_distillstart); /* * Add a "Location:" header so distillers have a way to get the URL of * this document, if they want. */ if (get_header_value(&din.metadata, "location", NULL, NULL, NULL) == NULL) { insert_header(&din.metadata, "Location", hp->url, 0); } do { INST_set_thread_state(thrindex, THR_DISTILLER); status = do_distillation(hp->url, &din, &dout, &dtype, al); } while (status == distConnectionBroken && num_tries_left-- > 0); #ifdef LOGGING lo->size_after = -status; /* pessimistically assume failure for log */ #endif /* LOGGING */ switch(status) { case distOk: case distRedispatch: /* * The rules for redispatch are as follows. * - If the response headers contain a nonempty X-Static-Route header, it * is the final authority. X-Static-Route is only saved the * first time it's seen. * - Otherwise, if the response code is distRedispatch, use the * default rules to figure out who to go to next. * - Otherwise, the response is distOk --> just finish. */ if (! static_route_initialized && DistillerBufferLength(&dout.metadata) > 0) { /* look for X-Static-Route */ int tmp_len; const char *static_route_hdr = get_header_value(&dout.metadata, "x-static-route", &tmp_len, NULL, NULL); if (static_route_hdr != NULL && tmp_len > 0) { static_route = ALLOCA(tmp_len+1); strncpy(static_route, static_route_hdr, tmp_len); static_route[tmp_len] = '\0'; static_route_initialized = 1; delete_header(&dout.metadata, "x-static-route"); } } if (static_route || (status == distRedispatch && !static_route_initialized)) { /* * this is a redispatch. * The redispatch strategy is as follows. Since the * DistillerInput pointer starts out being a *clone* of the * server headers and data, it's always safe to free it. THen move the * DistillerOutput pointer (result of previous pipestage) to the * DistillerInput pointer of this pipestage. */ DistillerBufferFree(&din.metadata); DistillerBufferFree(&din.data); DistillerBufferClone(&din.metadata, &dout.metadata); DistillerBufferClone(&din.data, &dout.data); DistillerBufferFree(&dout.metadata); DistillerBufferFree(&dout.data); /* * Fix the content-length and content-type, if nec. */ if (get_header_value(&din.metadata, "content-type",NULL,NULL,NULL) == NULL) insert_header(&din.metadata, "Content-type", din.mimeType, 1); if (get_header_value(&din.metadata, "content-length", NULL,NULL,NULL) == NULL) { char __tmp[12]; snprintf(__tmp, 11, "%lu", DistillerBufferLength(&din.data)); insert_header(&din.metadata, "Content-length", __tmp, 1); } if (static_route) { status = distRedispatch; /* add the X-Route header to this request */ insert_header(&din.metadata, "X-Route", static_route, 1); /* scan forward to the next component of the path */ while (*static_route && (*static_route != ';')) { static_route++; } if (*static_route == '\0') { static_route = NULL; } else { /* skip semicolon and any spaces */ while (*static_route && ((*static_route == ';') || (*static_route == ' '))) { static_route++; } if (*static_route == '\0') static_route = NULL; } } redispatch++; t->task_age++; /* "time to live" of this request */ retcode = distRedispatch; } else { /* * Here if any of the following were true: * - status was distOk and no static route header overrides this * - status was distRedispatch, but an existing static route header * indicates that we should override and finish with */ #ifdef LOGGING lo->size_after = DistillerBufferLength(&dout.data); #endif /* LOGGING */ status = retcode = distOk; } break; default: /* some other distiller/ptm error */ /* * BUG::we shouldn't make this visible to the user unless the * "guru" argument is set */ snprintf(hp->errmsg, HTTP_ERRMSG_MAX, (char *)FE_getDistillerStatusString(status)); /* retcode = HTTP_ERR_DISTILLER; XXX - XXX - XXX - */ retcode = status; break; } /* switch(status) */ /* Note that the data size is set last. So if the data size is not zero, it's a reasonable indication that this is a compelte set of valid measurements. (should really have a separate valid bit) */ INST_set_size(thrindex, DistillerBufferLength(&dout.data)); } while ((status == distRedispatch) && t->task_age <= PERF_REQUEST_TTL); /* do */ /* * "Copy" final output buffer to hp->pxy_hdrs/hp->pxy_data. (Really * we just copy the pointers, since the pxy_hdrs/pxy_data buffers * will be freed by the caller.) * * First generate headers to return to client. If last-stage * distiller returned * some headers, use them; otherwise, replace the "content-length" * and "content-type" fields of the ORIGINAL server headers with * new values deduced from the distiller data. */ if (status == distOk) { if (DistillerBufferLength(&(dout.metadata)) > 0) { DistillerBufferClone(&hp->pxy_hdrs, &dout.metadata); } else { /* * If the server headers begin with an HTTP/x.x response code, they are * headers from an origin server; OK to clone them and just replace the * content-type and content-length. Otherwise, they are probably * the result of a server-mode dispatch worker, which means they * actually look like request headers (not response headers), so delete them. */ if (DistillerBufferLength(&hp->svr_hdrs) > 0 && strncasecmp(DistillerBufferData(&hp->svr_hdrs), "HTTP/", 5) == 0) { DistillerBufferClone(&hp->pxy_hdrs, &hp->svr_hdrs); delete_header(&hp->pxy_hdrs, "content-type"); delete_header(&hp->pxy_hdrs, "content-length"); } else { char *s = "HTTP/1.0 200 OK\r\n\r\n"; int l = strlen(s); DistillerBufferAlloc(&hp->pxy_hdrs, 1+l); strcpy((char *)(hp->pxy_hdrs.data), s); DistillerBufferSetLength(&hp->pxy_hdrs,l); } } /* * Replace the "Content-length" and "Content-type" * headers with the correct info. Leave other headers * alone. */ if (get_header_value(&hp->pxy_hdrs, "content-type", NULL,NULL,NULL) == NULL) { insert_header(&hp->pxy_hdrs, "Content-type", dout.mimeType, 1); } if (get_header_value(&hp->pxy_hdrs,"content-length",NULL,NULL,NULL) == NULL) { char __tmp[12]; snprintf(__tmp, 11, "%lu", DistillerBufferLength(&dout.data)); insert_header(&hp->pxy_hdrs, "Content-length", __tmp, 1); } DistillerBufferClone(&hp->pxy_data, &dout.data); } if ((status == distOk) || (status == distRedispatch)) { DistillerBufferFree(&dout.data); DistillerBufferFree(&dout.metadata); } /* Always free this */ DistillerBufferFree(&din.data); DistillerBufferFree(&din.metadata); /* BUG::must do Clib_Put here??? */ return (retcode); }
DistillerStatus DistillerMain(Argument *args, int nargs, DistillerInput *din, DistillerOutput *dout) { JSAMPROW handoff = NULL; JDIMENSION handoff_height, handoff_width, num_scanlines; int max_x=-1, max_y=-1, min_x=-1, min_y=-1, qual=55, i; int expert=0, resize=0, quality=3, nodistill=0, ismap=0; double scale = 0.5; cjpeg_source_ptr src_mgr; void *phase1_data; INT32 phase1_length; int fin_denom, fin_qual; DistillerStatus result = distBadInput; SetData(dout, NULL); bailout_now = 0; if ( (setjmp(jumpbuffer) != 0) ) { /* * fatal error occurred, so return immediately. */ MonitorClientSend(monID, "Distiller Errors", "Resetting distiller...\n", "Log"); DistillerExit(); DistillerInit(dType, 0, NULL); if (DataPtr(dout) != NULL) DataNeedsFree(dout,gm_True); else DataNeedsFree(dout,gm_False); return distFatalError; } /* * parse distillation arguments. set default values for some * things, then override them if args are specified. Default will * be to scale each axis by 0.5, turn quality down to 55%. */ for (i=0; i<nargs; i++) { INT32 argval = ARG_INT(args[i]); switch(ARG_ID(args[i])) { case GJPG_MAX_X: max_x = (int) argval; break; case GJPG_MAX_Y: max_y = (int) argval; break; case GJPG_MIN_X: min_x = (int) argval; break; case GJPG_MIN_Y: min_y = (int) argval; break; case GJPG_SCALE: scale = (double) ARG_DOUBLE(args[i]); break; case GJPG_QUAL: qual = (int) argval; break; case FRONT_RESIZE: resize = (int) argval; break; case FRONT_NO_DISTILL: nodistill = (int) argval; break; case FRONT_QUALITY: if (argval >= 1 && argval <= 5) quality = (int) argval; break; case FRONT_EXPERT: expert = (int) argval; break; case FRONT_ISMAP: ismap = (int) argval; break; default: break; } } if (nodistill) { return gjpg_passthrough(din, dout); } /* First pass through, we're just going to convert the GIF to JPEG */ phase1_data = NULL; phase1_length = 0; dstinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&dstinfo); src_mgr = jinit_read_gif(&dstinfo, (JOCTET *) DataPtr(din), (INT32) DataLength(din)); (*src_mgr->start_input)(&dstinfo, src_mgr); jpeg_default_colorspace(&dstinfo); jpeg_mem_dest(&dstinfo, (void **) &phase1_data, (UINT32 *) &phase1_length); jpeg_start_compress(&dstinfo, TRUE); while (dstinfo.next_scanline < dstinfo.image_height) { num_scanlines = (*src_mgr->get_pixel_rows)(&dstinfo, src_mgr); jpeg_write_scanlines(&dstinfo, src_mgr->buffer, num_scanlines); } (*src_mgr->finish_input)(&dstinfo, src_mgr); jpeg_finish_compress(&dstinfo); /* early bailout because of animated or transparent gif? */ if (bailout_now && DataLength(din) <= bailout_thresh[quality]) { result = distBadInput; goto JPGMUNGE_RETURN; } /* Now we're into the second pass. Let's do our JPEG->JPEG * distillation. We need to compute the denominator and the quality * knob setting. */ if (expert) { /* Do expert-like things here. Need to work out still. */ fin_qual = qual; fin_denom = compute_scale_denom(max_x, max_y, min_x, min_y, srcinfo.image_width, srcinfo.image_height, scale); } else { /* We're in beginner mode. Life is easier. */ if (ismap) { fin_qual = ismap_qual[quality-1]; fin_denom = ismap_denom[quality-1]; } else if (resize) { fin_qual = noscale_qual[quality-1]; fin_denom = noscale_denom[quality-1]; } else { fin_qual = norm_qual[quality-1]; fin_denom = norm_denom[quality-1]; } } /* Prep the input decompressor */ jpeg_mem_src(&srcinfo, phase1_data, phase1_length); jpeg_read_header(&srcinfo, TRUE); srcinfo.scale_num = 1; srcinfo.scale_denom = fin_denom; srcinfo.dither_mode = JDITHER_ORDERED; srcinfo.dct_method = JDCT_FASTEST; jpeg_start_decompress(&srcinfo); /* Prep the output compressor */ SetDataLength(dout,0); SetData(dout, NULL); sprintf(dout->mimeType, "image/jpeg"); jpeg_mem_dest(&dstinfo, (void **) &(DataPtr(dout)), (UINT32 *) &(DataLength(dout))); dstinfo.image_width = srcinfo.output_width; dstinfo.image_height = srcinfo.output_height; dstinfo.input_components = srcinfo.output_components; dstinfo.in_color_space = srcinfo.out_color_space; jpeg_set_defaults(&dstinfo); jpeg_set_quality(&dstinfo, fin_qual, TRUE); jpeg_start_compress(&dstinfo, TRUE); handoff_height = (JDIMENSION) 1; handoff_width = srcinfo.output_width*sizeof(JSAMPLE)*srcinfo.output_components; handoff = (JSAMPROW) malloc(handoff_width); /* We're going to need some buffer space to hand off data from the decompressor to the compressor. */ while (srcinfo.output_scanline < srcinfo.output_height) { num_scanlines = jpeg_read_scanlines(&srcinfo, &handoff, handoff_height); jpeg_write_scanlines(&dstinfo, &handoff, num_scanlines); } jpeg_finish_decompress(&srcinfo); jpeg_finish_compress(&dstinfo); result = distOk; JPGMUNGE_RETURN: if (handoff) free(handoff); DataNeedsFree(dout,gm_True); if (phase1_data) free(phase1_data); if (DataLength(dout) > DataLength(din)) { SetDataLength(dout, DataLength(din)); memcpy(DataPtr(dout), DataPtr(din), DataLength(din)); sprintf(dout->mimeType, "image/gif"); } DEBUG("finished processing\n"); return result; }
void format (struct obstack *obs, int argc, token_data **argv) { char *fmt; /* format control string */ const char *fstart; /* beginning of current format spec */ int c; /* a simple character */ /* Flags. */ char flags; /* 1 iff treating flags */ /* Precision specifiers. */ int width; /* minimum field width */ int prec; /* precision */ char lflag; /* long flag */ char hflag; /* short flag */ /* Buffer and stuff. */ char *str; /* malloc'd buffer of formatted text */ enum {INT, UINT, LONG, ULONG, DOUBLE, STR} datatype; fmt = (char *) ARG_STR (argc, argv); for (;;) { while ((c = *fmt++) != '%') { if (c == 0) return; obstack_1grow (obs, c); } fstart = fmt - 1; if (*fmt == '%') { obstack_1grow (obs, '%'); fmt++; continue; } /* Parse flags. */ flags = 1; do { switch (*fmt) { case '-': /* left justification */ case '+': /* mandatory sign */ case ' ': /* space instead of positive sign */ case '0': /* zero padding */ case '#': /* alternate output */ break; default: flags = 0; break; } } while (flags && fmt++); /* Minimum field width. */ width = -1; if (*fmt == '*') { width = ARG_INT (argc, argv); fmt++; } else if (isdigit (to_uchar (*fmt))) { do { fmt++; } while (isdigit (to_uchar (*fmt))); } /* Maximum precision. */ prec = -1; if (*fmt == '.') { if (*(++fmt) == '*') { prec = ARG_INT (argc, argv); ++fmt; } else if (isdigit (to_uchar (*fmt))) { do { fmt++; } while (isdigit (to_uchar (*fmt))); } } /* Length modifiers. */ lflag = (*fmt == 'l'); hflag = (*fmt == 'h'); if (lflag || hflag) fmt++; switch (*fmt++) { case '\0': return; case 'c': datatype = INT; break; case 's': datatype = STR; break; case 'd': case 'i': if (lflag) { datatype = LONG; } else { datatype = INT; } break; case 'o': case 'x': case 'X': case 'u': if (lflag) { datatype = ULONG; } else { datatype = UINT; } break; case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': datatype = DOUBLE; break; default: continue; } c = *fmt; *fmt = '\0'; switch(datatype) { case INT: if (width != -1 && prec != -1) str = xasprintf (fstart, width, prec, ARG_INT(argc, argv)); else if (width != -1) str = xasprintf (fstart, width, ARG_INT(argc, argv)); else if (prec != -1) str = xasprintf (fstart, prec, ARG_INT(argc, argv)); else str = xasprintf (fstart, ARG_INT(argc, argv)); break; case UINT: if (width != -1 && prec != -1) str = xasprintf (fstart, width, prec, ARG_UINT(argc, argv)); else if (width != -1) str = xasprintf (fstart, width, ARG_UINT(argc, argv)); else if (prec != -1) str = xasprintf (fstart, prec, ARG_UINT(argc, argv)); else str = xasprintf (fstart, ARG_UINT(argc, argv)); break; case LONG: if (width != -1 && prec != -1) str = xasprintf (fstart, width, prec, ARG_LONG(argc, argv)); else if (width != -1) str = xasprintf (fstart, width, ARG_LONG(argc, argv)); else if (prec != -1) str = xasprintf (fstart, prec, ARG_LONG(argc, argv)); else str = xasprintf (fstart, ARG_LONG(argc, argv)); break; case ULONG: if (width != -1 && prec != -1) str = xasprintf (fstart, width, prec, ARG_ULONG(argc, argv)); else if (width != -1) str = xasprintf (fstart, width, ARG_ULONG(argc, argv)); else if (prec != -1) str = xasprintf (fstart, prec, ARG_ULONG(argc, argv)); else str = xasprintf (fstart, ARG_ULONG(argc, argv)); break; case DOUBLE: if (width != -1 && prec != -1) str = xasprintf (fstart, width, prec, ARG_DOUBLE(argc, argv)); else if (width != -1) str = xasprintf (fstart, width, ARG_DOUBLE(argc, argv)); else if (prec != -1) str = xasprintf (fstart, prec, ARG_DOUBLE(argc, argv)); else str = xasprintf (fstart, ARG_DOUBLE(argc, argv)); break; case STR: if (width != -1 && prec != -1) str = xasprintf (fstart, width, prec, ARG_STR(argc, argv)); else if (width != -1) str = xasprintf (fstart, width, ARG_STR(argc, argv)); else if (prec != -1) str = xasprintf (fstart, prec, ARG_STR(argc, argv)); else str = xasprintf (fstart, ARG_STR(argc, argv)); break; default: abort(); } *fmt = c; /* NULL was returned on failure, such as invalid format string. For now, just silently ignore that bad specifier. */ if (str == NULL) continue; obstack_grow (obs, str, strlen (str)); free (str); } }
int main(int argc, char * argv[]) { int i; int read_write_error; int input_stat[2] = {0}; int output_stat[2] = {0}; int flags = 0; int count = -1; int skip = 0, seek = 0; int bs = -1, ibs = 4096, obs = 4096; int buffer_size = 0; int count_read, count_write; time_t time_start, time_finish, time_use; const char * input_path = "-"; const char * output_path = "-"; const char * input_device = NULL; const char * output_device = NULL; struct io_base *input_handle, *output_handle; char * buffer_read, * buffer_write, * buffer_alloc; for (i = 1; i < argc; i++) { char * argline = argv[i]; char * optvalue = getoptvalue(argv[i]); ARG_INT(&ibs, 1, "ibs="); ARG_INT(&obs, 2, "obs="); ARG_INT(&bs, (1 | 2), "bs="); ARG_INT(&seek, 4, "seek="); ARG_INT(&skip, 8, "skip="); ARG_INT(&count, 16, "count="); ARG_STRING(&input_path, 32, "if="); ARG_STRING(&output_path, 64, "of="); ARG_STRING(&input_device, 128, "kin="); ARG_STRING(&output_device, 256, "kout="); fprintf(stderr, "unkown operand %s", argline); exit(-1); } if (bs != -1) { ibs = bs; obs = bs; } valid_size("invalid input block size", ibs); valid_size("invalid output block size", obs); input_handle = open_file(input_path, GENERIC_READ); valid_handle("invalid input handle", input_handle); output_handle = open_file(output_path, GENERIC_WRITE); valid_handle("invalid output handle", output_handle); buffer_size = (ibs < obs? obs: ibs) * 2; buffer_alloc = (char *)malloc(buffer_size); valid_buffer("alloc buffer fail", buffer_alloc); if (seek > 0) { off_t posnew = seek * (off_t)(obs); off_t poscur = io_lseek(output_handle, posnew, SEEK_CUR); valid_size("seek output file fail", posnew == poscur); } if (skip > 0) { off_t posnew = skip * (off_t)(ibs); off_t poscur = io_lseek(output_handle, posnew, SEEK_CUR); valid_size("skip input file fail", posnew == poscur); } read_write_error = 0; count_read = count_write = 0; buffer_read = buffer_write = buffer_alloc; time_start = time(NULL); while (read_write_error == 0) { size_t transfer = 0; while (buffer_read < buffer_alloc + obs) { if (!io_read(input_handle, buffer_read, ibs, &transfer)) { read_write_error = 2; break; } if (transfer == 0) { read_write_error = 1; break; } buffer_read += transfer; count_read += transfer; input_stat[transfer == ibs]++; if (input_stat[0] + input_stat[1] == count) { read_write_error = 1; break; } } while (buffer_write + obs <= buffer_read) { if (!io_write(output_handle, buffer_write, obs, &transfer)) { read_write_error = 2; break; } if (transfer == 0) { read_write_error = 2; break; } output_stat[transfer == obs]++; buffer_write += transfer; count_write += transfer; } memmove(buffer_alloc, buffer_write, count_read - count_write); buffer_read = buffer_alloc + (count_read - count_write); buffer_write = buffer_alloc; } while (read_write_error == 1 && count_write < count_read) { size_t transfer = (count_read - count_write); valid_size("internal error", transfer < obs); if (io_write(output_handle, buffer_write, transfer, &transfer)) { output_stat[transfer == obs]++; buffer_write += transfer; count_write += transfer; continue; } if (io_write(output_handle, buffer_write, obs, &transfer)) { output_stat[transfer == obs]++; buffer_write += transfer; count_write += transfer; continue; } read_write_error = 3; break; } time_finish = time(NULL); io_close(output_handle); io_close(input_handle); free(buffer_alloc); time_use = time_finish > time_start? time_finish - time_start: 1; fprintf(stderr, "%d+%d records in\n", input_stat[1], input_stat[0]); fprintf(stderr, "%d+%d records out\n", output_stat[1], output_stat[0]); fprintf(stderr, "%d bytes transferred in %ld secs (%ld bytes/sec)\n", count_read, time_use, count_read / time_use); return 0; }