formout.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /* functions writing lists out to text and data files
  2. Copyright (C) 2006 Dennis Furey
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software Foundation,
  13. Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  14. */
  15. #include <avm/common.h>
  16. #include <avm/error.h>
  17. #include <avm/branches.h>
  18. #include <avm/chrcodes.h>
  19. #include <avm/rawio.h>
  20. #include <avm/formin.h>
  21. #include <avm/fnames.h>
  22. #include <avm/formout.h>
  23. #include <ctype.h>
  24. /* non-zero means static variables are initialized */
  25. static int initialized = 0;
  26. /* the character code for a line break */
  27. static int line_break = 10;
  28. void
  29. avm_output (repository, filename, preamble, contents, trace_mode)
  30. FILE *repository;
  31. char *filename;
  32. list preamble;
  33. list contents;
  34. int trace_mode;
  35. /* Iff the preamble is non-empty, the contents are output in raw
  36. data format. Iff the first character of the preamble is an
  37. exclamation point, the file is marked executable. If the
  38. preamble is empty, the contents are output as text. */
  39. {
  40. int datum;
  41. list line;
  42. int ioerror;
  43. int incomment;
  44. int executable;
  45. if (!initialized)
  46. avm_initialize_formout ();
  47. executable = ioerror = incomment = 0;
  48. if (!repository)
  49. avm_internal_error (24);
  50. else if (preamble)
  51. {
  52. if (preamble->head ? 1 : !!(preamble->tail))
  53. {
  54. incomment = 0;
  55. while (preamble ? !ioerror : 0)
  56. {
  57. line = preamble->head;
  58. if (!incomment)
  59. {
  60. if (putc ('#', repository) != '#')
  61. avm_non_fatal_io_error ("can't write to", filename, errno);
  62. }
  63. incomment = 0;
  64. while (line ? !ioerror : 0)
  65. {
  66. if (line->head ? (line->head->characteristic ? 1 : 0) : 0)
  67. {
  68. incomment = (line->head->characterization == '\\');
  69. if (!executable)
  70. executable = ((line->head == preamble->head->head) ? (line->head->characterization == '!') : 0);
  71. if (putc (line->head->characterization, repository) != line->head->characterization)
  72. avm_non_fatal_io_error ("can't write to", filename, errno);
  73. else if (line->head->characterization == line_break)
  74. avm_error ("invalid output preamble format");
  75. }
  76. else
  77. {
  78. if ((datum = avm_character_code (line->head)) < 0)
  79. avm_error ("invalid output preamble format");
  80. else if (datum == line_break)
  81. avm_error ("invalid output preamble format");
  82. else if (putc (datum, repository) != datum)
  83. avm_non_fatal_io_error ("can't write to", filename, errno);
  84. else
  85. {
  86. incomment = (datum == '\\');
  87. executable = executable ? 1 : ((line->head == preamble->head->head) ? (datum == '!') : 0);
  88. }
  89. }
  90. line = line->tail;
  91. }
  92. preamble = preamble->tail;
  93. if (putc (line_break, repository) != line_break)
  94. avm_non_fatal_io_error ("can't write to", filename, errno);
  95. }
  96. }
  97. if (executable ? (repository != stdout) : 0)
  98. chmod (filename, S_IXUSR | S_IXGRP | S_IXOTH | S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
  99. avm_send_list (repository, contents, filename);
  100. }
  101. else
  102. {
  103. while (contents ? !ioerror : 0)
  104. {
  105. line = contents->head;
  106. while (line ? !ioerror : 0)
  107. {
  108. if (line->head ? (line->head->characteristic ? 1 : 0) : 0)
  109. {
  110. if (trace_mode)
  111. printf ("%c", line->head->characterization);
  112. if (putc (line->head->characterization, repository) != line->head->characterization)
  113. avm_non_fatal_io_error ("can't write to", filename, errno);
  114. }
  115. else if ((datum = avm_character_code (line->head)) < 0)
  116. avm_error ("invalid text format (code 3)");
  117. else if (putc (datum, repository) != datum)
  118. avm_non_fatal_io_error ("can't write to", filename, errno);
  119. else if (trace_mode)
  120. printf ("%c", datum);
  121. line = line->tail;
  122. }
  123. if (trace_mode ? (contents->tail) : 0)
  124. printf ("\n");
  125. if ((contents = contents->tail) ? putc (line_break, repository) != line_break : 0)
  126. avm_non_fatal_io_error ("can't write to", filename, errno);
  127. }
  128. }
  129. }
  130. void
  131. avm_output_as_directed (data, ask_to_overwrite_mode, verbose_mode)
  132. list data;
  133. int ask_to_overwrite_mode;
  134. int verbose_mode;
  135. /* This outputs a list of files specified in the form of a list
  136. of quadruples ((overwrite,path),(preamble,contents)). If the
  137. rewrite field is non-null, the file is opened for writing, but
  138. if it's null, the file is opened for appending. For security
  139. reasons, standard output is done last, so that malicious
  140. virtual code applications can't alter the query messages by
  141. using stdout to clobber the console.
  142. Thanks to Norm Pleszkoch for the part about buffered input.
  143. */
  144. {
  145. int authorized;
  146. FILE *repository;
  147. char *filename;
  148. char *program_name;
  149. char key;
  150. list old, front_preamble, back_preamble, front_contents, back_contents;
  151. #define current_file (data->head)
  152. #define current_overwrite (current_file->head->head)
  153. #define current_path (current_file->head->tail)
  154. #define current_preamble (current_file->tail->head)
  155. #define current_contents (current_file->tail->tail)
  156. if (!initialized)
  157. avm_initialize_formout ();
  158. program_name = avm_program_name ();
  159. front_preamble = back_preamble = front_contents = back_contents = NULL;
  160. while (data)
  161. {
  162. if (!(current_file) ? 1 : !(current_file->tail) ? 1 : !(current_file->head))
  163. avm_error ("invalid file specification");
  164. else if (!(filename = avm_path_name (current_path)))
  165. {
  166. avm_enqueue (&front_preamble, &back_preamble, avm_copied (current_preamble));
  167. avm_enqueue (&front_contents, &back_contents, avm_copied (current_contents));
  168. }
  169. else
  170. {
  171. if (!(authorized = !(ask_to_overwrite_mode ? repository = fopen (filename, "rb") : 0)))
  172. {
  173. if (fclose (repository))
  174. avm_non_fatal_io_error ("can't close", filename, errno);
  175. for (key = ' '; (authorized = (key != 'N')) && (key != 'Y');)
  176. {
  177. printf ("%s: %s `%s'? (y/n) ", program_name, current_overwrite ? "overwrite" : "append to", filename);
  178. fflush (stdout); /* usually stdout is buffered. (sometimes stderr is also) */
  179. key = toupper (getchar ());
  180. if (key != '\n')
  181. for (; '\n' != getchar (););
  182. }
  183. } /* flush out stdin up to (and including) the '\n' */
  184. if (authorized)
  185. {
  186. if (!(repository = fopen (filename, current_overwrite ? "wb" : "ab")))
  187. avm_non_fatal_io_error ("can't write", filename, errno);
  188. else
  189. {
  190. if (verbose_mode)
  191. {
  192. if(current_overwrite)
  193. printf ("%s: writing `%s'\n", program_name, filename);
  194. else
  195. printf ("%s: appending `%s'\n", program_name, filename);
  196. }
  197. avm_output (repository, filename, current_preamble, current_contents, 0);
  198. if (fclose (repository))
  199. avm_non_fatal_io_error ("can't close", filename, errno);
  200. }
  201. }
  202. else if (verbose_mode)
  203. {
  204. if(current_overwrite)
  205. printf ("%s: not writing `%s'\n", program_name, filename);
  206. else
  207. printf ("%s: not appending `%s'\n", program_name, filename);
  208. }
  209. free (filename);
  210. }
  211. data = data->tail;
  212. }
  213. while (front_preamble)
  214. {
  215. avm_output (stdout, "standard output", front_preamble->head, front_contents->head, 0);
  216. front_preamble = avm_copied ((old = front_preamble)->tail);
  217. avm_dispose (old);
  218. front_contents = avm_copied ((old = front_contents)->tail);
  219. avm_dispose (old);
  220. }
  221. }
  222. void
  223. avm_put_bytes (bytes)
  224. list bytes;
  225. /* This takes a list of character representations and sends it to
  226. standard output as characters. */
  227. {
  228. int ioerror;
  229. int datum;
  230. ioerror = 0;
  231. if (!initialized)
  232. avm_initialize_formout ();
  233. while (bytes ? !ioerror : 0)
  234. {
  235. if ((datum = avm_character_code (bytes->head)) < 0)
  236. avm_error ("invalid text format (code 2)");
  237. else if (ioerror = (putc (datum, stdout) != datum))
  238. avm_non_fatal_io_error ("can't write to", "standard output", errno);
  239. bytes = bytes->tail;
  240. }
  241. }
  242. void
  243. avm_initialize_formout ()
  244. /* This initializes some static data. */
  245. {
  246. if (initialized)
  247. return;
  248. initialized = 1;
  249. avm_initialize_lists ();
  250. avm_initialize_fnames ();
  251. avm_initialize_branches ();
  252. avm_initialize_chrcodes ();
  253. avm_initialize_formin ();
  254. }
  255. void
  256. avm_count_formout ()
  257. /* This is a hook for future use. */
  258. {
  259. if (!initialized)
  260. return;
  261. initialized = 0;
  262. }