1.1 --- a/test_files/programs/clip.c Wed Jan 24 21:12:41 2024 +0100
1.2 +++ b/test_files/programs/clip.c Wed Jan 24 21:17:37 2024 +0100
1.3 @@ -1,7 +1,7 @@
1.4 /*
1.5 * Show lines from a file.
1.6 *
1.7 - * Copyright (C) 2022, 2023 Paul Boddie <paul@boddie.org.uk>
1.8 + * Copyright (C) 2022, 2023, 2024 Paul Boddie <paul@boddie.org.uk>
1.9 *
1.10 * This program is free software; you can redistribute it and/or
1.11 * modify it under the terms of the GNU General Public License as
1.12 @@ -25,10 +25,21 @@
1.13 #include <stdlib.h>
1.14 #include <string.h>
1.15
1.16 +/* NOTE: For inclusion in the C library: stream acquisition and access. */
1.17 +
1.18 #include <fsclient/client.h>
1.19 #include <systypes/env.h>
1.20 #include <systypes/fcntl.h>
1.21
1.22 +static file_t *input, *output;
1.23 +static char output_buffer[256];
1.24 +
1.25 +#define _fprintf(file, s, ...) \
1.26 +( \
1.27 + sprintf(output_buffer, s, ##__VA_ARGS__), \
1.28 + client_write(file, output_buffer, strlen(output_buffer)) \
1.29 +)
1.30 +
1.31
1.32
1.33 /* Read a line from the file. */
1.34 @@ -37,74 +48,65 @@
1.35 {
1.36 static char buf[256];
1.37 static offset_t current = 0, limit = 0;
1.38 - char *newline = NULL;
1.39 + static int next_lineno = 1;
1.40 + char *newline;
1.41 +
1.42 + /* Advance to the next line if previously found. */
1.43
1.44 - do
1.45 + if (next_lineno > *lineno)
1.46 + *lineno = next_lineno;
1.47 +
1.48 + /* Obtain file content. */
1.49 +
1.50 + if (!limit)
1.51 {
1.52 - /* Obtain file content. */
1.53 + limit = client_read(file, buf, 256);
1.54
1.55 if (!limit)
1.56 {
1.57 - limit = client_read(file, buf, 256);
1.58 + *start = NULL;
1.59 + *end = NULL;
1.60 + return 0;
1.61 + }
1.62 + }
1.63
1.64 - if (!limit)
1.65 - {
1.66 - *start = NULL;
1.67 - *end = NULL;
1.68 - return 0;
1.69 - }
1.70 + /* Find newline. */
1.71
1.72 - current = 0;
1.73 + newline = (char *) memchr(buf + current, (int) '\n', limit - current);
1.74 + *start = (buf + current);
1.75 +
1.76 + /* Return final line fragment, potentially leaving more available text. */
1.77
1.78 - /* Start of line at start of buffer. */
1.79 + if (newline != NULL)
1.80 + {
1.81 + /* Advance the line number when reading again. */
1.82 +
1.83 + next_lineno = (*lineno) + 1;
1.84 +
1.85 + /* Define the end of the line and the start of the next line. */
1.86
1.87 - if (newline != NULL)
1.88 - {
1.89 - current += 1;
1.90 - *start = buf;
1.91 - *end = (char *) memchr(buf + current, (int) '\n', limit - current);
1.92 + *end = newline + 1;
1.93 + current = *end - buf;
1.94
1.95 - if (*end == NULL)
1.96 - *end = buf + limit;
1.97 -
1.98 - return 1;
1.99 - }
1.100 + if (current >= limit)
1.101 + {
1.102 + current = 0;
1.103 + limit = 0;
1.104 }
1.105
1.106 - /* Find newline. */
1.107 -
1.108 - newline = (char *) memchr(buf + current, (int) '\n', limit - current);
1.109 + return 1;
1.110 + }
1.111
1.112 - if (newline != NULL)
1.113 - {
1.114 - (*lineno)++;
1.115 - current = newline - (char *) buf + 1;
1.116 -
1.117 - /* Start of line before end of buffer. */
1.118 -
1.119 - if (current < limit)
1.120 - {
1.121 - *start = newline + 1;
1.122 - *end = (char *) memchr(buf + current, (int) '\n', limit - current);
1.123 + /* Or return mid-line fragment reaching the limit of the available text. */
1.124
1.125 - if (*end == NULL)
1.126 - *end = buf + limit;
1.127 -
1.128 - return 1;
1.129 - }
1.130 -
1.131 - /* Otherwise, reset the buffer to read the start of line. */
1.132 + else
1.133 + {
1.134 + *end = buf + limit;
1.135 + current = 0;
1.136 + limit = 0;
1.137
1.138 - else
1.139 - limit = 0;
1.140 - }
1.141 -
1.142 - /* No newline: read more data. */
1.143 -
1.144 - else
1.145 - limit = 0;
1.146 + return 1;
1.147 }
1.148 - while (1);
1.149 }
1.150
1.151
1.152 @@ -112,50 +114,56 @@
1.153 int main(int argc, char *argv[])
1.154 {
1.155 file_t *file;
1.156 - int i, startline, numlines;
1.157 + int lineno, startline, numlines;
1.158 char *start, *end;
1.159
1.160 + /* NOTE: For inclusion in the C library: stream acquisition and access. */
1.161 +
1.162 + input = client_get_stream(ENV_INPUT_STREAM_NAME, O_RDONLY);
1.163 + output = client_get_stream(ENV_OUTPUT_STREAM_NAME, O_WRONLY);
1.164 +
1.165 if (argc < 4)
1.166 return 1;
1.167
1.168 - file = client_open(argv[1], O_RDONLY);
1.169 + if (!strcmp(argv[1], "-"))
1.170 + file = input;
1.171 + else
1.172 + file = client_open(argv[1], O_RDONLY);
1.173
1.174 if (!client_opened(file))
1.175 {
1.176 if (file != NULL)
1.177 - printf("Error: %s\n", l4sys_errtostr(file->error));
1.178 + _fprintf(output, "Error: %s\n", l4sys_errtostr(file->error));
1.179 else
1.180 - printf("Could not open file.\n");
1.181 + _fprintf(output, "Could not open file.\n");
1.182
1.183 - while (1);
1.184 + client_flush(output);
1.185 + return 1;
1.186 }
1.187
1.188 startline = atoi(argv[2]);
1.189 numlines = atoi(argv[3]);
1.190
1.191 - i = 1;
1.192 - while (i < startline)
1.193 + lineno = 1;
1.194 +
1.195 + while (lineno < startline + numlines)
1.196 {
1.197 - if (!readline(file, &i, &start, &end))
1.198 + if (!readline(file, &lineno, &start, &end))
1.199 {
1.200 - printf("EOF error at line %d.\n", i);
1.201 + _fprintf(output, "EOF error at line %d.\n", lineno);
1.202 + client_flush(output);
1.203 return 1;
1.204 }
1.205 +
1.206 + if ((lineno >= startline) && (lineno < startline + numlines))
1.207 + client_write(output, start, end - start);
1.208 }
1.209
1.210 - while (i < startline + numlines)
1.211 - {
1.212 - fwrite(start, sizeof(char), end - start, stdout);
1.213 - if (!readline(file, &i, &start, &end))
1.214 - {
1.215 - printf("EOF error at line %d.\n", i);
1.216 - return 1;
1.217 - }
1.218 - }
1.219 + client_close(file);
1.220
1.221 - fputs("\n\n", stdout);
1.222 + /* NOTE: For inclusion in the C library: stream acquisition and access. */
1.223
1.224 - client_close(file);
1.225 + client_flush(output);
1.226
1.227 return 0;
1.228 }