Browse Source

fix stderr locking and ferror semantics in getopt message printing

if writing the error message fails, POSIX requires that ferror(stderr)
be set. and as a function that operates on a stdio stream, getopt is
required to lock the stream it uses, stderr.

fwrite calls are used instead of fprintf since there is a demand from
some users not to pull in heavy stdio machinery via getopt. this
mimics the original code using write.
Rich Felker 10 năm trước cách đây
mục cha
commit
1d8d86aeb5
1 tập tin đã thay đổi với 16 bổ sung12 xóa
  1. 16 12
      src/misc/getopt.c

+ 16 - 12
src/misc/getopt.c

@@ -11,6 +11,17 @@ int optind=1, opterr=1, optopt, __optpos, __optreset=0;
 #define optpos __optpos
 weak_alias(__optreset, optreset);
 
+void __getopt_msg(const char *a, const char *b, const char *c, int l)
+{
+	FILE *f = stderr;
+	flockfile(f);
+	fwrite(a, strlen(a), 1, f)
+	&& fwrite(b, strlen(b), 1, f)
+	&& fwrite(c, l, 1, f)
+	&& putc('\n', f);
+	funlockfile(f);
+}
+
 int getopt(int argc, char * const argv[], const char *optstring)
 {
 	int i;
@@ -66,24 +77,17 @@ int getopt(int argc, char * const argv[], const char *optstring)
 	} while (l && d != c);
 
 	if (d != c) {
-		if (optstring[0] != ':' && opterr) {
-			write(2, argv[0], strlen(argv[0]));
-			write(2, ": illegal option: ", 18);
-			write(2, optchar, k);
-			write(2, "\n", 1);
-		}
+		if (optstring[0] != ':' && opterr)
+			__getopt_msg(argv[0], ": illegal option: ", optchar, k);
 		return '?';
 	}
 	if (optstring[i] == ':') {
 		if (optstring[i+1] == ':') optarg = 0;
 		else if (optind >= argc) {
 			if (optstring[0] == ':') return ':';
-			if (opterr) {
-				write(2, argv[0], strlen(argv[0]));
-				write(2, ": option requires an argument: ", 31);
-				write(2, optchar, k);
-				write(2, "\n", 1);
-			}
+			if (opterr) __getopt_msg(argv[0],
+				": option requires an argument: ",
+				optchar, k);
 			return '?';
 		}
 		if (optstring[i+1] != ':' || optpos) {