]> Kevux Git Server - fll/commitdiff
Update: level_0 print functions.
authorKevin Day <thekevinday@gmail.com>
Fri, 23 Oct 2020 03:05:17 +0000 (22:05 -0500)
committerKevin Day <thekevinday@gmail.com>
Fri, 23 Oct 2020 03:18:22 +0000 (22:18 -0500)
Relax the parameter checks and have them return F_data_not when length is 0 or string is unavailable.
- Based on existing documentation, it seems this behavior was intended at some point anyway.
- The range is capped to buffer.used now.

The f_print_to* functions are rewritten to print as much of the string in as few calls to write() as possible.
- It is likely possible to utilize more complicated logic to further reduce the calls to write() but this is good enough for now.
- Reducing the calls to write(), in theory, should improve performance.

Add checks to f_print_to* functions to do nothing if the id is -1 (aka: an invalid/closed file descriptor).

Add *_except* print functions to print all characters except those specified in the "except" variable as well as not printing NULLs.

level_0/f_print/c/print.c
level_0/f_print/c/print.h
level_0/f_print/c/private-print.c
level_0/f_print/c/private-print.h

index 8488538dc5ae38cc0b09f383cf2029445954e520..dd4e34828c32bafc15aa87268033886976c7b94d 100644 (file)
@@ -9,9 +9,10 @@ extern "C" {
   f_return_status f_print(FILE *output, const f_string_t string, const f_string_length_t length) {
     #ifndef _di_level_0_parameter_checking_
       if (!output) return F_status_set_error(F_parameter);
-      if (!string) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
+    if (!string || length == 0) return F_data_not;
+
     return private_f_print(output, string, length);
   }
 #endif // _di_f_print_
@@ -22,6 +23,8 @@ extern "C" {
       if (!output) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
+    if (!buffer.used) return F_data_not;
+
     return private_f_print(output, buffer.string, buffer.used);
   }
 #endif // _di_f_print_dynamic_
@@ -30,30 +33,82 @@ extern "C" {
   f_return_status f_print_dynamic_partial(FILE *output, const f_string_static_t buffer, const f_string_range_t range) {
     #ifndef _di_level_0_parameter_checking_
       if (!output) return F_status_set_error(F_parameter);
-      if (range.start < 0) return F_status_set_error(F_parameter);
-      if (range.start > range.stop) return F_status_set_error(F_parameter);
-      if (range.start >= buffer.used) return F_status_set_error(F_parameter);
-      if (range.stop >= buffer.used) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
-    const f_string_length_t length = (range.stop - range.start) + 1;
+    if (!buffer.used || range.start > range.stop || range.start >= buffer.used) return F_data_not;
+
+    f_string_length_t length = (range.stop - range.start) + 1;
+
+    if (length + range.start > buffer.used) {
+      length = buffer.used - range.start;
+    }
 
     return private_f_print(output, buffer.string + range.start, length);
   }
 #endif // _di_f_print_dynamic_partial_
 
+#ifndef _di_f_print_except_
+  f_return_status f_print_except(FILE *output, const f_string_t string, const f_string_length_t length, const f_string_lengths_t except) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!output) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!string || length == 0) return F_data_not;
+
+    return private_f_print_except(output, string, length, except);
+  }
+#endif // _di_f_print_except_
+
+#ifndef _di_f_print_except_dynamic_
+  f_return_status f_print_except_dynamic(FILE *output, const f_string_static_t buffer, const f_string_lengths_t except) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!output) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!buffer.used) return F_data_not;
+
+    return private_f_print_except(output, buffer.string, buffer.used, except);
+  }
+#endif // _di_f_print_except_dynamic_
+
+#ifndef _di_f_print_except_dynamic_partial_
+  f_return_status f_print_except_dynamic_partial(FILE *output, const f_string_static_t buffer, const f_string_range_t range, const f_string_lengths_t except) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!output) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!buffer.used || range.start > range.stop || range.start >= buffer.used) return F_data_not;
+
+    f_string_length_t length = (range.stop - range.start) + 1;
+
+    if (length + range.start > buffer.used) {
+      length = buffer.used - range.start;
+    }
+
+    return private_f_print_except(output, buffer.string + range.start, length, except);
+  }
+#endif // _di_f_print_except_dynamic_partial_
+
 #ifndef _di_f_print_to_
   f_return_status f_print_to(const int id, const f_string_t string, const f_string_length_t length) {
     #ifndef _di_level_0_parameter_checking_
-      if (!string) return F_status_set_error(F_parameter);
+      if (id != -1) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
+    if (!string || length == 0) return F_data_not;
+
     return private_f_print_to(id, string, length);
   }
 #endif // _di_f_print_to_
 
 #ifndef _di_f_print_to_dynamic_
   f_return_status f_print_to_dynamic(const int id, const f_string_static_t buffer) {
+    #ifndef _di_level_0_parameter_checking_
+      if (id != -1) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!buffer.used) return F_data_not;
+
     return private_f_print_to(id, buffer.string, buffer.used);
   }
 #endif // _di_f_print_to_dynamic_
@@ -61,18 +116,63 @@ extern "C" {
 #ifndef _di_f_print_to_dynamic_partial_
   f_return_status f_print_to_dynamic_partial(const int id, const f_string_static_t buffer, const f_string_range_t range) {
     #ifndef _di_level_0_parameter_checking_
-      if (range.start < 0) return F_status_set_error(F_parameter);
-      if (range.start > range.stop) return F_status_set_error(F_parameter);
-      if (range.start >= buffer.used) return F_status_set_error(F_parameter);
-      if (range.stop >= buffer.used) return F_status_set_error(F_parameter);
+      if (id != -1) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
-    const f_string_length_t length = (range.stop - range.start) + 1;
+    if (!buffer.used || range.start > range.stop || range.start >= buffer.used) return F_data_not;
+
+    f_string_length_t length = (range.stop - range.start) + 1;
+
+    if (length + range.start > buffer.used) {
+      length = buffer.used - range.start;
+    }
 
     return private_f_print_to(id, buffer.string + range.start, length);
   }
 #endif // _di_f_print_to_dynamic_partial_
 
+#ifndef _di_f_print_to_except_
+  f_return_status f_print_to_except(const int id, const f_string_t string, const f_string_length_t length, const f_string_lengths_t except) {
+    #ifndef _di_level_0_parameter_checking_
+      if (id != -1) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!string || length == 0) return F_data_not;
+
+    return private_f_print_to_except(id, string, length, except);
+  }
+#endif // _di_f_print_to_except_
+
+#ifndef _di_f_print_to_except_dynamic_
+  f_return_status f_print_to_except_dynamic(const int id, const f_string_static_t buffer, const f_string_lengths_t except) {
+    #ifndef _di_level_0_parameter_checking_
+      if (id != -1) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!buffer.used) return F_data_not;
+
+    return private_f_print_to_except(id, buffer.string, buffer.used, except);
+  }
+#endif // _di_f_print_to_except_dynamic_
+
+#ifndef _di_f_print_to_except_dynamic_partial_
+  f_return_status f_print_to_except_dynamic_partial(const int id, const f_string_static_t buffer, const f_string_range_t range, const f_string_lengths_t except) {
+    #ifndef _di_level_0_parameter_checking_
+      if (id != -1) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!buffer.used || range.start > range.stop || range.start >= buffer.used) return F_data_not;
+
+    f_string_length_t length = (range.stop - range.start) + 1;
+
+    if (length + range.start > buffer.used) {
+      length = buffer.used - range.start;
+    }
+
+    return private_f_print_to_except(id, buffer.string + range.start, length, except);
+  }
+#endif // _di_f_print_to_except_dynamic_partial_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 4d1284c3ee9cf19cc50d410e73f2f3e4a314e686..0c11f4ebd202b730b0c6fb409780e24a240ce2b4 100644 (file)
@@ -32,10 +32,9 @@ extern "C" {
 /**
  * Similar to a c-library printf, except that this will only print a specific range.
  *
- * The string is printed as-is without interpretation.
- *
  * Will not stop at NULL.
  * Will not print NULL.
+ * Will print up to length 1-byte characters.
  *
  * @param output
  *   The file to output to, including standard streams such as stdout and stderr.
@@ -46,7 +45,7 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if length is 0.
+ *   F_data_not if there is nothing to print.
  *   F_output (with error bit) on failure.
  *   F_parameter (with error bit) if a parameter is invalid.
  *
@@ -59,11 +58,9 @@ extern "C" {
 /**
  * Similar to a c-library printf, except that this prints a given dynamic string.
  *
- * The string is printed as-is without interpretation.
- *
  * Will not stop at NULL.
  * Will not print NULL.
- * Will print the entire dynamic string.
+ * Will print up to the length of the buffer.
  *
  * @param output
  *   The file to output to, including standard streams such as stdout and stderr.
@@ -72,7 +69,7 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if buffer.used is 0.
+ *   F_data_not if there is nothing to print.
  *   F_output (with error bit) on failure.
  *   F_parameter (with error bit) if a parameter is invalid.
  *
@@ -85,11 +82,9 @@ extern "C" {
 /**
  * Similar to a c-library printf, except that this will only print a specific range in a given dynamic string.
  *
- * The string is printed as-is without interpretation.
- *
  * Will not stop at NULL.
  * Will not print NULL.
- * Will print the only the buffer range specified by range.
+ * Will print up to the specified range within the buffer.
  *
  * @param output
  *   The file to output to, including standard streams such as stdout and stderr.
@@ -100,7 +95,7 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if buffer.used is 0.
+ *   F_data_not if there is nothing to print.
  *   F_output (with error bit) on failure.
  *   F_parameter (with error bit) if a parameter is invalid.
  *
@@ -111,12 +106,100 @@ extern "C" {
 #endif // _di_f_print_dynamic_partial_
 
 /**
- * Similar to a c-library dprintf, except that this will only print a specific range.
+ * Similar to a c-library printf, except that this will only print a specific range.
  *
- * The string is printed as-is without interpretation.
+ * Will not stop at NULL.
+ * Will not print NULL.
+ * Will not print any 1-byte character at a location specified in except array.
+ * Will print up to length 1-byte characters.
+ *
+ * @param output
+ *   The file to output to, including standard streams such as stdout and stderr.
+ * @param string
+ *   The string to output.
+ * @param length
+ *   The total number of characters to print.
+ * @param except
+ *   An array of locations within the given string to not print.
+ *   The array of locations is assumed to be in linear order.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not if there is nothing to print.
+ *   F_output (with error bit) on failure.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see fputc()
+ */
+#ifndef _di_f_print_except_
+  extern f_return_status f_print_except(FILE *output, const f_string_t string, const f_string_length_t length, const f_string_lengths_t except);
+#endif // _di_f_print_except_
+
+/**
+ * Similar to a c-library printf, except that this prints a given dynamic string.
+ *
+ * Will not stop at NULL.
+ * Will not print NULL.
+ * Will not print any 1-byte character at a location specified in except array.
+ * Will print up to the length of the buffer.
+ *
+ * @param output
+ *   The file to output to, including standard streams such as stdout and stderr.
+ * @param buffer
+ *   The string to output.
+ * @param except
+ *   An array of locations within the given string to not print.
+ *   The array of locations is assumed to be in linear order.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not if there is nothing to print.
+ *   F_output (with error bit) on failure.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see fputc()
+ */
+#ifndef _di_f_print_except_dynamic_
+  extern f_return_status f_print_except_dynamic(FILE *output, const f_string_static_t buffer, const f_string_lengths_t except);
+#endif // _di_f_print_except_dynamic_
+
+/**
+ * Similar to a c-library printf, except that this will only print a specific range in a given dynamic string.
+ *
+ * Will not stop at NULL.
+ * Will not print NULL.
+ * Will not print any 1-byte character at a location specified in except array.
+ * Will print up to the specified range within the buffer.
+ *
+ * @param output
+ *   The file to output to, including standard streams such as stdout and stderr.
+ * @param buffer
+ *   The string to output.
+ * @param range
+ *   The range within the provided string to print.
+ * @param except
+ *   An array of locations within the given string to not print.
+ *   The array of locations is assumed to be in linear order.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not if there is nothing to print.
+ *   F_output (with error bit) on failure.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see fputc()
+ */
+#ifndef _di_f_print_dynamic_except_partial_
+  extern f_return_status f_print_except_dynamic_partial(FILE *output, const f_string_static_t buffer, const f_string_range_t range, const f_string_lengths_t except);
+#endif // _di_f_print_except_dynamic_partial_
+
+
+/**
+ * Similar to a c-library dprintf, except that this will only print a specific range.
  *
  * Will not stop at NULL.
  * Will not print NULL.
+ * Will print up to length 1-byte characters.
  *
  * @param id
  *   The file descriptor to output to.
@@ -127,7 +210,7 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if length is 0.
+ *   F_data_not if there is nothing to print.
  *   F_block (with error bit) if file descriptor is set to non-block and the write would result in a blocking operation.
  *   F_buffer (with error bit) if the buffer is invalid.
  *   F_file_closed (with error bit) if file is not open.
@@ -146,11 +229,9 @@ extern "C" {
 /**
  * Similar to a c-library dprintf, except that this prints a given dynamic string.
  *
- * The string is printed as-is without interpretation.
- *
  * Will not stop at NULL.
  * Will not print NULL.
- * Will print the entire dynamic string.
+ * Will print up to the length of the buffer.
  *
  * @param output
  *   The file to output to, including standard streams such as stdout and stderr.
@@ -159,7 +240,7 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if buffer.used is 0.
+ *   F_data_not if there is nothing to print.
  *   F_block (with error bit) if file descriptor is set to non-block and the write would result in a blocking operation.
  *   F_buffer (with error bit) if the buffer is invalid.
  *   F_file_closed (with error bit) if file is not open.
@@ -178,11 +259,9 @@ extern "C" {
 /**
  * Similar to a c-library dprintf, except that this will only print a specific range in a given dynamic string.
  *
- * The string is printed as-is without interpretation.
- *
  * Will not stop at NULL.
  * Will not print NULL.
- * Will print the only the buffer range specified by range.
+ * Will print up to the specified range within the buffer.
  *
  * @param output
  *   The file to output to, including standard streams such as stdout and stderr.
@@ -193,7 +272,7 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if buffer.used is 0.
+ *   F_data_not if there is nothing to print.
  *   F_block (with error bit) if file descriptor is set to non-block and the write would result in a blocking operation.
  *   F_buffer (with error bit) if the buffer is invalid.
  *   F_file_closed (with error bit) if file is not open.
@@ -209,6 +288,118 @@ extern "C" {
   extern f_return_status f_print_to_dynamic_partial(const int id, const f_string_static_t buffer, const f_string_range_t range);
 #endif // _di_f_print_to_dynamic_partial_
 
+/**
+ * Similar to a c-library dprintf, except that this will only print a specific range.
+ *
+ * The string is printed as-is without interpretation.
+ *
+ * Will not stop at NULL.
+ * Will not print NULL.
+ * Will not print any 1-byte character at a location specified in except array.
+ * Will print up to length 1-byte characters.
+ *
+ * @param id
+ *   The file descriptor to output to.
+ * @param string
+ *   The string to output.
+ * @param length
+ *   The total number of characters to print.
+ * @param except
+ *   An array of locations within the given string to not print.
+ *   The array of locations is assumed to be in linear order.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not if there is nothing to print.
+ *   F_block (with error bit) if file descriptor is set to non-block and the write would result in a blocking operation.
+ *   F_buffer (with error bit) if the buffer is invalid.
+ *   F_file_closed (with error bit) if file is not open.
+ *   F_file_descriptor (with error bit) if the file descriptor is invalid.
+ *   F_file_type_directory (with error bit) if file descriptor represents a directory.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_interrupted (with error bit) if interrupt was received.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see write()
+ */
+#ifndef _di_f_print_to_except_
+  extern f_return_status f_print_to_except(const int id, const f_string_t string, const f_string_length_t length, const f_string_lengths_t except);
+#endif // _di_f_print_to_except_
+
+/**
+ * Similar to a c-library dprintf, except that this prints a given dynamic string.
+ *
+ * The string is printed as-is without interpretation.
+ *
+ * Will not stop at NULL.
+ * Will not print NULL.
+ * Will not print any 1-byte character at a location specified in except array.
+ * Will print up to the length of the buffer.
+ *
+ * @param output
+ *   The file to output to, including standard streams such as stdout and stderr.
+ * @param buffer
+ *   The string to output.
+ * @param except
+ *   An array of locations within the given string to not print.
+ *   The array of locations is assumed to be in linear order.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not if there is nothing to print.
+ *   F_block (with error bit) if file descriptor is set to non-block and the write would result in a blocking operation.
+ *   F_buffer (with error bit) if the buffer is invalid.
+ *   F_file_closed (with error bit) if file is not open.
+ *   F_file_descriptor (with error bit) if the file descriptor is invalid.
+ *   F_file_type_directory (with error bit) if file descriptor represents a directory.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_interrupted (with error bit) if interrupt was received.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see write()
+ */
+#ifndef _di_f_print_to_except_dynamic_
+  extern f_return_status f_print_to_except_dynamic(const int id, const f_string_static_t buffer, const f_string_lengths_t except);
+#endif // _di_f_print_to_except_dynamic_
+
+/**
+ * Similar to a c-library dprintf, except that this will only print a specific range in a given dynamic string.
+ *
+ * The string is printed as-is without interpretation.
+ *
+ * Will not stop at NULL.
+ * Will not print NULL.
+ * Will not print any 1-byte character at a location specified in except array.
+ * Will print up to the specified range within the buffer.
+ *
+ * @param output
+ *   The file to output to, including standard streams such as stdout and stderr.
+ * @param buffer
+ *   The string to output.
+ * @param range
+ *   The range within the provided string to print.
+ * @param except
+ *   An array of locations within the given string to not print.
+ *   The array of locations is assumed to be in linear order.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not if there is nothing to print.
+ *   F_block (with error bit) if file descriptor is set to non-block and the write would result in a blocking operation.
+ *   F_buffer (with error bit) if the buffer is invalid.
+ *   F_file_closed (with error bit) if file is not open.
+ *   F_file_descriptor (with error bit) if the file descriptor is invalid.
+ *   F_file_type_directory (with error bit) if file descriptor represents a directory.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_interrupted (with error bit) if interrupt was received.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see write()
+ */
+#ifndef _di_f_print_to_except_dynamic_partial_
+  extern f_return_status f_print_to_except_dynamic_partial(const int id, const f_string_static_t buffer, const f_string_range_t range, const f_string_lengths_t except);
+#endif // _di_f_print_to_except_dynamic_partial_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 670fd37a9865056ed38b9afaf241e7ba9bd0d323..2b5319e9537c580f78693c1bc0dd54d96c653cb2 100644 (file)
@@ -22,15 +22,67 @@ extern "C" {
   }
 #endif // !defined(_di_f_print_) || !defined(_di_f_print_dynamic_) || !defined(_di_f_print_dynamic_partial_)
 
+#if !defined(_di_f_print_except_) || !defined(_di_f_print_except_dynamic_) || !defined(_di_f_print_except_dynamic_partial_)
+  f_return_status private_f_print_except(FILE *output, const f_string_t string, const f_string_length_t length, const f_string_lengths_t except) {
+
+    if (!length) return F_data_not;
+
+    f_string_length_t j = 0;
+
+    for (register f_string_length_t i = 0; i < length; ++i) {
+      for (; j < except.used; j++) {
+        if (except.array[j] >= i) break;
+      } // for
+
+      if (j < except.used && except.array[j] == i) continue;
+
+      if (string[i]) {
+        if (!fputc(string[i], output)) {
+          return F_status_set_error(F_output);
+        }
+      }
+    } // for
+
+    return F_none;
+  }
+#endif // !defined(_di_f_print_except_) || !defined(_di_f_print_except_dynamic_) || !defined(_di_f_print_except_dynamic_partial_)
+
 #if !defined(_di_f_print_to_) || !defined(_di_f_print_dynamic_to_) || !defined(_di_f_print_dynamic_partial_to_)
   f_return_status private_f_print_to(const int id, const f_string_t string, const f_string_length_t length) {
 
     if (!length) return F_data_not;
 
-    for (register f_string_length_t i = 0; i < length; ++i) {
-      if (!string[i]) continue;
+    register f_string_length_t i = 0;
+    f_string_length_t start = 0;
+    f_string_length_t total = 0;
+
+    for (; i < length; ++i) {
+
+      if (string[i]) {
+        total++;
+        continue;
+      }
+
+      if (total) {
+        if (write(id, string + start, total) == -1) {
+          if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block);
+          if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+          if (errno == EFAULT) return F_status_set_error(F_buffer);
+          if (errno == EINTR) return F_status_set_error(F_interrupted);
+          if (errno == EINVAL) return F_status_set_error(F_parameter);
+          if (errno == EIO) return F_status_set_error(F_input_output);
+          if (errno == EISDIR) return F_status_set_error(F_file_type_directory);
 
-      if (write(id, string + i, 1) == -1) {
+          return F_status_set_error(F_output);
+        }
+      }
+
+      start = i + 1;
+      total = 0;
+    } // for
+
+    if (total) {
+      if (write(id, string + start, total) == -1) {
         if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block);
         if (errno == EBADF) return F_status_set_error(F_file_descriptor);
         if (errno == EFAULT) return F_status_set_error(F_buffer);
@@ -41,12 +93,71 @@ extern "C" {
 
         return F_status_set_error(F_output);
       }
-    } // for
+    }
 
     return F_none;
   }
 #endif // !defined(_di_f_print_to_) || !defined(_di_f_print_dynamic_to_) || !defined(_di_f_print_dynamic_partial_to_)
 
+#if !defined(_di_f_print_to_except_) || !defined(_di_f_print_to_except_dynamic_) || !defined(_di_f_print_to_except_dynamic_partial_)
+  f_return_status private_f_print_to_except(const int id, const f_string_t string, const f_string_length_t length, const f_string_lengths_t except) {
+
+    if (!length) return F_data_not;
+
+    register f_string_length_t i = 0;
+    f_string_length_t j = 0;
+    f_string_length_t start = 0;
+    f_string_length_t total = 0;
+
+    for (; i < length; ++i) {
+
+      for (; j < except.used; j++) {
+        if (except.array[j] >= i) break;
+      } // for
+
+      if (j >= except.used || except.array[j] != i) {
+        if (string[i]) {
+          total++;
+          continue;
+        }
+      }
+
+      if (total) {
+        if (write(id, string + start, total) == -1) {
+          if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block);
+          if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+          if (errno == EFAULT) return F_status_set_error(F_buffer);
+          if (errno == EINTR) return F_status_set_error(F_interrupted);
+          if (errno == EINVAL) return F_status_set_error(F_parameter);
+          if (errno == EIO) return F_status_set_error(F_input_output);
+          if (errno == EISDIR) return F_status_set_error(F_file_type_directory);
+
+          return F_status_set_error(F_output);
+        }
+      }
+
+      start = i + 1;
+      total = 0;
+    } // for
+
+    if (total) {
+      if (write(id, string + start, total) == -1) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block);
+        if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+        if (errno == EFAULT) return F_status_set_error(F_buffer);
+        if (errno == EINTR) return F_status_set_error(F_interrupted);
+        if (errno == EINVAL) return F_status_set_error(F_parameter);
+        if (errno == EIO) return F_status_set_error(F_input_output);
+        if (errno == EISDIR) return F_status_set_error(F_file_type_directory);
+
+        return F_status_set_error(F_output);
+      }
+    }
+
+    return F_none;
+  }
+#endif // !defined(_di_f_print_to_except_) || !defined(_di_f_print_to_except_dynamic_) || !defined(_di_f_print_to_except_dynamic_partial_)
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 56e40c79c281386b899a38f174c9105808778da5..0dbc3169190bf5240c904cd2d7b46092edbb80b2 100644 (file)
@@ -42,6 +42,35 @@ extern "C" {
 #endif // !defined(_di_f_print_) || !defined(_di_f_print_dynamic_) || !defined(_di_f_print_dynamic_partial_)
 
 /**
+ * Private implementation of f_print_except().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param output
+ *   The file to output to, including standard streams such as stdout and stderr.
+ * @param string
+ *   The string to output.
+ * @param length
+ *   The total number of characters to print.
+ * @param except
+ *   An array of locations within the given string to not print.
+ *   The array of locations is assumed to be in linear order.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not if length is 0.
+ *   F_output (with error bit) on failure.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_print_except()
+ * @see f_print_except_dynamic()
+ * @see f_print_except_dynamic_partial()
+ */
+#if !defined(_di_f_print_except_) || !defined(_di_f_print_except_dynamic_) || !defined(_di_f_print_except_dynamic_partial_)
+  extern f_return_status private_f_print_except(FILE *output, const f_string_t string, const f_string_length_t length, const f_string_lengths_t except) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_print_except_) || !defined(_di_f_print_except_dynamic_) || !defined(_di_f_print_except_dynamic_partial_)
+
+/**
  * Private implementation of f_print_to().
  *
  * Intended to be shared to each of the different implementation variations.
@@ -69,9 +98,44 @@ extern "C" {
  * @see f_print_to_dynamic()
  * @see f_print_to_dynamic_partial()
  */
-#if !defined(_di_f_print_to_) || !defined(_di_f_print_dynamic_to_) || !defined(_di_f_print_dynamic_partial_to_)
+#if !defined(_di_f_print_to_) || !defined(_di_f_print_to_dynamic_) || !defined(_di_f_print_to_dynamic_partial_)
   extern f_return_status private_f_print_to(const int id, const f_string_t string, const f_string_length_t length) f_gcc_attribute_visibility_internal;
-#endif // !defined(_di_f_print_to_) || !defined(_di_f_print_dynamic_to_) || !defined(_di_f_print_dynamic_partial_to_)
+#endif // !defined(_di_f_print_to_) || !defined(_di_f_print_to_dynamic_) || !defined(_di_f_print_to_dynamic_partial_)
+
+/**
+ * Private implementation of f_print_to().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param output
+ *   The file to output to, including standard streams such as stdout and stderr.
+ * @param string
+ *   The string to output.
+ * @param length
+ *   The total number of characters to print.
+ * @param except
+ *   An array of locations within the given string to not print.
+ *   The array of locations is assumed to be in linear order.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not if length is 0.
+ *   F_block (with error bit) if file descriptor is set to non-block and the write would result in a blocking operation.
+ *   F_buffer (with error bit) if the buffer is invalid.
+ *   F_file_closed (with error bit) if file is not open.
+ *   F_file_descriptor (with error bit) if the file descriptor is invalid.
+ *   F_file_type_directory (with error bit) if file descriptor represents a directory.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_interrupted (with error bit) if interrupt was received.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_print_to_except()
+ * @see f_print_to_except_dynamic()
+ * @see f_print_to_except_dynamic_partial()
+ */
+#if !defined(_di_f_print_to_except_) || !defined(_di_f_print_to_except_dynamic_) || !defined(_di_f_print_to_except_dynamic_partial_)
+  extern f_return_status private_f_print_to_except(const int id, const f_string_t string, const f_string_length_t length, const f_string_lengths_t except) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_print_to_except_) || !defined(_di_f_print_to_except_dynamic_) || !defined(_di_f_print_to_except_dynamic_partial_)
 
 #ifdef __cplusplus
 } // extern "C"