mirror of
https://github.com/cc65/cc65.git
synced 2024-06-10 13:29:50 +00:00
Compare commits
34 Commits
7a3762148f
...
c5da2d8245
Author | SHA1 | Date | |
---|---|---|---|
|
c5da2d8245 | ||
|
2c4d4d3314 | ||
|
86e5acd679 | ||
|
84153e809e | ||
|
90723d7dd1 | ||
|
f789316f86 | ||
|
270f3544b5 | ||
|
c500cb9086 | ||
|
074ec82126 | ||
|
e8e0c41f87 | ||
|
8e17cc2692 | ||
|
7a5526b19e | ||
|
d4c7cba521 | ||
|
9c877fa529 | ||
|
e10647dca6 | ||
|
dfbfe79c71 | ||
|
6e203ab2d2 | ||
|
57e6c2a4f9 | ||
|
98208e7e95 | ||
|
30ff2bdc6b | ||
|
167c31c148 | ||
|
a6f207a2a5 | ||
|
346dd7df85 | ||
|
aa47b6c1c7 | ||
|
085509c2e1 | ||
|
d34a6df002 | ||
|
42a93f00d4 | ||
|
acf9676c0f | ||
|
7798c7a471 | ||
|
fc619573b4 | ||
|
9d50090769 | ||
|
c0285cadc8 | ||
|
6a276ccac3 | ||
|
9d32a84f69 |
4
.github/workflows/build-on-pull-request.yml
vendored
4
.github/workflows/build-on-pull-request.yml
vendored
|
@ -35,7 +35,7 @@ jobs:
|
|||
run: make -j2 lib QUIET=1
|
||||
- name: Run the regression tests.
|
||||
shell: bash
|
||||
run: make test QUIET=1
|
||||
run: make -j2 test QUIET=1
|
||||
- name: Test that the samples can be built.
|
||||
run: make -C samples platforms
|
||||
- name: Test that the targettest programs can be built.
|
||||
|
@ -89,4 +89,4 @@ jobs:
|
|||
|
||||
- name: Run the regression tests (make test)
|
||||
shell: cmd
|
||||
run: make test QUIET=1 SHELL=cmd
|
||||
run: make -j2 test QUIET=1 SHELL=cmd
|
||||
|
|
|
@ -59,7 +59,7 @@ jobs:
|
|||
run: make -j2 lib QUIET=1
|
||||
- name: Run the regression tests.
|
||||
shell: bash
|
||||
run: make test QUIET=1
|
||||
run: make -j2 test QUIET=1
|
||||
- name: Test that the samples can be built.
|
||||
shell: bash
|
||||
run: make -j2 samples
|
||||
|
|
2
.github/workflows/windows-test-scheduled.yml
vendored
2
.github/workflows/windows-test-scheduled.yml
vendored
|
@ -70,7 +70,7 @@ jobs:
|
|||
- name: Run the regression tests (make test)
|
||||
if: steps.check-sha.outputs.cache-hit != 'true'
|
||||
shell: cmd
|
||||
run: make test QUIET=1 SHELL=cmd
|
||||
run: make -j2 test QUIET=1 SHELL=cmd
|
||||
|
||||
- name: Test that the samples can be built (make samples)
|
||||
if: steps.check-sha.outputs.cache-hit != 'true'
|
||||
|
|
|
@ -14,6 +14,7 @@ MEMORY {
|
|||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp, optional = yes;
|
||||
LOADADDR: load = LOADADDR, type = ro;
|
||||
EXEHDR: load = MAIN, type = ro, optional = yes;
|
||||
CODE: load = MAIN, type = ro;
|
||||
RODATA: load = MAIN, type = ro;
|
||||
DATA: load = MAIN, type = rw;
|
||||
|
|
|
@ -14,6 +14,7 @@ MEMORY {
|
|||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp, optional = yes;
|
||||
LOADADDR: load = LOADADDR, type = ro;
|
||||
EXEHDR: load = MAIN, type = ro, optional = yes;
|
||||
CODE: load = MAIN, type = ro;
|
||||
RODATA: load = MAIN, type = ro;
|
||||
DATA: load = MAIN, type = rw;
|
||||
|
|
|
@ -14,6 +14,7 @@ MEMORY {
|
|||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp, optional = yes;
|
||||
LOADADDR: load = LOADADDR, type = ro;
|
||||
EXEHDR: load = MAIN, type = ro, optional = yes;
|
||||
CODE: load = MAIN, type = ro;
|
||||
RODATA: load = MAIN, type = ro;
|
||||
DATA: load = MAIN, type = rw;
|
||||
|
|
|
@ -829,49 +829,42 @@ names like "Loop". Here is an example:
|
|||
bne @Loop ; ERROR: Unknown identifier!
|
||||
</verb></tscreen>
|
||||
|
||||
|
||||
<sect1>Unnamed labels<p>
|
||||
|
||||
If you really want to write messy code, there are also unnamed labels. These
|
||||
labels do not have a name (you guessed that already, didn't you?). A colon is
|
||||
used to mark the absence of the name.
|
||||
If you really want to write messy code, there are also unnamed labels. To define
|
||||
an unnamed label, use either <tt>@:</tt> (<tt>.LOCALCHAR</tt> is respected if it
|
||||
is set) or sole <tt>:</tt>.
|
||||
|
||||
Unnamed labels may be accessed by using the colon plus several minus or plus
|
||||
characters as a label designator. Using the '-' characters will create a back
|
||||
reference (use the n'th label backwards), using '+' will create a forward
|
||||
reference (use the n'th label in forward direction). An example will help to
|
||||
understand this:
|
||||
To reference an unnamed label, use <tt>@</tt> (<tt>.LOCALCHAR</tt> is respected
|
||||
if it is set) or <tt>:</tt> with several <tt>-</tt> or <tt>+</tt> characters.
|
||||
The <tt>-</tt> characters will create a back reference (n'th label backwards),
|
||||
the <tt>+</tt> will create a forward reference (n'th label in forward direction).
|
||||
As an alternative, angle brackets <tt><</tt> and <tt>></tt> may be used
|
||||
instead of <tt>-</tt> and <tt>+</tt> with the same meaning.
|
||||
|
||||
Example:
|
||||
|
||||
<tscreen><verb>
|
||||
: lda (ptr1),y ; #1
|
||||
cmp (ptr2),y
|
||||
bne :+ ; -> #2
|
||||
tax
|
||||
beq :+++ ; -> #4
|
||||
iny
|
||||
bne :- ; -> #1
|
||||
inc ptr1+1
|
||||
inc ptr2+1
|
||||
bne :- ; -> #1
|
||||
|
||||
: bcs :+ ; #2 -> #3
|
||||
ldx #$FF
|
||||
rts
|
||||
|
||||
: ldx #$01 ; #3
|
||||
: rts ; #4
|
||||
cpy #0
|
||||
beq @++
|
||||
@:
|
||||
sta $2007
|
||||
dey
|
||||
bne @-
|
||||
@:
|
||||
rts
|
||||
</verb></tscreen>
|
||||
|
||||
As you can see from the example, unnamed labels will make even short
|
||||
sections of code hard to understand, because you have to count labels
|
||||
to find branch targets (this is the reason why I for my part do
|
||||
prefer the "cheap" local labels). Nevertheless, unnamed labels are
|
||||
convenient in some situations, so it's your decision.
|
||||
Unnamed labels may make even short sections of code hard to understand, because
|
||||
you have to count labels to find branch targets. It's better to prefer the
|
||||
"cheap" local labels. Nevertheless, unnamed labels are convenient in some
|
||||
situations, so it's up to your discretion.
|
||||
|
||||
<em/Note:/ <ref id="scopes" name="Scopes"> organize named symbols, not
|
||||
unnamed ones, so scopes don't have an effect on unnamed labels.
|
||||
|
||||
|
||||
|
||||
<sect1>Using macros to define labels and constants<p>
|
||||
|
||||
While there are drawbacks with this approach, it may be handy in a few rare
|
||||
|
|
|
@ -1681,6 +1681,16 @@ void somefunc2(int, char *);
|
|||
</verb></tscreen>
|
||||
|
||||
|
||||
<sect1><tt>#pragma once</tt><label id="pragma-once"><p>
|
||||
|
||||
This pragma is used to prevent multiple inclusion of a header file.
|
||||
If this pragma is preprocessed in a file, any posterior
|
||||
<tt>#include</tt> which targets the current file will be ignored.
|
||||
|
||||
Two files are considered to be the same by this directive if they
|
||||
share the same absolute path. In the case of symbolic links,
|
||||
the canonical, resolved path is considered instead.
|
||||
|
||||
|
||||
<sect>Register variables<label id="register-vars"><p>
|
||||
|
||||
|
|
|
@ -707,6 +707,24 @@ static void OneLine (void)
|
|||
NextTok ();
|
||||
}
|
||||
|
||||
/* Handle @-style unnamed labels */
|
||||
if (CurTok.Tok == TOK_ULABEL) {
|
||||
if (CurTok.IVal != 0) {
|
||||
Error ("Invalid unnamed label definition");
|
||||
}
|
||||
ULabDef ();
|
||||
NextTok ();
|
||||
|
||||
/* Skip the colon. If NoColonLabels is enabled, allow labels without
|
||||
** a colon if there is no whitespace before the identifier.
|
||||
*/
|
||||
if (CurTok.Tok == TOK_COLON) {
|
||||
NextTok ();
|
||||
} else if (CurTok.WS || !NoColonLabels) {
|
||||
Error ("':' expected");
|
||||
}
|
||||
}
|
||||
|
||||
/* If the first token on the line is an identifier, check for a macro or
|
||||
** an instruction.
|
||||
*/
|
||||
|
|
|
@ -1124,17 +1124,33 @@ Again:
|
|||
/* Local symbol? */
|
||||
if (C == LocalStart) {
|
||||
|
||||
/* Read the identifier. */
|
||||
ReadIdent ();
|
||||
NextChar ();
|
||||
|
||||
/* Start character alone is not enough */
|
||||
if (SB_GetLen (&CurTok.SVal) == 1) {
|
||||
Error ("Invalid cheap local symbol");
|
||||
goto Again;
|
||||
if (IsIdChar (C)) {
|
||||
/* Read a local identifier */
|
||||
CurTok.Tok = TOK_LOCAL_IDENT;
|
||||
SB_AppendChar (&CurTok.SVal, LocalStart);
|
||||
ReadIdent ();
|
||||
} else {
|
||||
/* Read an unnamed label */
|
||||
CurTok.IVal = 0;
|
||||
CurTok.Tok = TOK_ULABEL;
|
||||
|
||||
if (C == '-' || C == '<') {
|
||||
int PrevC = C;
|
||||
do {
|
||||
--CurTok.IVal;
|
||||
NextChar ();
|
||||
} while (C == PrevC);
|
||||
} else if (C == '+' || C == '>') {
|
||||
int PrevC = C;
|
||||
do {
|
||||
++CurTok.IVal;
|
||||
NextChar ();
|
||||
} while (C == PrevC);
|
||||
}
|
||||
}
|
||||
|
||||
/* A local identifier */
|
||||
CurTok.Tok = TOK_LOCAL_IDENT;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1314,22 +1330,30 @@ CharAgain:
|
|||
break;
|
||||
|
||||
case '-':
|
||||
case '<':
|
||||
{
|
||||
int PrevC = C;
|
||||
CurTok.IVal = 0;
|
||||
do {
|
||||
--CurTok.IVal;
|
||||
NextChar ();
|
||||
} while (C == '-');
|
||||
} while (C == PrevC);
|
||||
CurTok.Tok = TOK_ULABEL;
|
||||
break;
|
||||
}
|
||||
|
||||
case '+':
|
||||
case '>':
|
||||
{
|
||||
int PrevC = C;
|
||||
CurTok.IVal = 0;
|
||||
do {
|
||||
++CurTok.IVal;
|
||||
NextChar ();
|
||||
} while (C == '+');
|
||||
} while (C == PrevC);
|
||||
CurTok.Tok = TOK_ULABEL;
|
||||
break;
|
||||
}
|
||||
|
||||
case '=':
|
||||
NextChar ();
|
||||
|
|
|
@ -71,7 +71,7 @@ typedef enum token_t {
|
|||
TOK_REG, /* Sweet16 R.. register (in sweet16 mode) */
|
||||
|
||||
TOK_ASSIGN, /* := */
|
||||
TOK_ULABEL, /* :++ or :-- */
|
||||
TOK_ULABEL, /* An unnamed label */
|
||||
|
||||
TOK_EQ, /* = */
|
||||
TOK_NE, /* <> */
|
||||
|
|
|
@ -107,8 +107,12 @@ ExprNode* ULabRef (int Which)
|
|||
int Index;
|
||||
ULabel* L;
|
||||
|
||||
/* Which can never be 0 */
|
||||
PRECONDITION (Which != 0);
|
||||
/* Which should not be 0 */
|
||||
if (Which == 0) {
|
||||
Error ("Invalid unnamed label reference");
|
||||
/* We must return something valid */
|
||||
return GenCurrentPC();
|
||||
}
|
||||
|
||||
/* Get the index of the referenced label */
|
||||
if (Which > 0) {
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "print.h"
|
||||
#include "strbuf.h"
|
||||
#include "xmalloc.h"
|
||||
#include "pathutil.h"
|
||||
|
||||
/* cc65 */
|
||||
#include "codegen.h"
|
||||
|
@ -296,10 +297,11 @@ void OpenMainFile (const char* Name)
|
|||
|
||||
|
||||
|
||||
void OpenIncludeFile (const char* Name, InputType IT)
|
||||
void OpenIncludeFile (const char* Name, InputType IT, StringPool *FilesToIgnore)
|
||||
/* Open an include file and insert it into the tables. */
|
||||
{
|
||||
char* N;
|
||||
char* M;
|
||||
FILE* F;
|
||||
IFile* IF;
|
||||
AFile* AF;
|
||||
|
@ -317,6 +319,23 @@ void OpenIncludeFile (const char* Name, InputType IT)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Resolve real path of file in case of a symlink */
|
||||
M = FindRealPath(N);
|
||||
if (M == 0) {
|
||||
PPError ("Cannot resolve absolute path of '%s'", N);
|
||||
xfree (N);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SP_LookupStr(FilesToIgnore, M) != 0) {
|
||||
/* This file should not be included. */
|
||||
xfree (M);
|
||||
xfree (N);
|
||||
return;
|
||||
}
|
||||
|
||||
xfree (M);
|
||||
|
||||
/* Search the list of all input files for this file. If we don't find
|
||||
** it, create a new IFile object.
|
||||
*/
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
/* common */
|
||||
#include "coll.h"
|
||||
#include "strbuf.h"
|
||||
#include "strpool.h"
|
||||
|
||||
|
||||
|
||||
|
@ -83,8 +84,10 @@ extern char NextC;
|
|||
void OpenMainFile (const char* Name);
|
||||
/* Open the main file. Will call Fatal() in case of failures. */
|
||||
|
||||
void OpenIncludeFile (const char* Name, InputType IT);
|
||||
/* Open an include file and insert it into the tables. */
|
||||
void OpenIncludeFile (const char* Name, InputType IT, StringPool* FilesToIgnore);
|
||||
/* Open an include file and insert it into the tables.
|
||||
** Does nothing if the resolved file is present in the pool.
|
||||
*/
|
||||
|
||||
void CloseIncludeFile (void);
|
||||
/* Close an include file and switch to the higher level file. Set Input to
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
#include "inline.h"
|
||||
#include "print.h"
|
||||
#include "xmalloc.h"
|
||||
#include "strpool.h"
|
||||
#include "abend.h"
|
||||
#include "pathutil.h"
|
||||
|
||||
/* cc65 */
|
||||
#include "codegen.h"
|
||||
|
@ -113,6 +116,8 @@ static StrBuf* PLine; /* Buffer for macro expansion */
|
|||
static StrBuf* MLine; /* Buffer for macro expansion in #pragma */
|
||||
static StrBuf* OLine; /* Buffer for #pragma output */
|
||||
|
||||
static StringPool* PragmaOnceSeenFiles;
|
||||
|
||||
/* Newlines to be added to preprocessed text */
|
||||
static unsigned PendingNewLines;
|
||||
static unsigned ContinuedLines;
|
||||
|
@ -2804,7 +2809,6 @@ static int DoIfDef (int skip, int flag)
|
|||
}
|
||||
|
||||
|
||||
|
||||
static void DoInclude (void)
|
||||
/* Open an include file. */
|
||||
{
|
||||
|
@ -2854,8 +2858,8 @@ static void DoInclude (void)
|
|||
NextChar ();
|
||||
/* Check for extra tokens following the filename */
|
||||
CheckExtraTokens ("include");
|
||||
/* Open the include file */
|
||||
OpenIncludeFile (SB_GetConstBuf (&Filename), IT);
|
||||
/* Open the include file, if it is not marked with #pragma once */
|
||||
OpenIncludeFile (SB_GetConstBuf (&Filename), IT, PragmaOnceSeenFiles);
|
||||
} else {
|
||||
/* No terminator found */
|
||||
PPError ("#include expects \"FILENAME\" or <FILENAME>");
|
||||
|
@ -2963,14 +2967,28 @@ static void DoLine (void)
|
|||
MLine = InitLine (MLine);
|
||||
}
|
||||
|
||||
static void DoPragmaOnce (void)
|
||||
/* Marks the current file as seen by #pragma once. */
|
||||
{
|
||||
const char * const Filename = GetCurrentFilename ();
|
||||
|
||||
char * const FullPath = FindRealPath (Filename);
|
||||
|
||||
if (FullPath == NULL) {
|
||||
AbEnd ("Failed to find the real path for the file %s", Filename);
|
||||
}
|
||||
|
||||
SP_AddStr (PragmaOnceSeenFiles, FullPath);
|
||||
|
||||
free (FullPath);
|
||||
}
|
||||
|
||||
static void DoPragma (void)
|
||||
/* Handle a #pragma line by converting the #pragma preprocessor directive into
|
||||
** the _Pragma() compiler operator.
|
||||
*/
|
||||
{
|
||||
StrBuf* PragmaLine = OLine;
|
||||
StrBuf* const PragmaLine = OLine;
|
||||
|
||||
PRECONDITION (PragmaLine != 0);
|
||||
|
||||
|
@ -2981,11 +2999,16 @@ static void DoPragma (void)
|
|||
SB_Clear (MLine);
|
||||
PreprocessDirective (Line, MLine, MSM_NONE);
|
||||
|
||||
/* Convert #pragma to _Pragma () */
|
||||
SB_AppendStr (PragmaLine, "_Pragma (");
|
||||
SB_Reset (MLine);
|
||||
Stringize (MLine, PragmaLine);
|
||||
SB_AppendChar (PragmaLine, ')');
|
||||
if (SB_CompareStr(MLine, "once") == 0) {
|
||||
DoPragmaOnce ();
|
||||
}
|
||||
else {
|
||||
/* Convert #pragma to _Pragma () */
|
||||
SB_AppendStr (PragmaLine, "_Pragma (");
|
||||
SB_Reset (MLine);
|
||||
Stringize (MLine, PragmaLine);
|
||||
SB_AppendChar (PragmaLine, ')');
|
||||
}
|
||||
|
||||
/* End this line */
|
||||
SB_SetIndex (PragmaLine, SB_GetLen (PragmaLine));
|
||||
|
@ -3157,6 +3180,7 @@ static int ParseDirectives (unsigned ModeFlags)
|
|||
if (!PPSkip) {
|
||||
if ((ModeFlags & MSM_IN_ARG_LIST) == 0) {
|
||||
DoPragma ();
|
||||
|
||||
return Whitespace;
|
||||
} else {
|
||||
PPError ("Embedded #pragma directive within macro arguments is unsupported");
|
||||
|
@ -3348,6 +3372,9 @@ void InitPreprocess (void)
|
|||
/* Create the output buffers */
|
||||
MLine = NewStrBuf ();
|
||||
PLine = NewStrBuf ();
|
||||
|
||||
/* 64 is a sensible number of slots for the hash table */
|
||||
PragmaOnceSeenFiles = NewStringPool(64);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3358,6 +3385,7 @@ void DonePreprocess (void)
|
|||
/* Done with the output buffers */
|
||||
SB_Done (MLine);
|
||||
SB_Done (PLine);
|
||||
FreeStringPool(PragmaOnceSeenFiles);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
|
@ -110,6 +110,7 @@
|
|||
<ClInclude Include="common\objdefs.h" />
|
||||
<ClInclude Include="common\optdefs.h" />
|
||||
<ClInclude Include="common\print.h" />
|
||||
<ClInclude Include="common\pathutil.h" />
|
||||
<ClInclude Include="common\scopedefs.h" />
|
||||
<ClInclude Include="common\searchpath.h" />
|
||||
<ClInclude Include="common\segdefs.h" />
|
||||
|
@ -155,6 +156,7 @@
|
|||
<ClCompile Include="common\matchpat.c" />
|
||||
<ClCompile Include="common\mmodel.c" />
|
||||
<ClCompile Include="common\print.c" />
|
||||
<ClCompile Include="common\pathutil.c" />
|
||||
<ClCompile Include="common\searchpath.c" />
|
||||
<ClCompile Include="common\segnames.c" />
|
||||
<ClCompile Include="common\shift.c" />
|
||||
|
@ -171,4 +173,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
119
src/common/pathutil.c
Normal file
119
src/common/pathutil.c
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* pathutil.c */
|
||||
/* Path manipulation utilities */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2003-2008 Ullrich von Bassewitz */
|
||||
/* Roemerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
/* */
|
||||
/* */
|
||||
/* This software is provided 'as-is', without any expressed or implied */
|
||||
/* warranty. In no event will the authors be held liable for any damages */
|
||||
/* arising from the use of this software. */
|
||||
/* */
|
||||
/* Permission is granted to anyone to use this software for any purpose, */
|
||||
/* including commercial applications, and to alter it and redistribute it */
|
||||
/* freely, subject to the following restrictions: */
|
||||
/* */
|
||||
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||
/* claim that you wrote the original software. If you use this software */
|
||||
/* in a product, an acknowledgment in the product documentation would be */
|
||||
/* appreciated but is not required. */
|
||||
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||
/* be misrepresented as being the original software. */
|
||||
/* 3. This notice may not be removed or altered from any source */
|
||||
/* distribution. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#if !defined(_WIN32_WINNT) && !defined(NTDDI_VERSION)
|
||||
|
||||
/* Set minimum windows version for GetFinalPathNameByHandleA */
|
||||
/* NTDDI_VISTA */
|
||||
#define NTDDI_VERSION 0x06000000
|
||||
|
||||
/* _WIN32_WINNT_VISTA */
|
||||
#define _WIN32_WINNT 0x600
|
||||
|
||||
#endif
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include <windows.h>
|
||||
#include <fileapi.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
char *FindRealPath (const char *Path)
|
||||
/*
|
||||
** Returns a malloced buffer containing the canonical path of the given path.
|
||||
** If the path points to a non-existent file, or if any error occurs, NULL is returned.
|
||||
** If the path points to a symlink, the resolved symlink path is returned.
|
||||
** Note: The returned path's separator is system specific.
|
||||
*/
|
||||
{
|
||||
|
||||
HANDLE Handle = CreateFileA (Path,
|
||||
FILE_READ_ATTRIBUTES,
|
||||
FILE_SHARE_READ |
|
||||
FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL);
|
||||
|
||||
if (Handle == INVALID_HANDLE_VALUE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t BufferSize = MAX_PATH + 10;
|
||||
char* Buffer = xmalloc (BufferSize);
|
||||
|
||||
DWORD Status = GetFinalPathNameByHandleA (Handle,
|
||||
Buffer,
|
||||
BufferSize,
|
||||
FILE_NAME_NORMALIZED
|
||||
| VOLUME_NAME_DOS);
|
||||
|
||||
if (Status == 0) {
|
||||
xfree (Buffer);
|
||||
CloseHandle (Handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CloseHandle (Handle);
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
char* FindRealPath (const char* path)
|
||||
/*
|
||||
** Returns a malloced buffer containing the canonical path of the given path.
|
||||
** If the path points to a non-existent file, or if any error occurs, NULL is returned.
|
||||
** If the path points to a symlink, the resolved symlink path is returned.
|
||||
** Note: The returned path's separator is system specific.
|
||||
*/
|
||||
{
|
||||
return realpath (path, NULL);
|
||||
}
|
||||
|
||||
#endif
|
55
src/common/pathutil.h
Normal file
55
src/common/pathutil.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* pathutil.h */
|
||||
/* Path manipulation utilities */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2003-2008 Ullrich von Bassewitz */
|
||||
/* Roemerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
/* */
|
||||
/* */
|
||||
/* This software is provided 'as-is', without any expressed or implied */
|
||||
/* warranty. In no event will the authors be held liable for any damages */
|
||||
/* arising from the use of this software. */
|
||||
/* */
|
||||
/* Permission is granted to anyone to use this software for any purpose, */
|
||||
/* including commercial applications, and to alter it and redistribute it */
|
||||
/* freely, subject to the following restrictions: */
|
||||
/* */
|
||||
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||
/* claim that you wrote the original software. If you use this software */
|
||||
/* in a product, an acknowledgment in the product documentation would be */
|
||||
/* appreciated but is not required. */
|
||||
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||
/* be misrepresented as being the original software. */
|
||||
/* 3. This notice may not be removed or altered from any source */
|
||||
/* distribution. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef PATHUTIL_H
|
||||
#define PATHUTIL_H
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
char *FindRealPath (const char *path);
|
||||
/*
|
||||
** Returns a malloced buffer containing the canonical path of the given path.
|
||||
** If the path points to a non-existent file, or if any error occurs, NULL is returned.
|
||||
** If the path points to a symlink, the resolved symlink path is returned.
|
||||
** Note: The returned path's separator is system specific.
|
||||
*/
|
||||
|
||||
|
||||
/* End of pathutil.h */
|
||||
|
||||
#endif
|
|
@ -377,6 +377,7 @@ char* SearchFile (const SearchPaths* P, const char* File)
|
|||
SB_AppendStr (&PathName, File);
|
||||
SB_Terminate (&PathName);
|
||||
|
||||
|
||||
/* Check if this file exists */
|
||||
if (access (SB_GetBuf (&PathName), 0) == 0) {
|
||||
/* The file exists, we're done */
|
||||
|
|
|
@ -281,3 +281,22 @@ unsigned SP_GetCount (const StringPool* P)
|
|||
{
|
||||
return CollCount (&P->Entries);
|
||||
}
|
||||
|
||||
unsigned SP_Lookup(StringPool *P, const StrBuf *S)
|
||||
/*
|
||||
** Determine whether the given string is in the pool.
|
||||
** Returns 1 if the string is in the pool, 0 otherwise.
|
||||
*/
|
||||
{
|
||||
return HT_Find (&P->Tab, S) != 0;
|
||||
}
|
||||
|
||||
unsigned SP_LookupStr(StringPool *P, const char *S)
|
||||
/*
|
||||
** Determine whether the given string is in the pool.
|
||||
** Returns 1 if the string is in the pool, 0 otherwise.
|
||||
*/
|
||||
{
|
||||
StrBuf Buf;
|
||||
return SP_Lookup (P, SB_InitFromString (&Buf, S));
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ const StrBuf* SP_Get (const StringPool* P, unsigned Index);
|
|||
|
||||
unsigned SP_Add (StringPool* P, const StrBuf* S);
|
||||
/* Add a string buffer to the buffer and return the index. If the string does
|
||||
** already exist in the pool, SP_AddBuf will just return the index of the
|
||||
** already exist in the pool, SP_Add will just return the index of the
|
||||
** existing string.
|
||||
*/
|
||||
|
||||
|
@ -96,6 +96,18 @@ unsigned SP_AddStr (StringPool* P, const char* S);
|
|||
unsigned SP_GetCount (const StringPool* P);
|
||||
/* Return the number of strings in the pool */
|
||||
|
||||
unsigned SP_Lookup(StringPool *P, const StrBuf *S);
|
||||
/*
|
||||
** Determine whether the given string is in the pool.
|
||||
** Returns 1 if the string is in the pool, 0 otherwise.
|
||||
*/
|
||||
|
||||
unsigned SP_LookupStr(StringPool *P, const char *S);
|
||||
/*
|
||||
** Determine whether the given string is in the pool.
|
||||
** Returns 1 if the string is in the pool, 0 otherwise.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* End of strpool.h */
|
||||
|
|
|
@ -14,7 +14,9 @@ WORKDIR = ../testwrk
|
|||
|
||||
.PHONY: test continue mostlyclean clean
|
||||
|
||||
test: mostlyclean continue
|
||||
test:
|
||||
@$(MAKE) mostlyclean
|
||||
@$(MAKE) continue
|
||||
|
||||
continue:
|
||||
@$(MAKE) -C asm all
|
||||
|
|
25
test/asm/listing/060-ulabel.s
Normal file
25
test/asm/listing/060-ulabel.s
Normal file
|
@ -0,0 +1,25 @@
|
|||
; Test new-style (@:) and legacy-style (:) unnamed labels.
|
||||
; Make sure that they have identical behavior.
|
||||
|
||||
.ORG $0000
|
||||
|
||||
@: nop
|
||||
: nop
|
||||
.ASSERT @<< = $0000, error
|
||||
.ASSERT @-- = $0000, error
|
||||
.ASSERT :<< = $0000, error
|
||||
.ASSERT :-- = $0000, error
|
||||
.ASSERT @< = $0001, error
|
||||
.ASSERT @- = $0001, error
|
||||
.ASSERT :< = $0001, error
|
||||
.ASSERT :- = $0001, error
|
||||
.ASSERT @> = $0002, error
|
||||
.ASSERT @+ = $0002, error
|
||||
.ASSERT :> = $0002, error
|
||||
.ASSERT :+ = $0002, error
|
||||
.ASSERT @>> = $0003, error
|
||||
.ASSERT @++ = $0003, error
|
||||
.ASSERT :>> = $0003, error
|
||||
.ASSERT :++ = $0003, error
|
||||
@: nop
|
||||
: nop
|
8
test/val/pragma-once-sample-2.h
Normal file
8
test/val/pragma-once-sample-2.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
** !!DESCRIPTION!! Simple #pragma once directive tests
|
||||
** !!ORIGIN!! cc65 regression tests
|
||||
** !!LICENCE!! Public Domain
|
||||
*/
|
||||
|
||||
#include "pragma-once-sample.h";
|
||||
|
21
test/val/pragma-once-sample.h
Normal file
21
test/val/pragma-once-sample.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
** !!DESCRIPTION!! Simple #pragma once directive tests
|
||||
** !!ORIGIN!! cc65 regression tests
|
||||
** !!LICENCE!! Public Domain
|
||||
*/
|
||||
|
||||
#ifdef FILE_INCLUDED
|
||||
|
||||
#error "This file should not have been included twice"
|
||||
#define INCLUDED_TWICE
|
||||
|
||||
#else
|
||||
|
||||
#define FILE_INCLUDED
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* a pragma once directive should work regardless of where it is located in
|
||||
the file, as long as it is seen by the preprocessor */
|
||||
#pragma once
|
27
test/val/pragma-once-test.c
Normal file
27
test/val/pragma-once-test.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
** !!DESCRIPTION!! Simple #pragma once directive tests
|
||||
** !!ORIGIN!! cc65 regression tests
|
||||
** !!LICENCE!! Public Domain
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pragma-once-sample-2.h"
|
||||
#include "pragma-once-sample-2.h"
|
||||
#include "pragma-once-sample.h"
|
||||
#include "pragma-once-sample.h"
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
#ifdef INCLUDED_TWICE
|
||||
printf("pragma-once-sample.h included more than once\n");
|
||||
return 1;
|
||||
#else
|
||||
printf("pragma-once-sample included once\n");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
Loading…
Reference in New Issue
Block a user