Check Only Mode
Check Only Mode

Check whether the input files are in sorted order. This does not sort any of the files.

Notes
Currently this also includes multiple file sort (in check()). How should this be factored out?

This is a registered behavior: register the functional behavior register the parsing behavior link the two behaviors together


Define exit code for CheckMode
Constant definition
Segment Source
  63: /* Use this as exit status in case of error, not EXIT_FAILURE.  This
  64:    is necessary because EXIT_FAILURE is usually 1 and POSIX requires
  65:    that sort exit with status 1 IFF invoked with -c and the input is
  66:    not properly sorted.  Any other irregular exit must exit with a
  67:    status code greater than 1.  */
  68: #define SORT_FAILURE 2
  69: 

Define check buffer allocation size (mergealloc)
Constant definition
Notes
The merge buffer size is reused in the CheckMode concern. A separate and distinct constant might be more appropriate. It would also be quite pendantic.
Segment Source
 169: /* Initial buffer size for in core merge buffers.  Bear in mind that
 170:    up to NMERGE * mergealloc bytes may be allocated for merge buffers. */
 171: static int mergealloc =  16 * 1024;
 172: 

Define default line Length (linelength)
Constant definition
Segment Source
 173: /* Guess of average line length. */
 174: static int linelength = 30;
 175: 

Insert user message text
Text insertion
Segment Source
 222:   -c               check if given files already sorted, do not sort\n\

Define checkfp()
Function definition
Segment Source
1206: /* Check that the lines read from the given FP come in order.  Return
1207:    1 if they do and 0 if there is a disorder.
1208:    FIXME: return number of first out-of-order line if not sorted.  */
1209: 
1210: static int
1211: checkfp (FILE *fp)
1212: {
1213:   struct buffer buf;            /* Input buffer. */
1214:   struct lines lines;           /* Lines scanned from the buffer. */
1215:   struct line temp;             /* Copy of previous line. */
1216:   int cc;                       /* Character count. */
1217:   int alloc, sorted = 1;
1218: 
1219:   initbuf (&buf, mergealloc);
1220:   initlines (&lines, mergealloc / linelength + 1,
1221:              LINEALLOC / ((NMERGE + NMERGE) * sizeof (struct line)));
1222:   alloc = linelength;
1223:   temp.text = xmalloc (alloc);
1224: 
1225:   cc = fillbuf (&buf, fp);
1226:   if (cc == 0)
1227:     goto finish;
1228: 
1229:   findlines (&buf, &lines);
1230: 
1231:   while (1)
1232:     {
1233:       struct line *prev_line;   /* Pointer to previous line. */
1234:       int cmp;                  /* Result of calling compare. */
1235:       int i;
1236: 
1237:       /* Compare each line in the buffer with its successor. */
1238:       for (i = 0; i < lines.used - 1; ++i)
1239:         {
1240:           cmp = compare (&lines.lines[i], &lines.lines[i + 1]);
1241:           if ((unique && cmp >= 0) || (cmp > 0))
1242:             {
1243:               sorted = 0;
1244:               goto finish;
1245:             }
1246:         }
1247: 
1248:       /* Save the last line of the buffer and refill the buffer. */
1249:       prev_line = lines.lines + (lines.used - 1);
1250:       if (prev_line->length + 1 > alloc)
1251:         {
1252:           do
1253:             {
1254:               alloc *= 2;
1255:             }
1256:           while (alloc < prev_line->length + 1);
1257:           temp.text = xrealloc (temp.text, alloc);
1258:         }
1259:       assert (prev_line->length + 1 <= alloc);
1260:       memcpy (temp.text, prev_line->text, prev_line->length + 1);
1261:       temp.length = prev_line->length;
1262:       temp.keybeg = temp.text + (prev_line->keybeg - prev_line->text);
1263:       temp.keylim = temp.text + (prev_line->keylim - prev_line->text);
1264: 
1265:       cc = fillbuf (&buf, fp);
1266:       if (cc == 0)
1267:         break;
1268: 
1269:       findlines (&buf, &lines);
1270:       /* Make sure the line saved from the old buffer contents is
1271:          less than or equal to the first line of the new buffer. */
1272:       cmp = compare (&temp, &lines.lines[0]);
1273:       if ((unique && cmp >= 0) || (cmp > 0))
1274:         {
1275:           sorted = 0;
1276:           break;
1277:         }
1278:     }
1279: 
1280: finish:
1281:   xfclose (fp);
1282:   free (buf.buf);
1283:   free ((char *) lines.lines);
1284:   free (temp.text);
1285:   return sorted;
1286: }
1287: 

Define check()
Function definition
Notes
Does this use ErrMsg:Disorder() or does it extend ErrMsg to have Disorder support?

This primarily supports the SrcSpec concern. It adds multiple file support to the basic check validation capability.

Segment Source
1491: /* Check that each of the NFILES FILES is ordered.
1492:    Return a count of disordered files. */
1493: 
1494: static int
1495: check (char **files, int nfiles)
1496: {
1497:   int i, disorders = 0;
1498:   FILE *fp;
1499: 
1500:   for (i = 0; i < nfiles; ++i)
1501:     {
1502:       fp = xfopen (files[i], "r");
1503:       if (!checkfp (fp))
1504:         {
1505:           fprintf (stderr, _("%s: disorder on %s\n"), program_name, files[i]);
1506:           ++disorders;
1507:         }
1508:     }
1509:   return disorders;
1510: }
1511: 

Define check only flag (checkonly)
Variable definition
Segment Source
1721:   int checkonly = 0, mergeonly = 0, nfiles = 0;

Parse CheckOnly option (-c)
Code insertion
Segment Source
1840:                   case 'c':
1841:                     checkonly = 1;
1842:                     break;

Dispatch checkonly option
Code insertion
Notes
It's quite a surprise that this code does not use the manifest constants EXIT_SUCCESS and EXIT_FAILURE (or the "should be declared" constant EXIT_DISORDER).
Segment Source
2057:   if (checkonly)
2058:     {
2059:       /* POSIX requires that sort return 1 IFF invoked with -c and the
2060:          input is not properly sorted.  */
2061:       exit (check (files, nfiles) == 0 ? 0 : 1);
2062:     }
2063: