| 4037 | OUTPUT_FILE; a null OUTPUT_FILE stands for standard output. */ |
| 4038 | |
| 4039 | static void |
| 4040 | merge (struct sortfile *files, size_t ntemps, size_t nfiles, |
| 4041 | char const *output_file) |
| 4042 | { |
| 4043 | while (nmerge < nfiles) |
| 4044 | { |
| 4045 | /* Number of input files processed so far. */ |
| 4046 | size_t in; |
| 4047 | |
| 4048 | /* Number of output files generated so far. */ |
| 4049 | size_t out; |
| 4050 | |
| 4051 | /* nfiles % NMERGE; this counts input files that are left over |
| 4052 | after all full-sized merges have been done. */ |
| 4053 | size_t remainder; |
| 4054 | |
| 4055 | /* Number of easily-available slots at the next loop iteration. */ |
| 4056 | size_t cheap_slots; |
| 4057 | |
| 4058 | /* Do as many NMERGE-size merges as possible. In the case that |
| 4059 | nmerge is bogus, increment by the maximum number of file |
| 4060 | descriptors allowed. */ |
| 4061 | for (out = in = 0; nmerge <= nfiles - in; out++) |
| 4062 | { |
| 4063 | FILE *tfp; |
| 4064 | struct tempnode *temp = create_temp (&tfp); |
| 4065 | size_t num_merged = mergefiles (&files[in], MIN (ntemps, nmerge), |
| 4066 | nmerge, tfp, temp->name); |
| 4067 | ntemps -= MIN (ntemps, num_merged); |
| 4068 | files[out].name = temp->name; |
| 4069 | files[out].temp = temp; |
| 4070 | in += num_merged; |
| 4071 | } |
| 4072 | |
| 4073 | remainder = nfiles - in; |
| 4074 | cheap_slots = nmerge - out % nmerge; |
| 4075 | |
| 4076 | if (cheap_slots < remainder) |
| 4077 | { |
| 4078 | /* So many files remain that they can't all be put into the last |
| 4079 | NMERGE-sized output window. Do one more merge. Merge as few |
| 4080 | files as possible, to avoid needless I/O. */ |
| 4081 | size_t nshortmerge = remainder - cheap_slots + 1; |
| 4082 | FILE *tfp; |
| 4083 | struct tempnode *temp = create_temp (&tfp); |
| 4084 | size_t num_merged = mergefiles (&files[in], MIN (ntemps, nshortmerge), |
| 4085 | nshortmerge, tfp, temp->name); |
| 4086 | ntemps -= MIN (ntemps, num_merged); |
| 4087 | files[out].name = temp->name; |
| 4088 | files[out++].temp = temp; |
| 4089 | in += num_merged; |
| 4090 | } |
| 4091 | |
| 4092 | /* Put the remaining input files into the last NMERGE-sized output |
| 4093 | window, so they will be merged in the next pass. */ |
| 4094 | memmove (&files[out], &files[in], (nfiles - in) * sizeof *files); |
| 4095 | ntemps += out; |
| 4096 | nfiles -= in - out; |
no test coverage detected