time: -200 bytes of text
No binary (build failed)
—
(log yok)
| @@ -100,18 +100,14 @@ static int resuse_end(pid_t pid, resource_t * resp) | |
| return 1; | |
| } | |
| - | /* Print ARGV to FP, with each entry in ARGV separated by FILLER. */ |
| - | static void fprintargv(FILE * fp, char *const *argv, const char *filler) |
| + | /* Print ARGV, with each entry in ARGV separated by FILLER. */ |
| + | static void printargv(char *const *argv, const char *filler) |
| { | |
| - | char *const *av; |
| - | |
| - | av = argv; |
| - | fputs(*av, fp); |
| - | while (*++av) { |
| - | fputs(filler, fp); |
| - | fputs(*av, fp); |
| + | fputs(*argv, stdout); |
| + | while (*++argv) { |
| + | fputs(filler, stdout); |
| + | fputs(*argv, stdout); |
| } | |
| - | die_if_ferror(fp, "output"); |
| } | |
| /* Return the number of kilobytes corresponding to a number of pages PAGES. | |
| @@ -124,28 +120,26 @@ static void fprintargv(FILE * fp, char *const *argv, const char *filler) | |
| static unsigned long ptok(unsigned long pages) | |
| { | |
| - | static unsigned long ps = 0; |
| + | static unsigned long ps; |
| unsigned long tmp; | |
| - | static long size = LONG_MAX; |
| /* Initialization. */ | |
| if (ps == 0) | |
| - | ps = (long) getpagesize(); |
| + | ps = getpagesize(); |
| /* Conversion. */ | |
| if (pages > (LONG_MAX / ps)) { /* Could overflow. */ | |
| tmp = pages / 1024; /* Smaller first, */ | |
| - | size = tmp * ps; /* then larger. */ |
| - | } else { /* Could underflow. */ |
| - | tmp = pages * ps; /* Larger first, */ |
| - | size = tmp / 1024; /* then smaller. */ |
| + | return tmp * ps; /* then larger. */ |
| } | |
| - | return size; |
| + | /* Could underflow. */ |
| + | tmp = pages * ps; /* Larger first, */ |
| + | return tmp / 1024; /* then smaller. */ |
| } | |
| /* summarize: Report on the system use of a command. | |
| - | Copy the FMT argument to FP except that `%' sequences |
| + | Print the FMT argument except that `%' sequences |
| have special meaning, and `\n' and `\t' are translated into | |
| newline and tab, respectively, and `\\' is translated into `\'. | |
| @@ -183,25 +177,23 @@ static unsigned long ptok(unsigned long pages) | |
| to kbytes by multiplying by the page size, dividing by 1024, | |
| and dividing by elapsed real time. | |
| - | FP is the stream to print to. |
| FMT is the format string, interpreted as described above. | |
| COMMAND is the command and args that are being summarized. | |
| RESP is resource information on the command. */ | |
| - | static void summarize(FILE * fp, const char *fmt, char **command, |
| - | resource_t * resp) |
| + | static void summarize(const char *fmt, char **command, resource_t * resp) |
| { | |
| unsigned long r; /* Elapsed real milliseconds. */ | |
| unsigned long v; /* Elapsed virtual (CPU) milliseconds. */ | |
| if (WIFSTOPPED(resp->waitstatus)) | |
| - | fprintf(fp, "Command stopped by signal %d\n", |
| + | printf("Command stopped by signal %d\n", |
| WSTOPSIG(resp->waitstatus)); | |
| else if (WIFSIGNALED(resp->waitstatus)) | |
| - | fprintf(fp, "Command terminated by signal %d\n", |
| + | printf("Command terminated by signal %d\n", |
| WTERMSIG(resp->waitstatus)); | |
| else if (WIFEXITED(resp->waitstatus) && WEXITSTATUS(resp->waitstatus)) | |
| - | fprintf(fp, "Command exited with non-zero status %d\n", |
| + | printf("Command exited with non-zero status %d\n", |
| WEXITSTATUS(resp->waitstatus)); | |
| /* Convert all times to milliseconds. Occasionally, one of these values | |
| @@ -214,178 +206,194 @@ static void summarize(FILE * fp, const char *fmt, char **command, | |
| v = resp->ru.ru_utime.tv_sec * 1000 + resp->ru.ru_utime.TV_MSEC + | |
| resp->ru.ru_stime.tv_sec * 1000 + resp->ru.ru_stime.TV_MSEC; | |
| + | /* putchar() != putc(stdout) in glibc! */ |
| + | |
| while (*fmt) { | |
| + | /* Handle leading literal part */ |
| + | int n = strcspn(fmt, "%\\"); |
| + | if (n) { |
| + | printf("%.*s", n, fmt); |
| + | fmt += n; |
| + | continue; |
| + | } |
| + | |
| switch (*fmt) { | |
| + | #ifdef NOT_NEEDED |
| + | /* Handle literal char */ |
| + | /* Usually we optimize for size, but there is a limit |
| + | * for everything. With this we do a lot of 1-byte writes */ |
| + | default: |
| + | putc(*fmt, stdout); |
| + | break; |
| + | #endif |
| + | |
| case '%': | |
| switch (*++fmt) { | |
| - | case '%': /* Literal '%'. */ |
| - | putc('%', fp); |
| + | #ifdef NOT_NEEDED_YET |
| + | /* Our format strings do not have these */ |
| + | /* and we do not take format str from user */ |
| + | default: |
| + | putc('%', stdout); |
| + | /*FALLTHROUGH*/ |
| + | case '%': |
| + | if (!*fmt) goto ret; |
| + | putc(*fmt, stdout); |
| break; | |
| + | #endif |
| case 'C': /* The command that got timed. */ | |
| - | fprintargv(fp, command, " "); |
| + | printargv(command, " "); |
| break; | |
| case 'D': /* Average unshared data size. */ | |
| - | fprintf(fp, "%lu", |
| + | printf("%lu", |
| MSEC_TO_TICKS(v) == 0 ? 0 : | |
| ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v) + | |
| ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v)); | |
| break; | |
| case 'E': /* Elapsed real (wall clock) time. */ | |
| if (resp->elapsed.tv_sec >= 3600) /* One hour -> h:m:s. */ | |
| - | fprintf(fp, "%ldh %ldm %02lds", |
| + | printf("%ldh %ldm %02lds", |
| resp->elapsed.tv_sec / 3600, | |
| (resp->elapsed.tv_sec % 3600) / 60, | |
| resp->elapsed.tv_sec % 60); | |
| else | |
| - | fprintf(fp, "%ldm %ld.%02lds", /* -> m:s. */ |
| + | printf("%ldm %ld.%02lds", /* -> m:s. */ |
| resp->elapsed.tv_sec / 60, | |
| resp->elapsed.tv_sec % 60, | |
| resp->elapsed.tv_usec / 10000); | |
| break; | |
| case 'F': /* Major page faults. */ | |
| - | fprintf(fp, "%ld", resp->ru.ru_majflt); |
| + | printf("%ld", resp->ru.ru_majflt); |
| break; | |
| case 'I': /* Inputs. */ | |
| - | fprintf(fp, "%ld", resp->ru.ru_inblock); |
| + | printf("%ld", resp->ru.ru_inblock); |
| break; | |
| case 'K': /* Average mem usage == data+stack+text. */ | |
| - | fprintf(fp, "%lu", |
| + | printf("%lu", |
| MSEC_TO_TICKS(v) == 0 ? 0 : | |
| ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v) + | |
| ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v) + | |
| ptok((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS(v)); | |
| break; | |
| case 'M': /* Maximum resident set size. */ | |
| - | fprintf(fp, "%lu", ptok((UL) resp->ru.ru_maxrss)); |
| + | printf("%lu", ptok((UL) resp->ru.ru_maxrss)); |
| break; | |
| case 'O': /* Outputs. */ | |
| - | fprintf(fp, "%ld", resp->ru.ru_oublock); |
| + | printf("%ld", resp->ru.ru_oublock); |
| break; | |
| case 'P': /* Percent of CPU this job got. */ | |
| /* % cpu is (total cpu time)/(elapsed time). */ | |
| if (r > 0) | |
| - | fprintf(fp, "%lu%%", (v * 100 / r)); |
| + | printf("%lu%%", (v * 100 / r)); |
| else | |
| - | fprintf(fp, "?%%"); |
| + | printf("?%%"); |
| break; | |
| case 'R': /* Minor page faults (reclaims). */ | |
| - | fprintf(fp, "%ld", resp->ru.ru_minflt); |
| + | printf("%ld", resp->ru.ru_minflt); |
| break; | |
| case 'S': /* System time. */ | |
| - | fprintf(fp, "%ld.%02ld", |
| + | printf("%ld.%02ld", |
| resp->ru.ru_stime.tv_sec, | |
| resp->ru.ru_stime.TV_MSEC / 10); | |
| break; | |
| case 'T': /* System time. */ | |
| if (resp->ru.ru_stime.tv_sec >= 3600) /* One hour -> h:m:s. */ | |
| - | fprintf(fp, "%ldh %ldm %02lds", |
| + | printf("%ldh %ldm %02lds", |
| resp->ru.ru_stime.tv_sec / 3600, | |
| (resp->ru.ru_stime.tv_sec % 3600) / 60, | |
| resp->ru.ru_stime.tv_sec % 60); | |
| else | |
| - | fprintf(fp, "%ldm %ld.%02lds", /* -> m:s. */ |
| + | printf("%ldm %ld.%02lds", /* -> m:s. */ |
| resp->ru.ru_stime.tv_sec / 60, | |
| resp->ru.ru_stime.tv_sec % 60, | |
| resp->ru.ru_stime.tv_usec / 10000); | |
| break; | |
| case 'U': /* User time. */ | |
| - | fprintf(fp, "%ld.%02ld", |
| + | printf("%ld.%02ld", |
| resp->ru.ru_utime.tv_sec, | |
| resp->ru.ru_utime.TV_MSEC / 10); | |
| break; | |
| case 'u': /* User time. */ | |
| if (resp->ru.ru_utime.tv_sec >= 3600) /* One hour -> h:m:s. */ | |
| - | fprintf(fp, "%ldh %ldm %02lds", |
| + | printf("%ldh %ldm %02lds", |
| resp->ru.ru_utime.tv_sec / 3600, | |
| (resp->ru.ru_utime.tv_sec % 3600) / 60, | |
| resp->ru.ru_utime.tv_sec % 60); | |
| else | |
| - | fprintf(fp, "%ldm %ld.%02lds", /* -> m:s. */ |
| + | printf("%ldm %ld.%02lds", /* -> m:s. */ |
| resp->ru.ru_utime.tv_sec / 60, | |
| resp->ru.ru_utime.tv_sec % 60, | |
| resp->ru.ru_utime.tv_usec / 10000); | |
| break; | |
| case 'W': /* Times swapped out. */ | |
| - | fprintf(fp, "%ld", resp->ru.ru_nswap); |
| + | printf("%ld", resp->ru.ru_nswap); |
| break; | |
| case 'X': /* Average shared text size. */ | |
| - | fprintf(fp, "%lu", |
| + | printf("%lu", |
| MSEC_TO_TICKS(v) == 0 ? 0 : | |
| ptok((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS(v)); | |
| break; | |
| case 'Z': /* Page size. */ | |
| - | fprintf(fp, "%d", getpagesize()); |
| + | printf("%d", getpagesize()); |
| break; | |
| case 'c': /* Involuntary context switches. */ | |
| - | fprintf(fp, "%ld", resp->ru.ru_nivcsw); |
| + | printf("%ld", resp->ru.ru_nivcsw); |
| break; | |
| case 'e': /* Elapsed real time in seconds. */ | |
| - | fprintf(fp, "%ld.%02ld", |
| + | printf("%ld.%02ld", |
| resp->elapsed.tv_sec, resp->elapsed.tv_usec / 10000); | |
| break; | |
| case 'k': /* Signals delivered. */ | |
| - | fprintf(fp, "%ld", resp->ru.ru_nsignals); |
| + | printf("%ld", resp->ru.ru_nsignals); |
| break; | |
| case 'p': /* Average stack segment. */ | |
| - | fprintf(fp, "%lu", |
| + | printf("%lu", |
| MSEC_TO_TICKS(v) == 0 ? 0 : | |
| ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v)); | |
| break; | |
| case 'r': /* Incoming socket messages received. */ | |
| - | fprintf(fp, "%ld", resp->ru.ru_msgrcv); |
| + | printf("%ld", resp->ru.ru_msgrcv); |
| break; | |
| case 's': /* Outgoing socket messages sent. */ | |
| - | fprintf(fp, "%ld", resp->ru.ru_msgsnd); |
| + | printf("%ld", resp->ru.ru_msgsnd); |
| break; | |
| case 't': /* Average resident set size. */ | |
| - | fprintf(fp, "%lu", |
| + | printf("%lu", |
| MSEC_TO_TICKS(v) == 0 ? 0 : | |
| ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v)); | |
| break; | |
| case 'w': /* Voluntary context switches. */ | |
| - | fprintf(fp, "%ld", resp->ru.ru_nvcsw); |
| + | printf("%ld", resp->ru.ru_nvcsw); |
| break; | |
| case 'x': /* Exit status. */ | |
| - | fprintf(fp, "%d", WEXITSTATUS(resp->waitstatus)); |
| + | printf("%d", WEXITSTATUS(resp->waitstatus)); |
| break; | |
| - | case '\0': |
| - | putc('?', fp); |
| - | return; |
| - | default: |
| - | putc('?', fp); |
| - | putc(*fmt, fp); |
| } | |
| - | ++fmt; |
| break; | |
| + | #ifdef NOT_NEEDED_YET |
| case '\\': /* Format escape. */ | |
| switch (*++fmt) { | |
| + | default: |
| + | putc('\\', stdout); |
| + | /*FALLTHROUGH*/ |
| + | case '\\': |
| + | if (!*fmt) goto ret; |
| + | putc(*fmt, stdout); |
| + | break; |
| case 't': | |
| - | putc('\t', fp); |
| + | putc('\t', stdout); |
| break; | |
| case 'n': | |
| - | putc('\n', fp); |
| - | break; |
| - | case '\\': |
| - | putc('\\', fp); |
| + | putc('\n', stdout); |
| break; | |
| - | default: |
| - | putc('?', fp); |
| - | putc('\\', fp); |
| - | putc(*fmt, fp); |
| } | |
| - | ++fmt; |
| break; | |
| - | |
| - | default: |
| - | putc(*fmt++, fp); |
| + | #endif |
| } | |
| - | |
| - | die_if_ferror(fp, "output"); |
| + | ++fmt; |
| } | |
| - | putc('\n', fp); |
| - | |
| - | die_if_ferror(fp, "output"); |
| + | /* ret: */ |
| + | putc('\n', stdout); |
| } | |
| /* Run command CMD and return statistics on it. | |
| @@ -449,7 +457,11 @@ int time_main(int argc, char **argv) | |
| } | |
| run_command(argv, &res); | |
| - | summarize(stderr, output_format, argv, &res); |
| + | |
| + | /* Cheat. printf's are shorter :) */ |
| + | stdout = stderr; |
| + | dup2(2, 1); /* just in case libc does something silly :( */ |
| + | summarize(output_format, argv, &res); |
| if (WIFSTOPPED(res.waitstatus)) | |
| return WSTOPSIG(res.waitstatus); | |
| @@ -457,5 +469,5 @@ int time_main(int argc, char **argv) | |
| return WTERMSIG(res.waitstatus); | |
| if (WIFEXITED(res.waitstatus)) | |
| return WEXITSTATUS(res.waitstatus); | |
| - | return 0; |
| + | fflush_stdout_and_exit(0); |
| } | |