~ubuntu-branches/ubuntu/natty/pd-zexy/natty

« back to all changes in this revision

Viewing changes to src/msgfile.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard, IOhannes m zmölnig, Jonas Smedegaard
  • Date: 2010-08-20 12:17:41 UTC
  • mfrom: (2.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20100820121741-4kxozn8b9rhee9fr
Tags: 2.2.3-1
* New upstream version

[ IOhannes m zmölnig ]
* Adopt package, on behalf of Multimedia Team.
  Closes: #546964
* Simply debian/rules with CDBS, and don't unconditionally strip
  binaries.
  Closes: #437763
* Install into /usr/lib/pd/extra/zexy/. Document usage in REAME.Debian
  and warn about change in NEWS.
* git'ify package. Add Vcs-* stanzas to control file.
* Use dpkg source format 3.0 (quilt). Drop build-dependency on quilt.

[ Jonas Smedegaard ]
* Enable CDBS copyright-check routine.
* Add copyright and licensing header to debian/rules.
* Add myself as uploader.
* Rewrite debian/copyright using rev. 135 of draft DEP5 format.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
 *
 
3
 * zexy - implementation file
 
4
 *
 
5
 * copyleft (c) IOhannes m zm�lnig
 
6
 *
 
7
 *   1999:forum::f�r::uml�ute:2004
 
8
 *
 
9
 *   institute of electronic music and acoustics (iem)
 
10
 *
 
11
 ******************************************************
 
12
 *
 
13
 * license: GNU General Public License v.2
 
14
 *
 
15
 ******************************************************/
 
16
 
 
17
 
 
18
/*  
 
19
    this is heavily based on code from [textfile],
 
20
    which is part of pd and written by Miller S. Pucket
 
21
    pd (and thus [textfile]) come with their own license
 
22
*/
 
23
 
 
24
#include "zexy.h"
 
25
 
 
26
#ifdef __WIN32__
 
27
# include <io.h>
 
28
#else
 
29
# include <unistd.h>
 
30
#endif
 
31
 
 
32
#include <stdio.h>
 
33
#include <fcntl.h>
 
34
#include <string.h>
 
35
 
 
36
 
 
37
 
 
38
/* ****************************************************************************** */
 
39
/* msgfile : save and load messages... */
 
40
 
 
41
#define PD_MODE 0
 
42
#define CR_MODE 1
 
43
#define CSV_MODE 2
 
44
/* modi
 
45
   PD : separate items by ' '; seperate lines by ";\n"
 
46
   looks like a PD-file
 
47
   CR : separate items by ' '; seperate lines by " \n"
 
48
   how you would expect a file to look like
 
49
   CSV: separate items by ','; seperate lines by " \n"
 
50
   spreadsheet: each argument gets its own column
 
51
*/
 
52
 
 
53
 
 
54
typedef struct _msglist {
 
55
  int n;
 
56
  t_atom *thislist;
 
57
 
 
58
  void *next;
 
59
  void *previous;  
 
60
} t_msglist;
 
61
 
 
62
typedef struct _msgfile
 
63
{
 
64
  t_object x_obj;              /* everything */
 
65
  t_outlet *x_secondout;        /* "done" */
 
66
 
 
67
  int mode;
 
68
 
 
69
  t_msglist *start;
 
70
 
 
71
  t_msglist *current;         /* pointer to our list */
 
72
  t_msglist *previous; /* just in case we lost "current" */
 
73
 
 
74
  t_symbol *x_dir;
 
75
  t_canvas *x_canvas;
 
76
 
 
77
  char eol, separator;
 
78
 
 
79
} t_msgfile;
 
80
 
 
81
static t_class *msgfile_class;
 
82
 
 
83
 
 
84
 
 
85
 
 
86
 
 
87
/* ************************************************************************ */
 
88
/* forward declarations                                                     */
 
89
 
 
90
static void msgfile_end(t_msgfile *x);
 
91
static void msgfile_goto(t_msgfile *x, t_float f);
 
92
 
 
93
/* ************************************************************************ */
 
94
/* help functions                                                           */
 
95
 
 
96
static int node_wherearewe(t_msgfile *x)
 
97
{
 
98
  int counter = 0;
 
99
  t_msglist *cur = x->start;
 
100
 
 
101
  while (cur && cur->next && cur!=x->current) {
 
102
    counter++;
 
103
    cur = cur->next;
 
104
  }
 
105
 
 
106
  return (cur->thislist)?counter:-1;
 
107
}
 
108
 
 
109
static void write_currentnode(t_msgfile *x, int ac, t_atom *av)
 
110
{
 
111
  /* append list to the current node list */
 
112
  
 
113
  t_msglist *cur=x->current;
 
114
  t_atom *ap=NULL;
 
115
  int newsize = 0; 
 
116
 
 
117
  if(!cur || (ac && av && A_SYMBOL==av->a_type && gensym("")==atom_getsymbol(av))){
 
118
    /* ignoring empty symbols! */
 
119
    return;
 
120
  }
 
121
 
 
122
  newsize = cur->n + ac; 
 
123
 
 
124
  ap = (t_atom *)getbytes(newsize * sizeof(t_atom));
 
125
  memcpy(ap, cur->thislist, cur->n * sizeof(t_atom));
 
126
  cur->thislist = ap;
 
127
  memcpy(cur->thislist + cur->n, av, ac * sizeof(t_atom));
 
128
 
 
129
  cur->n = newsize;
 
130
}
 
131
 
 
132
static void delete_currentnode(t_msgfile *x)
 
133
{
 
134
  if (x&&x->current){
 
135
    t_msglist *dummy = x->current;
 
136
    t_msglist *nxt=0;
 
137
    t_msglist *prv=0;
 
138
 
 
139
    if(dummy){
 
140
      nxt=dummy->next;
 
141
      prv=dummy->previous;
 
142
 
 
143
      if(dummy==x->start) {
 
144
        x->start=nxt;
 
145
      }
 
146
 
 
147
      freebytes(dummy->thislist, sizeof(dummy->thislist));
 
148
      dummy->thislist = 0;
 
149
      dummy->n = 0;
 
150
      dummy->next=0;
 
151
      dummy->previous=0;
 
152
 
 
153
      freebytes(dummy, sizeof(t_msglist));
 
154
 
 
155
      dummy=0;
 
156
    }
 
157
 
 
158
    if (nxt) nxt->previous = prv;
 
159
    if (prv) prv->next     = nxt;
 
160
    
 
161
    x->current = (nxt)?nxt:prv;
 
162
    if(x->current)
 
163
      x->previous=x->current->previous;
 
164
    else
 
165
      x->previous=prv;
 
166
 
 
167
  }
 
168
}
 
169
 
 
170
static void delete_emptynodes(t_msgfile *x)
 
171
{
 
172
  x->current=x->start;
 
173
  x->previous=0;
 
174
  if (!x->current) return;
 
175
 
 
176
  while (x->current && x->current->next) {
 
177
    if (!x->current->thislist) delete_currentnode(x);
 
178
    else {
 
179
      x->previous=x->current;
 
180
      x->current = x->current->next;
 
181
    }
 
182
  }
 
183
}
 
184
 
 
185
static void add_currentnode(t_msgfile *x)
 
186
 
187
  /* add (after the current node) a node at the current position (do not write the listbuf !!!) */
 
188
  t_msglist *newnode = (t_msglist *)getbytes(sizeof(t_msglist));
 
189
  t_msglist  *prv, *nxt, *cur=x->current;
 
190
 
 
191
  newnode->n = 0;
 
192
  newnode->thislist = 0;
 
193
 
 
194
  prv = cur;
 
195
  nxt = (cur)?cur->next:0;
 
196
 
 
197
  newnode->next = nxt;
 
198
  newnode->previous = prv;
 
199
 
 
200
  if (prv) prv->next = newnode;
 
201
  if (nxt) nxt->previous = newnode;
 
202
 
 
203
  x->current = newnode;
 
204
  x->previous=prv;
 
205
 
 
206
  if(!x->start) /* it's the first line in the buffer */
 
207
    x->start=x->current;
 
208
}
 
209
static void insert_currentnode(t_msgfile *x)
 
210
{  /* insert (add before the current node) a node (do not write a the listbuf !!!) */
 
211
  t_msglist *newnode;
 
212
  t_msglist  *prv, *nxt, *cur = x->current;
 
213
 
 
214
  if (!(cur && cur->thislist)) {
 
215
    add_currentnode(x);
 
216
  } else {
 
217
    newnode = (t_msglist *)getbytes(sizeof(t_msglist));
 
218
 
 
219
    newnode->n = 0;
 
220
    newnode->thislist = 0;
 
221
 
 
222
    nxt = cur;
 
223
    prv = (cur)?cur->previous:0;
 
224
 
 
225
    newnode->next = nxt;
 
226
    newnode->previous = prv;
 
227
 
 
228
    if (prv) prv->next = newnode;
 
229
    if (nxt) nxt->previous = newnode;
 
230
 
 
231
    x->previous=prv;
 
232
    x->current = newnode;
 
233
    if(0==prv) {
 
234
      /* oh, we have a new start! */
 
235
      x->start = newnode;
 
236
    }
 
237
  }
 
238
}
 
239
 
 
240
/* delete from line "start" to line "stop"
 
241
 * if "stop" is negative, delete from "start" to the end
 
242
 */
 
243
static void delete_region(t_msgfile *x, int start, int stop)
 
244
{
 
245
  int n;
 
246
  int newwhere, oldwhere = node_wherearewe(x);
 
247
 
 
248
  /* get the number of lists in the buffer */
 
249
  t_msglist *dummy = x->start;
 
250
  int counter = 0;
 
251
 
 
252
  /* go to the end of the buffer */
 
253
  while (dummy && dummy->next) {
 
254
    counter++;
 
255
    dummy = dummy->next;
 
256
  }
 
257
 
 
258
  if ((stop > counter) || (stop == -1)) stop = counter;
 
259
  if ((stop+1) && (start > stop)) return;
 
260
  if (stop == 0) return;
 
261
 
 
262
  newwhere = (oldwhere < start)?oldwhere:( (oldwhere < stop)?start:start+(oldwhere-stop));
 
263
  n = stop - start;
 
264
 
 
265
  msgfile_goto(x, start);
 
266
 
 
267
  while (n--) delete_currentnode(x);
 
268
 
 
269
  if (newwhere+1) msgfile_goto(x, newwhere);
 
270
  else msgfile_end(x);
 
271
}
 
272
 
 
273
 
 
274
static int atomcmp(t_atom *this, t_atom *that)
 
275
{
 
276
  if (this->a_type != that->a_type) return 1;
 
277
 
 
278
  switch (this->a_type) {
 
279
  case A_FLOAT:
 
280
    return !(atom_getfloat(this) == atom_getfloat(that));
 
281
    break;
 
282
  case A_SYMBOL:
 
283
    return strcmp(atom_getsymbol(this)->s_name, atom_getsymbol(that)->s_name);
 
284
    break;
 
285
  case A_POINTER:
 
286
    return !(this->a_w.w_gpointer == that->a_w.w_gpointer);
 
287
    break;
 
288
  default:
 
289
    return 0;
 
290
  }
 
291
 
 
292
  return 1;
 
293
}
 
294
 
 
295
 
 
296
static void msgfile_binbuf2listbuf(t_msgfile *x, t_binbuf *bbuf)
 
297
{
 
298
  int ac = binbuf_getnatom(bbuf);
 
299
  t_atom *ap = binbuf_getvec(bbuf);
 
300
 
 
301
  while (ac--) {
 
302
    if (ap->a_type == A_SEMI) {
 
303
      add_currentnode(x);
 
304
    } else {
 
305
      write_currentnode(x, 1, ap);
 
306
    }
 
307
    ap++;
 
308
  }
 
309
 
 
310
  delete_emptynodes(x);
 
311
}
 
312
 
 
313
 
 
314
 
 
315
 
 
316
 
 
317
/* ************************************************************************ */
 
318
/* object methods                                                           */
 
319
 
 
320
static void msgfile_rewind(t_msgfile *x)
 
321
{
 
322
  //  while (x->current && x->current->previous) x->current = x->current->previous;    
 
323
  x->current = x->start;
 
324
  x->previous=0;
 
325
}
 
326
static void msgfile_end(t_msgfile *x)
 
327
{
 
328
  if (!x->current) return;
 
329
  while (x->current->next) {
 
330
    x->previous= x->current;
 
331
    x->current = x->current->next;
 
332
  }
 
333
  
 
334
}
 
335
static void msgfile_goto(t_msgfile *x, t_float f)
 
336
{
 
337
  int i = f;
 
338
 
 
339
  if (i<0) return;
 
340
  if (!x->current) return;
 
341
  msgfile_rewind(x);
 
342
 
 
343
  while (i-- && x->current->next) {
 
344
    x->previous= x->current;
 
345
    x->current = x->current->next;
 
346
  }
 
347
}
 
348
static void msgfile_skip(t_msgfile *x, t_float f)
 
349
{
 
350
  int i;
 
351
  int counter = 0;
 
352
 
 
353
  t_msglist *dummy = x->start;
 
354
 
 
355
  if (!f) return;
 
356
  if (!x->current) return;
 
357
 
 
358
  while (dummy->next && dummy!=x->current) {
 
359
    counter++;
 
360
    dummy=dummy->next;
 
361
  }
 
362
 
 
363
  i = counter + f;
 
364
  if (i<0) i=0;
 
365
 
 
366
  msgfile_goto(x, i);
 
367
}
 
368
 
 
369
static void msgfile_clear(t_msgfile *x)
 
370
{
 
371
  /* find the beginning */
 
372
  msgfile_rewind(x);
 
373
 
 
374
  while (x->current) {
 
375
    delete_currentnode(x);
 
376
  }
 
377
}
 
378
 
 
379
static void msgfile_delete(t_msgfile *x, t_symbol *s, int ac, t_atom *av)
 
380
{
 
381
  if (ac==1) {
 
382
    int pos = atom_getfloat(av);
 
383
    int oldwhere = node_wherearewe(x);
 
384
 
 
385
    if (pos<0) return;
 
386
    if (oldwhere > pos) oldwhere--;
 
387
    msgfile_goto(x, pos);
 
388
    delete_currentnode(x);
 
389
    msgfile_goto(x, oldwhere);
 
390
  } else if (ac==2) {
 
391
    int pos1 = atom_getfloat(av++);
 
392
    int pos2 = atom_getfloat(av);
 
393
 
 
394
    if ((pos1 < pos2) || (pos2 == -1)) {
 
395
      if (pos2+1) delete_region(x, pos1, pos2+1);
 
396
      else delete_region(x, pos1, -1);
 
397
    } else {
 
398
      delete_region(x, pos1+1, -1);
 
399
      delete_region(x, 0, pos2);
 
400
    }
 
401
  } else delete_currentnode(x);
 
402
}
 
403
 
 
404
static void msgfile_add(t_msgfile *x, t_symbol *s, int ac, t_atom *av)
 
405
{
 
406
  msgfile_end(x);
 
407
  add_currentnode(x);
 
408
  write_currentnode(x, ac, av);
 
409
}
 
410
static void msgfile_add2(t_msgfile *x, t_symbol *s, int ac, t_atom *av)
 
411
{
 
412
  msgfile_end(x);
 
413
  if (x->current->previous) x->current = x->current->previous;
 
414
  write_currentnode(x, ac, av);
 
415
  if (x->current->next) {
 
416
    x->previous= x->current;
 
417
    x->current = x->current->next;
 
418
  }
 
419
}
 
420
static void msgfile_append(t_msgfile *x, t_symbol *s, int ac, t_atom *av)
 
421
{
 
422
  add_currentnode(x);
 
423
  write_currentnode(x, ac, av);
 
424
}
 
425
static void msgfile_append2(t_msgfile *x, t_symbol *s, int ac, t_atom *av)
 
426
{
 
427
  if (x->current->thislist) write_currentnode(x, ac, av);
 
428
  else msgfile_append(x, s, ac, av);
 
429
}
 
430
static void msgfile_insert(t_msgfile *x, t_symbol *s, int ac, t_atom *av)
 
431
{
 
432
  t_msglist *cur = x->current;
 
433
  insert_currentnode(x);
 
434
  write_currentnode(x, ac, av);
 
435
  x->current = cur;
 
436
}
 
437
static void msgfile_insert2(t_msgfile *x, t_symbol *s, int ac, t_atom *av)
 
438
{
 
439
  t_msglist *cur = x->current;
 
440
  if ((x->current) && (x->current->previous)) x->current = x->current->previous;
 
441
  write_currentnode(x, ac, av);
 
442
  x->current = cur;
 
443
}
 
444
 
 
445
static void msgfile_set(t_msgfile *x, t_symbol *s, int ac, t_atom *av)
 
446
{
 
447
  msgfile_clear(x);
 
448
  msgfile_add(x, s, ac, av);
 
449
}
 
450
 
 
451
static void msgfile_replace(t_msgfile *x, t_symbol *s, int ac, t_atom *av)
 
452
{
 
453
  if(x->current) {
 
454
    if(x->current->thislist) {
 
455
      freebytes(x->current->thislist, sizeof(x->current->thislist));
 
456
    }
 
457
    x->current->thislist = 0;
 
458
    x->current->n = 0;
 
459
  } else {
 
460
    add_currentnode(x);
 
461
  }
 
462
  write_currentnode(x, ac, av);
 
463
}
 
464
 
 
465
static void msgfile_flush(t_msgfile *x)
 
466
{
 
467
  t_msglist *cur = x->start;
 
468
  while (cur && cur->thislist) {
 
469
    outlet_list(x->x_obj.ob_outlet, gensym("list"), cur->n, cur->thislist);
 
470
    cur = cur->next;
 
471
  }
 
472
}
 
473
static void msgfile_this(t_msgfile *x)
 
474
{
 
475
  if ((x->current) && (x->current->thislist)) {
 
476
    outlet_list(x->x_obj.ob_outlet, gensym("list"), x->current->n, x->current->thislist);
 
477
  } else {
 
478
    outlet_bang(x->x_secondout);
 
479
  }
 
480
}
 
481
static void msgfile_next(t_msgfile *x)
 
482
{
 
483
  if ((x->current) && (x->current->next)) {
 
484
    t_msglist *next = x->current->next;
 
485
    if (next->thislist)
 
486
      outlet_list(x->x_obj.ob_outlet, gensym("list"), next->n, next->thislist);
 
487
    else outlet_bang(x->x_secondout);
 
488
  } else outlet_bang(x->x_secondout);
 
489
}
 
490
static void msgfile_prev(t_msgfile *x)
 
491
{
 
492
  t_msglist*prev=0;
 
493
 
 
494
  if ((x->current) && (x->current->previous)) {
 
495
    prev = x->current->previous;
 
496
  } else if (x->previous) {
 
497
    prev = x->previous;
 
498
  }
 
499
  if(prev) {
 
500
    if (prev->thislist)
 
501
      outlet_list(x->x_obj.ob_outlet, gensym("list"), prev->n, prev->thislist);
 
502
    else outlet_bang(x->x_secondout);
 
503
 
 
504
  } else outlet_bang(x->x_secondout);
 
505
}
 
506
 
 
507
static void msgfile_bang(t_msgfile *x)
 
508
 
509
  if ((x->current) && (x->current->thislist)) {
 
510
    t_msglist*cur=x->current;
 
511
    x->current=cur->next;
 
512
    x->previous=cur;
 
513
    outlet_list(x->x_obj.ob_outlet, gensym("list"), cur->n, cur->thislist);
 
514
  } else {
 
515
    outlet_bang(x->x_secondout);
 
516
  }
 
517
}
 
518
 
 
519
static void msgfile_find(t_msgfile *x, t_symbol *s, int ac, t_atom *av)
 
520
{
 
521
  t_msglist *found = 0;
 
522
  t_msglist *cur=x->current;
 
523
 
 
524
  while (cur) {
 
525
    int n = cur->n;
 
526
    int equal = 1;
 
527
    t_atom *that = av;
 
528
    t_atom *this = cur->thislist;
 
529
 
 
530
    if(0==this){
 
531
      cur=cur->next;
 
532
      continue;
 
533
    }
 
534
    
 
535
    if (ac < n) n = ac;
 
536
 
 
537
    while (n-->0) {
 
538
      if ( (strcmp("*", atom_getsymbol(that)->s_name) && atomcmp(that, this)) ) {
 
539
        equal = 0;
 
540
      }
 
541
 
 
542
      that++;
 
543
      this++;
 
544
    }
 
545
 
 
546
    if (equal) {
 
547
      found = cur;
 
548
      break;
 
549
    }
 
550
 
 
551
    cur=cur->next;
 
552
  }
 
553
 
 
554
  if(found){
 
555
    x->current = found;
 
556
    x->previous= found->previous;
 
557
    outlet_float(x->x_secondout, node_wherearewe(x));
 
558
    if(found->n && found->thislist)
 
559
      outlet_list(x->x_obj.ob_outlet, gensym("list"), found->n, found->thislist);
 
560
  } else {
 
561
    outlet_bang(x->x_secondout);
 
562
  }
 
563
}
 
564
 
 
565
static void msgfile_where(t_msgfile *x)
 
566
{
 
567
  if (x->current && x->current->thislist) outlet_float(x->x_secondout, node_wherearewe(x));
 
568
  else outlet_bang(x->x_secondout);
 
569
}
 
570
 
 
571
 
 
572
static void msgfile_sort(t_msgfile *x, t_symbol *s0, t_symbol*s1, t_symbol*r)
 
573
{
 
574
  post("sorting not implemented yet: '%s', '%s' -> '%s'", s0->s_name, s1->s_name, r->s_name);
 
575
 
 
576
 
 
577
#if 0
 
578
  int step = argc, n;
 
579
  t_atom *atombuf = (t_atom *)getbytes(sizeof(t_atom) * argc);
 
580
  t_float *buf;
 
581
  t_int   *idx;
 
582
 
 
583
  int i, loops = 1;
 
584
 
 
585
  sort_buffer(x, argc, argv);
 
586
  buf = x->buffer;
 
587
  idx = x->indices;
 
588
 
 
589
  while (step > 1) {
 
590
    step = (step % 2)?(step+1)/2:step/2;
 
591
 
 
592
    i = loops;
 
593
    loops += 2;
 
594
 
 
595
    while(i--) { /* there might be some optimization in here */
 
596
      for (n=0; n<(argc-step); n++) {
 
597
        if (buf[n] > buf[n+step]) {
 
598
          t_int   i_tmp = idx[n];
 
599
          t_float f_tmp = buf[n];
 
600
          buf[n]        = buf[n+step];
 
601
          buf[n+step]   = f_tmp;
 
602
          idx[n]        = idx[n+step];
 
603
          idx[n+step]   = i_tmp;
 
604
        }
 
605
      }
 
606
    }
 
607
  }
 
608
#endif
 
609
 
 
610
}
 
611
 
 
612
 
 
613
/* ********************************** */
 
614
/* file I/O                           */
 
615
 
 
616
static void msgfile_read2(t_msgfile *x, t_symbol *filename, t_symbol *format)
 
617
{
 
618
  int rmode = 0;
 
619
 
 
620
  int fd=0;
 
621
  FILE*fil=NULL;
 
622
  long readlength, length, pos;
 
623
  char filnam[MAXPDSTRING];
 
624
  char buf[MAXPDSTRING], *bufptr, *readbuf;
 
625
  char *charbinbuf=NULL, *cbb;
 
626
  int charbinbuflength=0;
 
627
  char*dirname=canvas_getdir(x->x_canvas)->s_name;
 
628
 
 
629
  int mode = x->mode;
 
630
  char separator, eol;
 
631
 
 
632
  t_binbuf *bbuf = binbuf_new();
 
633
 
 
634
#ifdef __WIN32__
 
635
  rmode |= O_BINARY;
 
636
#endif
 
637
 
 
638
  if ((fd = open_via_path(dirname,
 
639
                          filename->s_name, "", buf, &bufptr, MAXPDSTRING, 0)) < 0) {
 
640
 
 
641
    if((fd=open(filename->s_name, rmode)) < 0) {
 
642
      pd_error(x, "can't open in %s/%s",  dirname, filename->s_name);
 
643
      return;
 
644
    } else {
 
645
      sprintf(filnam, "%s", filename->s_name);
 
646
    }
 
647
  } else {
 
648
    close(fd);
 
649
    sprintf(filnam, "%s/%s", buf, bufptr);
 
650
  }
 
651
 
 
652
  fil=fopen(filnam, "rb");
 
653
  fseek(fil, 0, SEEK_END);
 
654
  if(fil==NULL) {
 
655
    pd_error(x, "could not open '%s'", filnam);
 
656
    return;
 
657
  }
 
658
  length=ftell(fil);
 
659
  fseek(fil, 0, SEEK_SET);
 
660
 
 
661
  if (!(readbuf = t_getbytes(length))) {
 
662
    pd_error(x, "msgfile_read: could not reserve %d bytes to read into", length);
 
663
    close(fd);
 
664
    return;
 
665
  }
 
666
 
 
667
  if (gensym("cr")==format) {
 
668
    mode = CR_MODE;
 
669
  } else if (gensym("csv")==format) {
 
670
    mode = CSV_MODE;
 
671
  } else if (gensym("pd")==format) {
 
672
    mode = PD_MODE;
 
673
  } else if (*format->s_name)
 
674
    pd_error(x, "msgfile_read: unknown flag: %s", format->s_name);
 
675
 
 
676
  switch (mode) {
 
677
  case CR_MODE:
 
678
    separator = ' ';
 
679
    eol = '\n';
 
680
    break;
 
681
  case CSV_MODE:
 
682
    separator = ',';
 
683
    eol = ' ';
 
684
    break;
 
685
  default:
 
686
    separator = '\n';
 
687
    eol = ';';
 
688
    break;
 
689
  }
 
690
 
 
691
  /* read */
 
692
  if ((readlength = fread(readbuf, sizeof(char), length, fil)) < length) {
 
693
    pd_error(x, "msgfile_read: unable to read %s: %d of %d", filnam, readlength, length);
 
694
    fclose(fil);
 
695
    t_freebytes(readbuf, length);
 
696
    return;
 
697
  }
 
698
 
 
699
  /* close */
 
700
  fclose(fil);
 
701
 
 
702
  /* convert separators and eols to what pd expects in a binbuf*/
 
703
  bufptr=readbuf;
 
704
 
 
705
# define MSGFILE_HEADROOM 1024
 
706
  charbinbuflength=2*length+MSGFILE_HEADROOM;
 
707
 
 
708
  charbinbuf=(char*)getbytes(charbinbuflength);
 
709
  
 
710
  cbb=charbinbuf;
 
711
  for(pos=0; pos<charbinbuflength; pos++)charbinbuf[pos]=0;
 
712
 
 
713
  *cbb++=';';
 
714
  pos=1;
 
715
  while (readlength--) {
 
716
    if(pos>=charbinbuflength){
 
717
      pd_error(x, "msgfile: read error (headroom %d too small!)", MSGFILE_HEADROOM);
 
718
      goto read_error;
 
719
      break;
 
720
    }
 
721
    if (*bufptr == separator) {
 
722
      *cbb = ' ';
 
723
    } else if (*bufptr==eol) {
 
724
      *cbb++=';';pos++;
 
725
      *cbb='\n';
 
726
    } else {
 
727
      *cbb=*bufptr;
 
728
    }
 
729
 
 
730
    bufptr++;
 
731
    cbb++;
 
732
    pos++;
 
733
  }
 
734
 
 
735
  /* convert to binbuf */
 
736
  binbuf_text(bbuf, charbinbuf, charbinbuflength);
 
737
  msgfile_binbuf2listbuf(x, bbuf);
 
738
 
 
739
 read_error:
 
740
  binbuf_free(bbuf);
 
741
  t_freebytes(readbuf, length);
 
742
  t_freebytes(charbinbuf, charbinbuflength);
 
743
}
 
744
static void msgfile_read(t_msgfile *x, t_symbol *filename, t_symbol *format)
 
745
{
 
746
  msgfile_clear(x);
 
747
  msgfile_read2(x, filename, format);
 
748
}
 
749
 
 
750
static void msgfile_write(t_msgfile *x, t_symbol *filename, t_symbol *format)
 
751
{
 
752
  char buf[MAXPDSTRING];
 
753
  t_binbuf *bbuf = binbuf_new();
 
754
  t_msglist *cur = x->start;
 
755
 
 
756
  char *mytext = 0, *dumtext;
 
757
  char filnam[MAXPDSTRING];
 
758
  int textlen = 0, i;
 
759
 
 
760
  char separator, eol;
 
761
  int mode = x->mode;
 
762
 
 
763
  FILE *f=0;
 
764
 
 
765
  while(cur) {
 
766
    binbuf_add(bbuf, cur->n, cur->thislist);
 
767
    binbuf_addsemi(bbuf);
 
768
    cur = cur->next;
 
769
  }
 
770
    
 
771
  canvas_makefilename(x->x_canvas, filename->s_name,
 
772
                      buf, MAXPDSTRING);
 
773
 
 
774
  if(format&&gensym("")!=format) {
 
775
    if(gensym("cr")==format) {
 
776
      mode = CR_MODE;
 
777
    } else if(gensym("csv")==format) {
 
778
      mode = CSV_MODE;
 
779
    } else if(gensym("pd")==format) {
 
780
      mode = PD_MODE;
 
781
    } else if(format&&format->s_name) {
 
782
      pd_error(x, "msgfile_write: ignoring unknown flag: %s", format->s_name);
 
783
    }
 
784
  }
 
785
 
 
786
  switch (mode) {
 
787
  case CR_MODE:
 
788
    separator = ' ';
 
789
    eol = ' ';
 
790
    break;
 
791
  case CSV_MODE:
 
792
    separator = ',';
 
793
    eol = ' ';
 
794
    break;
 
795
  default:
 
796
    separator = ' ';
 
797
    eol = ';';
 
798
    break;
 
799
  }
 
800
  
 
801
  binbuf_gettext(bbuf, &mytext, &textlen);
 
802
  dumtext = mytext;
 
803
  i = textlen;
 
804
 
 
805
  while(i--) {
 
806
    if (*dumtext==' ')
 
807
      *dumtext=separator;
 
808
    else if ((*dumtext==';') && (dumtext[1]=='\n'))
 
809
      *dumtext = eol;
 
810
    dumtext++;
 
811
  }
 
812
  
 
813
  /* open */
 
814
  sys_bashfilename(filename->s_name, filnam);
 
815
  if (!(f = fopen(filnam, "w"))) {
 
816
    pd_error(x, "msgfile : failed to open %s", filnam);
 
817
  } else {
 
818
    /* write */
 
819
    if (fwrite(mytext, textlen*sizeof(char), 1, f) < 1) {
 
820
      pd_error(x, "msgfile : failed to write %s", filnam);
 
821
    }
 
822
  }
 
823
  /* close */
 
824
  if (f) fclose(f);
 
825
 
 
826
  binbuf_free(bbuf);
 
827
}
 
828
 
 
829
/* ********************************** */
 
830
/* misc                               */
 
831
 
 
832
static void msgfile_print(t_msgfile *x)
 
833
{
 
834
  t_msglist *cur = x->start;
 
835
  int j=0;
 
836
  post("--------- msgfile contents: -----------");
 
837
 
 
838
  while (cur) {
 
839
    t_msglist *dum=cur;
 
840
    int i;
 
841
    j++;
 
842
    startpost("line %d:", j);
 
843
    for (i = 0; i < dum->n; i++) {
 
844
      t_atom *a = dum->thislist + i;
 
845
      postatom(1, a);
 
846
    }
 
847
    endpost();
 
848
    cur = cur->next;
 
849
  }
 
850
}
 
851
 
 
852
static void msgfile_help(t_msgfile *x)
 
853
{
 
854
  post("\n%c msgfile\t:: handle and store files of lists", HEARTSYMBOL);
 
855
  post("goto <n>\t: goto line <n>"
 
856
       "\nrewind\t\t: goto the beginning of the file"
 
857
       "\nend\t\t: goto the end of the file"
 
858
       "\nskip <n>\t: move relatively to current position"
 
859
       "\nbang\t\t: output current line and move forward"
 
860
       "\nprev\t\t: output previous line"
 
861
       "\nthis\t\t: output this line"
 
862
       "\nnext\t\t: output next line"
 
863
       "\nflush\t\t: output all lines");
 
864
  post("set <list>\t: clear the buffer and add <list>"
 
865
       "\nadd <list>\t: add <list> at the end of the file"
 
866
       "\nadd2 <list>\t: append <list> to the last line of the file"
 
867
       "\nappend <list>\t: append <list> at the current position"
 
868
       "\nappend2 <list>\t: append <list> to the current line"
 
869
       "\ninsert <list>\t: insert <list> at the current position"
 
870
       "\ninsert2 <list>\t: append <list> to position [current-1]"
 
871
       "\nreplace <list>\t: replace current line by <list>"
 
872
       "\ndelete [<pos> [<pos2>]]\t: delete lines or regions"
 
873
       "\nclear\t\t: delete the whole buffer");
 
874
  post("where\t\t: output current position"
 
875
       "\nfind <list>\t: search for <list>"
 
876
       "\nread <file> [<format>]\t: read <file> as <format>"
 
877
       "\nwrite <file> [<format>]\t: write <file> as <format>"
 
878
       "\n\t\t: valid <formats> are\t: PD, CR, CSV"
 
879
       "\n\nprint\t\t: show buffer (for debugging)"
 
880
       "\nhelp\t\t: show this help");
 
881
  post("creation: \"msgfile [<format>]\": <format> defines fileaccess-mode(default is PD)");
 
882
}
 
883
static void msgfile_free(t_msgfile *x)
 
884
{
 
885
  msgfile_clear(x);
 
886
  freebytes(x->current, sizeof(t_msglist));
 
887
}
 
888
 
 
889
static void *msgfile_new(t_symbol *s, int argc, t_atom *argv)
 
890
{
 
891
  t_msgfile *x = (t_msgfile *)pd_new(msgfile_class);
 
892
 
 
893
  /* an empty node indicates the end of our listbuffer */
 
894
  x->current = 0;
 
895
  x->start   = 0;
 
896
  x->previous= 0;
 
897
 
 
898
  x->mode=PD_MODE; /* that's the default */
 
899
 
 
900
  if ((argc==1) && (argv->a_type == A_SYMBOL)) {
 
901
    t_symbol*mode=atom_getsymbol(argv);
 
902
    if      (gensym("cr") == mode) x->mode = CR_MODE;
 
903
    else if (gensym("csv")== mode) x->mode = CSV_MODE;
 
904
    else if (gensym("pd") == mode) x->mode = PD_MODE;
 
905
    else {
 
906
      pd_error(x, "msgfile: unknown argument %s", argv->a_w.w_symbol->s_name);
 
907
    }
 
908
  }
 
909
 
 
910
  outlet_new(&x->x_obj, &s_list);
 
911
  x->x_secondout = outlet_new(&x->x_obj, &s_float);
 
912
  x->x_canvas = canvas_getcurrent();
 
913
 
 
914
  x->eol=' ';
 
915
  x->separator=',';
 
916
 
 
917
  return (x);
 
918
}
 
919
 
 
920
void msgfile_setup(void)
 
921
{
 
922
  msgfile_class = class_new(gensym("msgfile"), (t_newmethod)msgfile_new,
 
923
                            (t_method)msgfile_free, sizeof(t_msgfile), 0, A_GIMME, 0);
 
924
  class_addmethod(msgfile_class, (t_method)msgfile_goto, gensym("goto"), A_DEFFLOAT, 0);
 
925
  class_addmethod(msgfile_class, (t_method)msgfile_rewind, gensym("rewind"), 0);
 
926
  class_addmethod(msgfile_class, (t_method)msgfile_rewind, gensym("begin"), 0);
 
927
  class_addmethod(msgfile_class, (t_method)msgfile_end, gensym("end"), 0);
 
928
 
 
929
  class_addmethod(msgfile_class, (t_method)msgfile_next, gensym("next"), A_DEFFLOAT, 0);
 
930
  class_addmethod(msgfile_class, (t_method)msgfile_prev, gensym("prev"), A_DEFFLOAT, 0);
 
931
 
 
932
  class_addmethod(msgfile_class, (t_method)msgfile_skip, gensym("skip"), A_DEFFLOAT, 0);
 
933
 
 
934
  class_addmethod(msgfile_class, (t_method)msgfile_set, gensym("set"), A_GIMME, 0);
 
935
  
 
936
  class_addmethod(msgfile_class, (t_method)msgfile_clear, gensym("clear"), 0);
 
937
  class_addmethod(msgfile_class, (t_method)msgfile_delete, gensym("delete"), A_GIMME, 0);
 
938
  
 
939
  class_addmethod(msgfile_class, (t_method)msgfile_add, gensym("add"), A_GIMME, 0);
 
940
  class_addmethod(msgfile_class, (t_method)msgfile_add2, gensym("add2"), A_GIMME, 0);
 
941
  class_addmethod(msgfile_class, (t_method)msgfile_append, gensym("append"), A_GIMME, 0);
 
942
  class_addmethod(msgfile_class, (t_method)msgfile_append2, gensym("append2"), A_GIMME, 0);
 
943
  class_addmethod(msgfile_class, (t_method)msgfile_insert, gensym("insert"), A_GIMME, 0);
 
944
  class_addmethod(msgfile_class, (t_method)msgfile_insert2, gensym("insert2"), A_GIMME, 0);
 
945
 
 
946
  class_addmethod(msgfile_class, (t_method)msgfile_replace, gensym("replace"), A_GIMME, 0);
 
947
 
 
948
  class_addmethod(msgfile_class, (t_method)msgfile_find, gensym("find"), A_GIMME, 0);
 
949
 
 
950
  class_addmethod(msgfile_class, (t_method)msgfile_read, gensym("read"), A_SYMBOL, A_DEFSYM, 0);
 
951
  class_addmethod(msgfile_class, (t_method)msgfile_read2, gensym("read2"), A_SYMBOL, A_DEFSYM, 0);
 
952
  class_addmethod(msgfile_class, (t_method)msgfile_write, gensym("write"), A_SYMBOL, A_DEFSYM, 0);
 
953
  class_addmethod(msgfile_class, (t_method)msgfile_print, gensym("print"), 0);
 
954
  class_addmethod(msgfile_class, (t_method)msgfile_flush, gensym("flush"), 0);
 
955
 
 
956
  class_addbang(msgfile_class, msgfile_bang);
 
957
  class_addmethod(msgfile_class, (t_method)msgfile_this, gensym("this"), 0);
 
958
  class_addmethod(msgfile_class, (t_method)msgfile_where, gensym("where"), 0);
 
959
 
 
960
 
 
961
  class_addmethod(msgfile_class, (t_method)msgfile_sort, gensym("sort"), A_SYMBOL, A_SYMBOL, A_SYMBOL, 0);
 
962
 
 
963
  class_addmethod(msgfile_class, (t_method)msgfile_help, gensym("help"), 0);
 
964
 
 
965
  zexy_register("msgfile");
 
966
}