Add document about Gfile related objects.

This commit is contained in:
Toshio Sekiya 2021-03-12 14:45:24 +09:00
parent c8d7adcb51
commit dda0a704cd
9 changed files with 564 additions and 13 deletions

1
.gitignore vendored
View file

@ -25,6 +25,7 @@ src/turtle/_build
src/temp
src/le
doc/GFile_example/_build
html/*
latex/*

54
doc/GFile_example/copy.c Normal file
View file

@ -0,0 +1,54 @@
/* Samples of GFile related objects */
/* Copy file program */
/* This function uses 'g_input_stream_read' and 'g_output_stream_write'. */
#include <gio/gio.h>
void
usage () {
g_printerr ("Usage: copy file1 file2\n");
exit (1);
}
#define MAXBUF 4096
int
main (int argc, char **argv) {
GFile *file1, *file2;
GFileInputStream *istream;
GFileOutputStream *ostream;
char buf[MAXBUF];
gssize size;
GError *err = NULL;
int status = 0;
if (argc != 3)
usage();
file1 = g_file_new_for_commandline_arg (argv[1]);
file2 = g_file_new_for_commandline_arg (argv[2]);
if (! (istream = g_file_read (file1, NULL, &err))) {
g_warning ("%s\n", err->message);
return 1;
}
if (! (ostream = g_file_replace (file2, NULL, TRUE, G_FILE_CREATE_NONE, NULL, &err))) {
g_warning ("%s\n", err->message);
return 1;
}
while ((size = g_input_stream_read (G_INPUT_STREAM (istream), buf, MAXBUF, NULL, &err)) > 0) {
if ((size = g_output_stream_write (G_OUTPUT_STREAM (ostream), buf, (gsize) size, NULL, &err)) < 0)
break;
}
if (size < 0) {
g_warning ("%s\n", err->message);
status = 1;
}
if (! (g_input_stream_close (G_INPUT_STREAM (istream), NULL, &err))) {
g_warning ("%s\n", err->message);
status = 1;
}
if (! (g_output_stream_close (G_OUTPUT_STREAM (ostream), NULL, &err))) {
g_warning ("%s\n", err->message);
status = 1;
}
return status;
}

View file

@ -0,0 +1,27 @@
/* Samples of GFile related objects */
/* Copy file program */
/* This function uses 'g_input_stream_read' and 'g_output_stream_write'. */
#include <gio/gio.h>
void
usage () {
g_printerr ("Usage: gfile_object (file|uri)\n");
exit (1);
}
int
main (int argc, char **argv) {
GFile *file;
GType type;
if (argc != 2)
usage();
file = g_file_new_for_commandline_arg (argv[1]);
type = G_OBJECT_TYPE (file);
g_print ("%s\n", g_type_name (type));
while (type = g_type_parent (type))
g_print ("%s\n", g_type_name (type));
return 0;
}

View file

@ -0,0 +1,11 @@
project('gio_samples', 'c')
compiler = meson.get_compiler('c')
giodep = dependency('gio-2.0')
executable('readline', 'readline.c', dependencies: giodep, install: false)
executable('copy', 'copy.c', dependencies: giodep, install: false)
executable('gfile_object', 'gfile_object.c', dependencies: giodep, install: false)
run_command('ruby', '../../src2md.rb', 'readme.src.md', 'readme.md')

View file

@ -0,0 +1,84 @@
/* Samples of GFile related objects */
/* Functions here has "sgf" prefix. Sgf is an acronym of "Sample of GFile". */
/* List a file */
/* This program shows how to read lines from a file. */
#include <gio/gio.h>
#include <glib/gprintf.h>
void
usage () {
g_printerr ("Usage: readline file\n");
exit (1);
}
/* Inputstream objects */
/* GInputStream */
/* +----- GFileInputStream */
/* +--+-- GFilterInputStream */
/* +--+-- GBufferedInputStream */
/* +----- GDataInputStream */
GDataInputStream *
sgf_open (GFile *file) {
g_return_val_if_fail (G_IS_FILE (file), NULL);
GFileInputStream *stream;
GDataInputStream *dstream;
GError *err;
if (! (stream = g_file_read (file, NULL, &err))) {
g_warning ("%s\n", err->message);
return NULL;
}
/* 'dstream' is a different instance from 'stream' instance. */
/* 'dstream' has "base-stream" property, which is a property of GFilterInputStream, and the property points 'stream'. */
/* GBufferedInputStream uses base-stream to read (input) data from its source. */
/* Therefore, 'dstream' reads a line through the IO interface of 'stream'. */
dstream = g_data_input_stream_new (G_INPUT_STREAM (stream));
return dstream;
}
char *
sgf_readline (GDataInputStream *dstream) {
char *contents;
gsize length;
GError *err = NULL;
contents = g_data_input_stream_read_line_utf8 (dstream, &length, NULL, &err);
if (! contents && err) {
g_warning ("%s\n", err->message);
return NULL;
}
return contents; /* if contents == NULL, then it is EOF */
}
void
sgf_close (GDataInputStream *dstream) {
GError *err = NULL;
/* At the same time dstream closes, its base stream (GFileInputStream created by 'sgf_open') is also closed. */
/* Because the default of "close-base-stream" property (of GFilterInputStream which is an ancester of GDataInputStream) is TRUE */
if (! g_input_stream_close (G_INPUT_STREAM (dstream), NULL, &err))
g_warning ("%s\n", err->message);
}
/* ----- main ----- */
int
main (int argc, char **argv) {
GFile *file;
GDataInputStream *dstream;
char *line;
if (argc != 2)
usage ();
file = g_file_new_for_commandline_arg (argv[1]);
if (! (dstream = sgf_open (file)))
return -1; /* error */
while (line = sgf_readline (dstream))
g_printf ("%s\n", line);
sgf_close (dstream);
return 0;
}

213
doc/GFile_example/readme.md Normal file
View file

@ -0,0 +1,213 @@
# What are the files in this directory?
They are examples to show how to use GFile related objects such as GInputStream and GOutPutStream.
- `meson.build` is used by meson.
- `readline.c` is an example to show how to read lines from a file.
- `copy.c` is an example to show read and write stream functions with Gio objects.
- `gfile_object.c` shows the object implements GFile interface.
## Compilation
Type as follows on your command line.
1. `meson _build`
2. `ninja -C _build`
Then executable files `readline`, `copy` and `gfile_object` are created under `_build` directory.
## Execution
Readline prints the contents of a file.
The file is given to `readline` as an argument.
~~~
$ _build/readline readline.c
/* Samples of GFile related objects */
/* Functions here has "sgf" prefix. Sgf is an acronym of "Sample of GFile". */
/* List a file */
/* This program shows how to read lines from a file. */
#include <gio/gio.h>
void
usage () {
g_printerr ("Usage: readline file\n");
exit (1);
}
... ... ...
... ... ...
~~~
Readline can also prints a file through the internet.
~~~
$ _build/readline http://www7b.biglobe.ne.jp/~j87107/SINU/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
... ... ...
... ... ...
~~~
This is because GFile can be constructed for local path or uri.
Copy is given two arguments.
The first one is a source filename and the second one is a destination filename.
If the destination file is exist, it will be overwritten.
Before the overwriting, the destination file is backed up.
The backup file name is appended with tilde ('~').
~~~
$ ls
_build copy.c meson.build readline.c readme.md
$ _build/copy copy.c sample.txt
$ ls
_build copy.c meson.build readline.c readme.md sample.txt
$ diff copy.c sample.txt
$ _build/copy readline.c sample.txt
$ ls
_build copy.c meson.build readline.c readme.md sample.txt sample.txt~
$ diff readline.c sample.txt
$ diff copy.c sample.txt~
$
~~~
Files can be on the internet.
~~~
$ _build/copy http://www7b.biglobe.ne.jp/~j87107/SINU/Algebra.pdf algebra.pdf
$ ls
_build algebra.pdf copy.c meson.build readline.c readme.md sample.txt sample.txt~
~~~
Gfile_object shows the object implements GFile interface.
~~~
$ _build/gfile_object gfile_object.c
GLocalFile
GObject
$ _build/gfile_object http://www7b.biglobe.ne.jp/~j87107/SINU/Algebra.pdf
GDaemonFile
GObject
~~~
`g_file_new_for_path` creates GLocalFile object which implements GFile interface.
And it returns the pointer to the object as `GFile *`.
`g_file_new_for_uri` creates GDaemonFile object which implements GFile interface.
And it returns the pointer to the object as `GFile *`.
## GFile interface
GFile is an interface.
It is like a pathname.
If you want to read from a file or write to a file, you need to create a stream object.
`copy.c` creates GInputStream and GOutputStream to copy a file.
~~~C
1 /* Samples of GFile related objects */
2 /* Copy file program */
3 /* This function uses 'g_input_stream_read' and 'g_output_stream_write'. */
4
5 #include <gio/gio.h>
6
7 void
8 usage () {
9 g_printerr ("Usage: copy file1 file2\n");
10 exit (1);
11 }
12
13 #define MAXBUF 4096
14 int
15 main (int argc, char **argv) {
16 GFile *file1, *file2;
17 GFileInputStream *istream;
18 GFileOutputStream *ostream;
19 char buf[MAXBUF];
20 gssize size;
21 GError *err = NULL;
22 int status = 0;
23
24 if (argc != 3)
25 usage();
26 file1 = g_file_new_for_commandline_arg (argv[1]);
27 file2 = g_file_new_for_commandline_arg (argv[2]);
28 if (! (istream = g_file_read (file1, NULL, &err))) {
29 g_warning ("%s\n", err->message);
30 return 1;
31 }
32 if (! (ostream = g_file_replace (file2, NULL, TRUE, G_FILE_CREATE_NONE, NULL, &err))) {
33 g_warning ("%s\n", err->message);
34 return 1;
35 }
36 while ((size = g_input_stream_read (G_INPUT_STREAM (istream), buf, MAXBUF, NULL, &err)) > 0) {
37 if ((size = g_output_stream_write (G_OUTPUT_STREAM (ostream), buf, (gsize) size, NULL, &err)) < 0)
38 break;
39 }
40 if (size < 0) {
41 g_warning ("%s\n", err->message);
42 status = 1;
43 }
44 if (! (g_input_stream_close (G_INPUT_STREAM (istream), NULL, &err))) {
45 g_warning ("%s\n", err->message);
46 status = 1;
47 }
48 if (! (g_output_stream_close (G_OUTPUT_STREAM (ostream), NULL, &err))) {
49 g_warning ("%s\n", err->message);
50 status = 1;
51 }
52 return status;
53 }
54
~~~
## Stream objects
Stream objects have hierarchy.
~~~
GInputStream
+--+-- GFilterInputStream
| +--+-- GBufferedInputStream
| | +----- GDataInputStream
| +----- GConverterInputStream
+----- GFileInputStream
+----- GMemoryInputStream
+----- GUnixInputStream
~~~
GInputStream is the top parent object.
It is an abstract object.
Streams are created with specific objects such as files, memories and unix file descriptors.
For example, the following function creates a GFileInputStream.
~~~C
GFileInputStream *istream = g_file_read (GFile *file, GCancellable *cancellable, GError **error);
~~~
This stream is a child of GInputStream object, so you can apply any functions of GInputStream for `istream`.
For example,
~~~C
gssize size = g_input_stream_read (G_INPUT_STREAM (istream), void *buffer, gsize count, GCancellable *cancellable, GError **error);
~~~
This function reads data from `istream` and put them into `buffer`.
GDtaInputStream is used often.
It can read structured data such as sized data (byte, int16, int32 and int64) and lines (new line terminated string).
For example,
~~~C
GDataInputStream *dstream = g_data_input_stream_new (G_INPUT_STREAM (istream));
char *line = g_data_input_stream_read_line_utf8 (dstream, gsize *size, GCancellable *cancellable, GError **error);
~~~
The program above reads a line from `dstream`.

View file

@ -0,0 +1,160 @@
# What are the files in this directory?
They are examples to show how to use GFile related objects such as GInputStream and GOutPutStream.
- `meson.build` is used by meson.
- `readline.c` is an example to show how to read lines from a file.
- `copy.c` is an example to show read and write stream functions with Gio objects.
- `gfile_object.c` shows the object implements GFile interface.
## Compilation
Type as follows on your command line.
1. `meson _build`
2. `ninja -C _build`
Then executable files `readline`, `copy` and `gfile_object` are created under `_build` directory.
## Execution
Readline prints the contents of a file.
The file is given to `readline` as an argument.
~~~
$ _build/readline readline.c
/* Samples of GFile related objects */
/* Functions here has "sgf" prefix. Sgf is an acronym of "Sample of GFile". */
/* List a file */
/* This program shows how to read lines from a file. */
#include <gio/gio.h>
void
usage () {
g_printerr ("Usage: readline file\n");
exit (1);
}
... ... ...
... ... ...
~~~
Readline can also prints a file through the internet.
~~~
$ _build/readline http://www7b.biglobe.ne.jp/~j87107/SINU/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
... ... ...
... ... ...
~~~
This is because GFile can be constructed for local path or uri.
Copy is given two arguments.
The first one is a source filename and the second one is a destination filename.
If the destination file is exist, it will be overwritten.
Before the overwriting, the destination file is backed up.
The backup file name is appended with tilde ('~').
~~~
$ ls
_build copy.c meson.build readline.c readme.md
$ _build/copy copy.c sample.txt
$ ls
_build copy.c meson.build readline.c readme.md sample.txt
$ diff copy.c sample.txt
$ _build/copy readline.c sample.txt
$ ls
_build copy.c meson.build readline.c readme.md sample.txt sample.txt~
$ diff readline.c sample.txt
$ diff copy.c sample.txt~
$
~~~
Files can be on the internet.
~~~
$ _build/copy http://www7b.biglobe.ne.jp/~j87107/SINU/Algebra.pdf algebra.pdf
$ ls
_build algebra.pdf copy.c meson.build readline.c readme.md sample.txt sample.txt~
~~~
Gfile_object shows the object implements GFile interface.
~~~
$ _build/gfile_object gfile_object.c
GLocalFile
GObject
$ _build/gfile_object http://www7b.biglobe.ne.jp/~j87107/SINU/Algebra.pdf
GDaemonFile
GObject
~~~
`g_file_new_for_path` creates GLocalFile object which implements GFile interface.
And it returns the pointer to the object as `GFile *`.
`g_file_new_for_uri` creates GDaemonFile object which implements GFile interface.
And it returns the pointer to the object as `GFile *`.
## GFile interface
GFile is an interface.
It is like a pathname.
If you want to read from a file or write to a file, you need to create a stream object.
`copy.c` creates GInputStream and GOutputStream to copy a file.
@@@include
copy.c
@@@
## Stream objects
Stream objects have hierarchy.
~~~
GInputStream
+--+-- GFilterInputStream
| +--+-- GBufferedInputStream
| | +----- GDataInputStream
| +----- GConverterInputStream
+----- GFileInputStream
+----- GMemoryInputStream
+----- GUnixInputStream
~~~
GInputStream is the top parent object.
It is an abstract object.
Streams are created with specific objects such as files, memories and unix file descriptors.
For example, the following function creates a GFileInputStream.
~~~C
GFileInputStream *istream = g_file_read (GFile *file, GCancellable *cancellable, GError **error);
~~~
This stream is a child of GInputStream object, so you can apply any functions of GInputStream for `istream`.
For example,
~~~C
gssize size = g_input_stream_read (G_INPUT_STREAM (istream), void *buffer, gsize count, GCancellable *cancellable, GError **error);
~~~
This function reads data from `istream` and put them into `buffer`.
GDtaInputStream is used often.
It can read structured data such as sized data (byte, int16, int32 and int64) and lines (new line terminated string).
For example,
~~~C
GDataInputStream *dstream = g_data_input_stream_new (G_INPUT_STREAM (istream));
char *line = g_data_input_stream_read_line_utf8 (dstream, gsize *size, GCancellable *cancellable, GError **error);
~~~
The program above reads a line from `dstream`.

View file

@ -71,14 +71,17 @@ require 'pathname'
# Listings package supports only C, ruby, xml and make.
# Bison, lex, markdown and meson aren't supported.
def src2md srcmd, md
def src2md srcmd, md, type="gfm"
# parameters:
# srcmd: .src.md file's path. source
# md: .md file's path. destination
src_buf = IO.readlines srcmd
src_dir = File.dirname srcmd
md_dir = File.dirname md
type = File.basename md_dir # type of the target. gfm, html or latex
type_dir = File.basename md_dir # type of the target. gfm, html or latex
if type_dir == "gfm" || type_dir == "html" || type_dir == "latex"
type = type_dir
end
# phase 1
# @@@if - @@@elif - @@@else - @@@end
@ -202,8 +205,8 @@ def src2md srcmd, md
md_buf << "~~~\n"
end
end
else # This can't happen.
md_buf << "~~~"
else
md_buf << "~~~\n"
end
ln_width = tmp_buf.size.to_s.length
n = 1

View file

@ -7,18 +7,16 @@ exec ruby -x "$0" "$@"
require_relative 'lib/lib_src2md.rb'
def usage
$stderr.print "Usage: ruby srcd2md.rb src.md_file md_file width\n"
$stderr.print " The width is used to fold lines in indented or fenced code blocks.\n"
$stderr.print " If the width is negative, no lines are folded.\n"
$stderr.print "Usage: ruby srcd2md.rb src.md_file md_file type\n"
$stderr.print " type is gfm (default), html or latex.\n"
end
if ARGV.size != 3
if ARGV.size == 2
src2md ARGV[0], ARGV[1]
elsif ARGV.size == 3
src2md ARGV[0], ARGV[1], ARGV[2]
else
usage
exit 1
end
srcmd = ARGV[0]
md = ARGV[1]
width = ARGV[2]
src2md srcmd, md, width.to_i