123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633 |
- /*
- * CDE - Common Desktop Environment
- *
- * Copyright (c) 1993-2012, The Open Group. All rights reserved.
- *
- * These libraries and programs are free software; you can
- * redistribute them and/or modify them under the terms of the GNU
- * Lesser General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * These libraries and programs are distributed in the hope that
- * they will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with these libraries and programs; if not, write
- * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- * Floor, Boston, MA 02110-1301 USA
- */
- //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
- //%% (c) Copyright 1993, 1994 International Business Machines Corp.
- //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
- //%% (c) Copyright 1993, 1994 Novell, Inc.
- //%% $XConsortium: CoEdFile.C /main/3 1995/10/20 17:06:45 rswiston $
- /*
- * CoEdFile.cc
- *
- * Copyright (c) 1991 by Sun Microsystems. All Rights Reserved.
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without
- * fee, provided that the above copyright notice appear in all copies
- * and that both that copyright notice and this permission notice
- * appear in supporting documentation, and that the names of Sun
- * Microsystems and its subsidiaries not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. Sun Microsystems and its
- * subsidiaries make no representations about the suitability of this
- * software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * Sun Microsystems and its subsidiaries disclaim all warranties with
- * regard to this software, including all implied warranties of
- * merchantability and fitness. In no event shall Sun Microsystems or
- * its subsidiaries be liable for any special, indirect or
- * consequential damages or any damages whatsoever resulting from loss
- * of use, data or profits, whether in an action of contract,
- * negligence or other tortious action, arising out of or in
- * connection with the use or performance of this software.
- */
- #include <stdio.h>
- #include <string.h>
- #include <sys/param.h>
- #include <stdlib.h>
- #include <poll.h>
- #include <sys/time.h>
- #include <sys/resource.h>
- #include "CoEdFile.h"
- #include "CoEdGlobals.h"
- #include "CoEdChangeHistory.h"
- #include "CoEdChangeQueue.h"
- #include "CoEdTextVersion.h"
- #undef DEBUG
- CoEdFile::
- CoEdFile( const char *path, CoEdTextBuffer *textBuf, CoEdStatus &status,
- int timeOutSec )
- {
- Tt_status err;
- _next = 0;
- _numLocalChanges = 0;
- _joining = 1;
- if (path == 0) {
- fprintf( stderr, "libCoEd: can't join null file\n" );
- status = CoEdErrFile;
- return;
- }
- _appliedChanges = new CoEdChangeHistory;
- if (_appliedChanges == 0) {
- status = CoEdErrNoMem;
- return;
- }
- _textBuf = textBuf;
- if (_textBuf == 0) {
- status = CoEdErrBadPointer;
- return;
- }
- _unAppliedChanges = new CoEdChangeQueue;
- if (_unAppliedChanges == 0) {
- status = CoEdErrNoMem;
- return;
- }
- _version = new CoEdTextVersion;
- if (_version == 0) {
- status = CoEdErrNoMem;
- return;
- }
- _versionInQ = new CoEdTextVersion;
- if (_versionInQ == 0) {
- status = CoEdErrNoMem;
- return;
- }
- _coEditors = new CoEdSiteIDList;
- if (_coEditors == 0) {
- status = CoEdErrNoMem;
- return;
- }
- //
- // Join the file.
- //
- err = tt_file_join( path );
- if (err != TT_OK) {
- fprintf( stderr, "libCoEd: %s: %s\n", path,
- tt_status_message( err ));
- status = (CoEdStatus)err;
- return;
- }
- //
- // Trick ToolTalk into translating the path into the canonical
- // path that it will use to label messages about this file.
- //
- char *oldDefaultFile = tt_default_file();
- err = tt_ptr_error( oldDefaultFile );
- if (err != TT_OK) {
- fprintf( stderr, "libCoEd: tt_default_file(): %s\n",
- tt_status_message( err ));
- status = (CoEdStatus)err;
- return;
- }
- err = tt_default_file_set( path );
- if (err != TT_OK) {
- fprintf( stderr, "libCoEd: tt_default_file_set(\"%s\"): %s\n",
- path, tt_status_message( err ));
- status = (CoEdStatus)err;
- return;
- }
- char *temp = tt_default_file();
- err = tt_ptr_error( temp );
- if (err != TT_OK) {
- fprintf( stderr, "libCoEd: tt_default_file(): %s\n",
- tt_status_message( err ));
- status = (CoEdStatus)err;
- return;
- }
- _path = strdup( temp );
- if (_path == 0) {
- status = CoEdErrNoMem;
- return;
- }
- tt_free( temp );
- if (oldDefaultFile != 0) {
- //
- // Reset the default file to what it was.
- //
- Tt_status err = tt_default_file_set( oldDefaultFile );
- if (err != TT_OK) {
- fprintf( stderr, "libCoEd: tt_default_file_set(\"%s\")"
- ": %s\n", oldDefaultFile,
- tt_status_message( err ));
- status = (CoEdStatus)err;
- return;
- }
- }
- tt_free( oldDefaultFile );
- //
- // Ask to join the file.
- //
- Tt_message msg = tt_prequest_create( TT_FILE, "Text_File_Join" );
- Tt_status ttErr = tt_ptr_error( msg );
- if (ttErr != TT_OK) {
- fprintf( stderr, "libCoEd: tt_prequest_create(): %s\n",
- tt_status_message( ttErr ));
- status = (CoEdStatus)ttErr;
- return;
- }
- //
- // Set the file of the message.
- //
- ttErr = tt_message_file_set( msg, _path );
- if (ttErr != TT_OK) {
- fprintf( stderr, "libCoEd: tt_message_file_set(): %s\n",
- tt_status_message( ttErr ));
- status = (CoEdStatus)ttErr;
- return;
- }
- //
- // Send the message.
- //
- ttErr = tt_message_send( msg );
- if (ttErr != TT_OK) {
- fprintf( stderr, "libCoEd: tt_message_send(): %s\n",
- tt_status_message( ttErr ));
- status = (CoEdStatus)ttErr;
- return;
- }
- //
- // Add ourselves to the list of files joined.
- //
- coEdFiles->append( this );
- //
- // Wait for the reply.
- //
- status = CoEdOK;
- time_t start = time(0);
- struct rlimit nofile;
- getrlimit( RLIMIT_NOFILE, &nofile );
- struct pollfd fds[ 1 ];
- fds[ 0 ].fd = coEdTtFd;
- fds[ 0 ].events = POLLIN;
- while (_joining && (status == CoEdOK)) {
- if ((timeOutSec > 0) && (time(0) - start > timeOutSec)) {
- status = CoEdWarnTimeout;
- break;
- }
- int activeFDs = poll( fds, 1, (1000*timeOutSec) );
- if (activeFDs > 0) {
- if (fds[ 0 ].revents & POLLIN) {
- status = coEdHandleActiveFD( coEdTtFd );
- }
- } else if (activeFDs == 0) {
- status = CoEdWarnTimeout;
- } else {
- perror( "libCoEd" );
- status = CoEdErrFailure;
- }
- }
- }
- CoEdFile::
- ~CoEdFile()
- {
- // XXX unjoin from the file, remove from coEdFiles
- if (_appliedChanges != 0) {
- delete _appliedChanges;
- }
- if (_unAppliedChanges != 0) {
- delete _unAppliedChanges;
- }
- if (_version != 0) {
- delete _version;
- }
- if (_versionInQ != 0) {
- delete _versionInQ;
- }
- if (_path != 0) {
- free( _path );
- }
- }
- CoEdStatus CoEdFile::
- insertText( long start, long end, const char *text )
- {
- CoEdTextChange *change;
- _numLocalChanges++;
- change = new CoEdTextChange( start, end, text, _version, coEdSiteID,
- _numLocalChanges );
- _version ->update( *coEdSiteID, _numLocalChanges );
- _versionInQ->update( *coEdSiteID, _numLocalChanges );
- if (change == 0) {
- return CoEdErrNoMem;
- }
- _appliedChanges->insert( change );
- return change->broadcast( _path );
- }
- CoEdStatus CoEdFile::
- _handleMsg( Tt_message msg )
- {
- Tt_class theClass = tt_message_class( msg );
- Tt_status err = tt_int_error( theClass );
- if (err != TT_OK) {
- fprintf( stderr, "libCoEd: tt_message_class(): %s\n",
- tt_status_message( err ));
- return (CoEdStatus)err;
- }
- switch (theClass) {
- case TT_REQUEST:
- return _handleRequest( msg );
- case TT_NOTICE:
- return _handleNotice( msg );
- default:
- fprintf( stderr, "libCoEd: bad Tt_class!\n" );
- return CoEdOK;
- }
- }
- CoEdStatus CoEdFile::
- _handleRequest( Tt_message msg )
- {
- CoEdStatus val2Return;
- char *op = tt_message_op( msg );
- Tt_status err = tt_ptr_error( op );
- if (err != TT_OK) {
- fprintf( stderr, "libCoEd: tt_message_op(): %s\n",
- tt_status_message( err ));
- val2Return = (CoEdStatus)err;
- }
- if (op == 0) {
- fprintf( stderr, "libCoEd: msg has null op!\n" );
- val2Return = CoEdErrBadMsg;
- }
- if (! strcmp( op, "Text_File_Join" )) {
- val2Return = _handleJoin( msg );
- } else if (! strcmp( op, "Text_File_Version_Vote" )) {
- //val2Return = _handleVersionVote( msg );
- } else {
- fprintf( stderr, "libCoEd: unknown msg op \"%s\"\n", op );
- val2Return = CoEdErrBadMsg;
- }
- return val2Return;
- }
- CoEdStatus CoEdFile::
- _handleJoin( Tt_message msg )
- {
- Tt_status ttErr;
- Tt_state state = tt_message_state( msg );
- ttErr = tt_int_error( state );
- if (ttErr != TT_OK) {
- fprintf( stderr, "libCoEd: tt_message_state(): %s\n",
- tt_status_message( ttErr ));
- return (CoEdStatus)ttErr;
- }
- switch (state) {
- char *sender;
- Tt_status ttErr;
- case TT_FAILED:
- //
- // Nobody handled our request, so we must be the
- // first process to have joined the file.
- //
- _joining = 0;
- return CoEdOK;
- case TT_SENT:
- //
- // If the Text_File_Join request was sent by us, we
- // don't care about it.
- //
- sender = tt_message_sender( msg );
- ttErr = tt_ptr_error( sender );
- if (ttErr != TT_OK) {
- fprintf( stderr, "libCoEd: tt_message_sender(): %s\n",
- tt_status_message( ttErr ));
- return (CoEdStatus)ttErr;
- }
- if (sender == 0) {
- return CoEdErrBadMsg;
- }
- if (! strcmp( sender, coEdProcID )) {
- tt_free( sender );
- //
- // The request was made by us, so we reject it, in
- // order to give someone in the know a chance to
- // handle it.
- //
- ttErr = tt_message_reject( msg );
- if (ttErr != TT_OK) {
- fprintf( stderr,
- "libCoEd: tt_message_reject(): %s\n",
- tt_status_message( ttErr ));
- return (CoEdStatus)ttErr;
- }
- return CoEdOK;
- }
- tt_free( sender );
- // XXX Quiesce the file, and ship 'em a copy.
- tt_message_fail( msg );
- return CoEdOK;
- default:
- fprintf( stderr, "msg state: %d!\n", (int)state );
- tt_message_reject( msg );
- break;
- }
- return CoEdOK;
- } /* CoEdFile::_handleJoin() */
- CoEdStatus CoEdFile::
- _handleNotice( Tt_message msg )
- {
- Tt_state state = tt_message_state( msg );
- Tt_status err = tt_int_error( state );
- if (err != TT_OK) {
- fprintf( stderr, "libCoEd: tt_message_state(): %s\n",
- tt_status_message( err ));
- return (CoEdStatus)err;
- }
- if (state != TT_SENT) {
- return CoEdOK;
- }
- CoEdStatus val2Return;
- char *op = tt_message_op( msg );
- err = tt_ptr_error( op );
- if (err != TT_OK) {
- fprintf( stderr, "libCoEd: tt_message_op(): %s\n",
- tt_status_message( err ));
- val2Return = (CoEdStatus)err;
- }
- if (op == 0) {
- fprintf( stderr, "libCoEd: msg has null op!\n" );
- val2Return = CoEdErrBadMsg;
- }
- if (! strcmp( op, "Text_File_Changed" )) {
- val2Return = _handleChanged( msg );
- } else if (! strcmp( op, "Text_File_Poll_Version" )) {
- val2Return = _handlePollVersion( msg );
- } else {
- fprintf( stderr, "libCoEd: unknown msg op \"%s\"\n", op );
- val2Return = CoEdErrBadMsg;
- }
- tt_message_destroy( msg );
- return val2Return;
- }
- CoEdStatus CoEdFile::
- _handleChanged( Tt_message msg )
- {
- if (_joining) {
- fprintf( stderr, "libCoEd: warning: got a change while "
- "joining \"%s\"\n", _path );
- return CoEdOK;
- }
- //
- // If the Text_File_Changed notice was sent by us, we don't care
- // about it.
- //
- char *sender = tt_message_sender( msg );
- Tt_status ttErr = tt_ptr_error( sender );
- if (ttErr != TT_OK) {
- fprintf( stderr, "libCoEd: tt_message_sender(): %s\n",
- tt_status_message( ttErr ));
- return (CoEdStatus)ttErr;
- }
- if (sender == 0) {
- return CoEdErrBadMsg;
- }
- if (! strcmp( sender, coEdProcID )) {
- tt_free( sender );
- return CoEdOK;
- }
- tt_free( sender );
- //
- // It was not sent by us. Process it.
- //
- CoEdStatus err;
- CoEdTextChange *change = new CoEdTextChange( msg, err );
- if (err != CoEdOK) {
- return CoEdOK;
- }
- return _handleChange( change );
- }
- CoEdStatus CoEdFile::
- _handlePollVersion( Tt_message msg )
- {
- //
- // If the Text_File_Changed notice was sent by us, we don't care
- // about it.
- //
- char *sender = tt_message_sender( msg );
- Tt_status ttErr = tt_ptr_error( sender );
- if (ttErr != TT_OK) {
- fprintf( stderr, "libCoEd: tt_message_sender(): %s\n",
- tt_status_message( ttErr ));
- return (CoEdStatus)ttErr;
- }
- if (sender == 0) {
- return CoEdErrBadMsg;
- }
- if (! strcmp( sender, coEdProcID )) {
- tt_free( sender );
- return CoEdOK;
- }
- tt_free( sender );
- //
- // It was not sent by us. Respond.
- //
- Tt_message response = tt_prequest_create( TT_FILE,
- "Text_File_Version_Vote" );
- ttErr = tt_ptr_error( response );
- if (ttErr != TT_OK) {
- fprintf( stderr, "libCoEd: tt_prequest_create(): %s\n",
- tt_status_message( ttErr ));
- return (CoEdStatus)ttErr;
- }
- //
- // Set the file of the response.
- //
- ttErr = tt_message_file_set( response, _path );
- if (ttErr != TT_OK) {
- fprintf( stderr, "libCoEd: tt_message_file_set(): %s\n",
- tt_status_message( ttErr ));
- return (CoEdStatus)ttErr;
- }
- //
- // Aim the response back at the sender
- //
- ttErr = tt_message_handler_set( response, sender );
- if (ttErr != TT_OK) {
- fprintf( stderr, "libCoEd: tt_message_handler_set(): %s\n",
- tt_status_message( ttErr ));
- return (CoEdStatus)ttErr;
- }
- //
- // Send the message.
- //
- ttErr = tt_message_send( response );
- if (ttErr != TT_OK) {
- fprintf( stderr, "libCoEd: tt_message_send(): %s\n",
- tt_status_message( ttErr ));
- return (CoEdStatus)ttErr;
- }
- //
- // We don't expect or care about a reply, so destroy the
- // message now.
- //
- return CoEdOK;
- }
- CoEdStatus CoEdFile::
- _handleChange( CoEdTextChange *change, int changeIsFromQueue )
- {
- if (change->knowsOfNewerChangesThan( *_version )) {
- if (changeIsFromQueue) {
- fprintf( stderr, "Re-queuing change!\n" );
- abort();
- }
- _unAppliedChanges->insert( change );
- _versionInQ->update( change->causer(), change->changeNum() );
- } else {
- _appliedChanges->insert( change );
- CoEdTextChange *translatedChange =
- _appliedChanges->translate( *change );
- if (translatedChange != 0) {
- CoEdStatus err;
- err = _textBuf->insertText( translatedChange->start(),
- translatedChange->end(),
- translatedChange->text() );
- if (err != CoEdOK) {
- fprintf( stderr, "libCoEd: CoEdTextBuffer::"
- "insertText(): %d! Failed change: ");
- translatedChange->print( stderr );
- }
- delete translatedChange;
- }
- _version->update( change->causer(), change->changeNum() );
- if (! changeIsFromQueue) {
- _versionInQ->update( change->causer(),
- change->changeNum() );
- }
- }
- CoEdTextChange *newlyEligibleChange =
- _unAppliedChanges->deQEligibleChng( *_version );
- if (newlyEligibleChange != 0) {
- return _handleChange( newlyEligibleChange, 1 );
- } else {
- return CoEdOK;
- }
- }
- CoEdFileList::
- CoEdFileList()
- {
- _head = 0;
- _tail = 0;
- _count = 0;
- }
- CoEdFileList::
- ~CoEdFileList()
- {
- CoEdFile *curr = _head;
- CoEdFile *prev;
- while (curr != 0) {
- prev = curr;
- curr = curr->_next;
- delete prev;
- }
- }
- void CoEdFileList::
- push( CoEdFile *file )
- {
- file->_next = _head;
- file->_prev = 0;
- if (_tail == 0) {
- _tail = file;
- } else {
- _head->_prev = file;
- }
- _head = file;
- _count++;
- }
- void CoEdFileList::
- append( CoEdFile *file )
- {
- file->_next = 0;
- file->_prev = _tail;
- if (_head == 0) {
- _head = file;
- } else {
- _tail->_next = file;
- }
- _tail = file;
- _count++;
- }
- CoEdStatus CoEdFileList::
- handleMsg( const char *path, Tt_message msg )
- {
- if (path == 0) {
- fprintf( stderr, "libCoEd: got msg for null file!\n" );
- return CoEdErrFile;
- }
- CoEdFile *curr = _head;
- while (curr != 0) {
- if ((curr->_path != 0) && (! strcmp( path, curr->_path))) {
- return curr->_handleMsg( msg );
- }
- curr = curr->_next;
- }
- fprintf( stderr, "libCoEd: \"%s\" is not a file being CoEdited.\n",
- path );
- return CoEdErrFile;
- }
|