Update to new Glk 0.7.2 code
[projects/chimara/chimara.git] / libchimara / glkunix.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <libchimara/glk.h>
4 #include <libchimara/glkstart.h>
5 #include "chimara-glk-private.h"
6 #include "magic.h"
7 #include "fileref.h"
8 #include "stream.h"
9
10 extern GPrivate *glk_data_key;
11
12 /**
13  * glkunix_stream_open_pathname:
14  * @pathname: A path to a file, in the system filename encoding. 
15  * @textmode: Bitfield with one or more of the <code>fileusage_</code> constants.
16  * @rock: The new stream's rock value.
17  *
18  * Opens an arbitrary file, in read-only mode. Note that this function is
19  * <emphasis>only</emphasis> available during glkunix_startup_code(). It is 
20  * inherently non-portable; it should not and cannot be called from inside 
21  * glk_main().
22  * 
23  * Returns: A new stream, or %NULL if the file operation failed.
24  */
25 strid_t
26 glkunix_stream_open_pathname(char *pathname, glui32 textmode, glui32 rock)
27 {
28         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
29         
30         if(!glk_data->in_startup)
31                 ILLEGAL("glkunix_stream_open_pathname() may only be called from "
32                                 "glkunix_startup_code().");
33         
34         g_return_val_if_fail(pathname, NULL);
35         g_return_val_if_fail(strlen(pathname) > 0, NULL);
36         
37         frefid_t fileref = fileref_new(pathname, rock, textmode, filemode_Read);
38         return file_stream_new(fileref, filemode_Read, rock, FALSE);
39 }
40
41 /**
42  * glkunix_set_base_file:
43  * @filename: A path to a file, in the system filename encoding.
44  *
45  * Sets the library's idea of the <quote>current directory</quote> for the 
46  * executing program. The argument should be the name of a file (not a 
47  * directory). When this is set, glk_fileref_create_by_name() will create files 
48  * in the same directory as that file, and glk_fileref_create_by_prompt() will 
49  * base default filenames off of the file. If this is not called, the library 
50  * works in the Unix current working directory, and picks reasonable default 
51  * defaults.
52  */
53 void 
54 glkunix_set_base_file(char *filename)
55 {
56         g_return_if_fail(filename);
57         g_return_if_fail(strlen(filename) > 0);
58
59         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
60         
61         gchar *dirname = g_path_get_dirname(filename);
62         if(!g_file_test(dirname, G_FILE_TEST_IS_DIR))
63         {
64                 WARNING_S("Not a directory", dirname);
65                 g_free(dirname);
66                 return;
67         }
68         
69         glk_data->current_dir = dirname;
70 }
71
72 /* Internal function: parse the command line, getting only the arguments
73  requested by the plugin in its glkunix_arguments structure. Algorithm copied
74  from CheapGlk by Andrew Plotkin. */
75 gboolean
76 parse_command_line(glkunix_argumentlist_t glkunix_arguments[], int argc, char *argv[], glkunix_startup_t *data)
77 {
78         GSList *arglist = NULL, *iter;
79         int arg;
80         
81         /* Now some argument-parsing. This is probably going to hurt. */
82     for(arg = 1; arg < argc; arg++) 
83         {
84         glkunix_argumentlist_t *argform;
85         char *numptr;
86         
87         for(argform = glkunix_arguments; argform->argtype != glkunix_arg_End; argform++) 
88                 {
89             if(argform->name[0] == '\0') 
90                         {
91                 if(((argform->argtype == glkunix_arg_ValueFollows ||
92                                     argform->argtype == glkunix_arg_ValueCanFollow) && 
93                                     argv[arg][0] != '-') ||
94                                     (argform->argtype == glkunix_arg_NumberValue &&
95                                         (atoi(argv[arg]) != 0 || argv[arg][0] == '0')))
96                                 {
97                     arglist = g_slist_prepend(arglist, argv[arg]);
98                                 }
99                                 else
100                                         continue;
101             }
102                         
103             else if((argform->argtype == glkunix_arg_NumberValue)
104                 && !strncmp(argv[arg], argform->name, strlen(argform->name))
105                 && (numptr = argv[arg] + strlen(argform->name))
106                 && (atoi(numptr) != 0 || numptr[0] == '0')) 
107                         {
108                 arglist = g_slist_prepend(arglist, argv[arg]);
109                         }
110                         
111             else if(strcmp(argv[arg], argform->name) == 0) 
112                         {
113                 if(argform->argtype == glkunix_arg_ValueFollows) 
114                                 {
115                     if(arg + 1 >= argc) {
116                                                 g_slist_free(arglist);
117                                                 return FALSE; /* No more arguments, and this one is invalid */
118                                         }
119                     arglist = g_slist_prepend(arglist, argv[arg++]);
120                                         arglist = g_slist_prepend(arglist, argv[arg]);
121                 }
122
123                                 else if(argform->argtype == glkunix_arg_NoValue) 
124                     arglist = g_slist_prepend(arglist, argv[arg]);
125
126                 else if(argform->argtype == glkunix_arg_ValueCanFollow) 
127                                 {
128                                         arglist = g_slist_prepend(arglist, argv[arg]);
129                     if(arg + 1 < argc && argv[arg + 1][0] != '-') 
130                         arglist = g_slist_prepend(arglist, argv[++arg]);
131                 }
132                 
133                                 else if(argform->argtype == glkunix_arg_NumberValue) 
134                                 {
135                     if(arg + 1 >= argc || (atoi(argv[arg + 1]) == 0 && argv[arg + 1][0] != '0')) 
136                                         {
137                                                 g_slist_free(arglist);
138                                                 return FALSE;
139                                         }
140                     arglist = g_slist_prepend(arglist, argv[arg++]);
141                                         arglist = g_slist_prepend(arglist, argv[arg]);
142                 }
143                 else 
144                                 {
145                                         g_slist_free(arglist);
146                                         return FALSE;
147                                 }
148             }
149                 }
150         }
151         
152         data->argc = g_slist_length(arglist) + 1;
153         data->argv = g_new0(char *, data->argc);
154         arglist = g_slist_reverse(arglist);
155         for(iter = arglist, arg = 1; iter; iter = g_slist_next(iter), arg++)
156                 data->argv[arg] = g_strdup(iter->data);
157         g_slist_free(arglist);
158         
159         return TRUE;
160 }